@@ -446,8 +446,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
446
446
case tp2 : HKTypeLambda =>
447
447
def compareTypeLambda : Boolean = tp1.stripTypeVar match {
448
448
case tp1 : HKTypeLambda =>
449
- /* Don't compare bounds or variances of lambdas under language:Scala2.
450
- * (1) If we compare bounds, t2994 will fail.
449
+ /* Don't compare bounds of lambdas under language:Scala2, or t2994 will fail.
451
450
* The issue is that, logically, bounds should compare contravariantly,
452
451
* but that would invalidate a pattern exploited in t2994:
453
452
*
@@ -459,32 +458,17 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
459
458
*
460
459
* Note: it would be nice if this could trigger a migration warning, but I
461
460
* am not sure how, since the code is buried so deep in subtyping logic.
462
- *
463
- * (2) If we compare variances, compilation of scala.collection.mutable.Set wil fail.
464
- * The issue is the following:
465
- *
466
- * Error overriding method companion in trait Iterable of type
467
- * => scala.collection.generic.GenericCompanion[[+A] => scala.collection.Iterable[A]];
468
- * method companion of type
469
- * => scala.collection.generic.GenericCompanion[[A] => scala.collection.mutable.Set[A]]
470
- * has incompatible type.
471
- *
472
- * Indeed, a non-variant Set is not a legal substitute for a covariant Iterable.
473
- * Every instantiated Set is an Iterable, but the type constructor Iterable can be
474
- * passed to a covariant type constructor CC[+X] whereas a non-variant Set cannot.
475
461
*/
476
462
def boundsOK =
477
463
ctx.scala2Mode ||
478
464
tp1.typeParams.corresponds(tp2.typeParams)((tparam1, tparam2) =>
479
465
isSubType(tparam2.paramInfo.subst(tp2, tp1), tparam1.paramInfo))
480
- def variancesOK =
481
- ctx.scala2Mode ||
482
- variancesConform(tp1.typeParams, tp2.typeParams)
483
466
val saved = comparedTypeLambdas
484
467
comparedTypeLambdas += tp1
485
468
comparedTypeLambdas += tp2
486
469
try
487
- variancesOK && boundsOK &&
470
+ variancesConform(tp1.typeParams, tp2.typeParams) &&
471
+ boundsOK &&
488
472
isSubType(tp1.resType, tp2.resType.subst(tp2, tp1))
489
473
finally comparedTypeLambdas = saved
490
474
case _ =>
@@ -1014,7 +998,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
1014
998
}
1015
999
}
1016
1000
1017
- isSubArg(args1.head, args2.head)
1001
+ val arg1 = args1.head
1002
+ val arg2 = args2.head
1003
+ isSubArg(arg1, arg2) || {
1004
+ // last effort: try to adapt variances of higher-kinded types if this is sound.
1005
+ // TODO: Move this to eta-expansion?
1006
+ val adapted2 = arg2.adaptHkVariances(tparam.paramInfo)
1007
+ adapted2.ne(arg2) && isSubArg(arg1, adapted2)
1008
+ }
1018
1009
} && isSubArgs(args1.tail, args2.tail, tp1, tparams.tail)
1019
1010
1020
1011
/** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where
@@ -1186,6 +1177,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
1186
1177
def hasSubRefinement (tp1 : RefinedType , refine2 : Type ): Boolean = {
1187
1178
isSubType(tp1.refinedInfo, refine2) || {
1188
1179
// last effort: try to adapt variances of higher-kinded types if this is sound.
1180
+ // TODO: Move this to eta-expansion?
1189
1181
val adapted2 = refine2.adaptHkVariances(tp1.parent.member(tp1.refinedName).symbol.info)
1190
1182
adapted2.ne(refine2) && hasSubRefinement(tp1, adapted2)
1191
1183
}
0 commit comments