Skip to content

Commit acb1ffd

Browse files
authored
Merge pull request #6719 from dotty-staging/wildcard-sub
Rely on variance to typecheck more uses of wildcards
2 parents aef831a + bfa19a2 commit acb1ffd

File tree

6 files changed

+35
-16
lines changed

6 files changed

+35
-16
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,7 +1181,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
11811181
* If the original left-hand type `leftRoot` is a path `p.type`,
11821182
* and the current widened left type is an application with wildcard arguments
11831183
* such as `C[_]`, where `X` is `C`'s type parameter corresponding to the `_` argument,
1184-
* compare with `C[p.X]` instead. Otherwise return `false`.
1184+
* compare with `C[p.X]` instead. Otherwise approximate based on variance.
11851185
* Also do a capture conversion in either of the following cases:
11861186
*
11871187
* - If we are after typer. We generally relax soundness requirements then.
@@ -1203,10 +1203,18 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
12031203
* paths is less intrusive than skolemization.
12041204
*/
12051205
def compareCaptured(arg1: TypeBounds, arg2: Type) = tparam match {
1206-
case tparam: Symbol
1207-
if leftRoot.isStable || (ctx.isAfterTyper || ctx.mode.is(Mode.TypevarsMissContext)) && leftRoot.member(tparam.name).exists =>
1208-
val captured = TypeRef(leftRoot, tparam)
1209-
isSubArg(captured, arg2)
1206+
case tparam: Symbol =>
1207+
if (leftRoot.isStable || (ctx.isAfterTyper || ctx.mode.is(Mode.TypevarsMissContext))
1208+
&& leftRoot.member(tparam.name).exists) {
1209+
val captured = TypeRef(leftRoot, tparam)
1210+
isSubArg(captured, arg2)
1211+
}
1212+
else if (v > 0)
1213+
isSubType(paramBounds(tparam).hi, arg2)
1214+
else if (v < 0)
1215+
isSubType(arg2, paramBounds(tparam).lo)
1216+
else
1217+
false
12101218
case _ =>
12111219
false
12121220
}

compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ class ExpandSAMs extends MiniPhase {
107107
anon.rhs match {
108108
case PartialFunctionRHS(pf) =>
109109
val anonSym = anon.symbol
110-
111-
val parents = List(defn.AbstractPartialFunctionType.appliedTo(tpe.argInfos), defn.SerializableType)
110+
val anonTpe = anon.tpe.widen
111+
val parents = List(defn.AbstractPartialFunctionType.appliedTo(anonTpe.firstParamTypes.head, anonTpe.resultType), defn.SerializableType)
112112
val pfSym = ctx.newNormalizedClassSymbol(anonSym.owner, tpnme.ANON_CLASS, Synthetic | Final, parents, coord = tree.span)
113113

114114
def overrideSym(sym: Symbol) = sym.copy(

tests/neg/t5729.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object C {
2+
def join(in: Seq[List[_]]): Int = 1
3+
def join[S](in: Seq[List[S]]): String = "x"
4+
5+
val x= join(Seq[List[Int]]()) // error: ambiguous overload
6+
assert(x == "x")
7+
}

tests/pos/capture-variance.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class Hi
2+
class Lo extends Hi
3+
class Cov1[+T]
4+
class Cov2[+T >: Lo <: Hi]
5+
class Contra1[-T]
6+
class Contra2[-T >: Lo <: Hi]
7+
8+
object Test {
9+
val a: List[Cov1[Any]] = ??? : List[Cov1[_]]
10+
val b: List[Cov2[Hi]] = ??? : List[Cov2[_]]
11+
val c: List[Contra1[Nothing]] = ??? : List[Contra1[_]]
12+
val d: List[Contra2[Lo]] = ??? : List[Contra2[_]]
13+
}

tests/run/t5729.scala

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,4 @@ object Test extends App {
44
def join[S](in: Seq[T[S]]): String = "x"
55
val x = join(null: Seq[T[_]])
66
assert(x == 1) // first alt chosen, since second requires a capture conversion in adapt
7-
C
8-
}
9-
10-
object C {
11-
def join(in: Seq[List[_]]): Int = 1
12-
def join[S](in: Seq[List[S]]): String = "x"
13-
14-
val x= join(Seq[List[Int]]()) // second alt chosen, since it is more specific
15-
assert(x == "x")
167
}

0 commit comments

Comments
 (0)