Skip to content

Commit f77c419

Browse files
committed
Rely on variance to typecheck more uses of wildcards
If we can't capture the wildcard argument, we might still be able to return true to the subtype check by approximating the wildcard based on variance.
1 parent dc62333 commit f77c419

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
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
}

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+
}

0 commit comments

Comments
 (0)