Skip to content

Commit 1ca0fb7

Browse files
committed
Fix isSubType bug related to testLifted
testLifted widened a type to an some base type constructor when comparing with a type lambda. This can return false positives if the widened type is on the right of the comparison. The fix adds a parameter to testLifted indicating whether widening is permitted.
1 parent 8e4bf31 commit 1ca0fb7

File tree

2 files changed

+9
-7
lines changed

2 files changed

+9
-7
lines changed

src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,8 @@ class TypeApplications(val self: Type) extends AnyVal {
515515
self.appliedTo(tparams map (_.typeRef)).LambdaAbstract(tparams)
516516
}
517517

518-
/** Test whether this type has a base type `B[T1, ..., Tn]` where the type parameters
518+
/** Test whether this type if od the form `B[T1, ..., Tn]`, or,
519+
* if `canWiden` if true, has a base type of the form `B[T1, ..., Bn]` where the type parameters
519520
* of `B` match one-by-one the variances of `tparams`, and where the lambda
520521
* abstracted type
521522
*
@@ -525,7 +526,7 @@ class TypeApplications(val self: Type) extends AnyVal {
525526
* satisfies predicate `p`. Try base types in the order of their occurrence in `baseClasses`.
526527
* A type parameter matches a variance V if it has V as its variance or if V == 0.
527528
*/
528-
def testLifted(tparams: List[Symbol], p: Type => Boolean)(implicit ctx: Context): Boolean = {
529+
def testLifted(tparams: List[Symbol], p: Type => Boolean, canWiden: Boolean)(implicit ctx: Context): Boolean = {
529530
def tryLift(bcs: List[ClassSymbol]): Boolean = bcs match {
530531
case bc :: bcs1 =>
531532
val tp = self.baseTypeWithArgs(bc)
@@ -548,7 +549,7 @@ class TypeApplications(val self: Type) extends AnyVal {
548549
false
549550
}
550551
if (tparams.isEmpty) false
551-
else if (typeParams.nonEmpty) p(EtaExpand) || tryLift(self.baseClasses)
552-
else tryLift(self.baseClasses)
552+
else if (typeParams.nonEmpty) p(EtaExpand) || canWiden && tryLift(self.baseClasses)
553+
else canWiden && tryLift(self.baseClasses)
553554
}
554555
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
345345
|| fourthTry(tp1, tp2)
346346
)
347347
normalPath ||
348-
needsEtaLift(tp1, tp2) && tp1.testLifted(tp2.typeParams, isSubType(_, tp2))
348+
needsEtaLift(tp1, tp2) && tp1.testLifted(tp2.typeParams, isSubType(_, tp2), canWiden = true)
349349
}
350350
else // fast path, in particular for refinements resulting from parameterization.
351351
isSubType(tp1, skipped2) &&
@@ -453,7 +453,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
453453
isNewSubType(tp1.underlying.widenExpr, tp2) || comparePaths
454454
case tp1: RefinedType =>
455455
isNewSubType(tp1.parent, tp2) ||
456-
needsEtaLift(tp2, tp1) && tp2.testLifted(tp1.typeParams, isSubType(tp1, _))
456+
needsEtaLift(tp2, tp1) && tp2.testLifted(tp1.typeParams, isSubType(tp1, _), canWiden = false)
457457
case AndType(tp11, tp12) =>
458458
eitherIsSubType(tp11, tp2, tp12, tp2)
459459
case JavaArrayType(elem1) =>
@@ -475,7 +475,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
475475
val lambda = projection.prefix.LambdaClass(forcing = true)
476476
lambda.exists && !other.isLambda &&
477477
other.testLifted(lambda.typeParams,
478-
if (inOrder) isSubType(projection.prefix, _) else isSubType(_, projection.prefix))
478+
if (inOrder) isSubType(projection.prefix, _) else isSubType(_, projection.prefix),
479+
canWiden = !inOrder)
479480
}
480481

481482
/** Returns true iff either `tp11 <:< tp21` or `tp12 <:< tp22`, trying at the same time

0 commit comments

Comments
 (0)