@@ -169,6 +169,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
169
169
private inline def inFrozenGadtAndConstraint [T ](inline op : T ): T =
170
170
inFrozenGadtIf(true )(inFrozenConstraint(op))
171
171
172
+ extension (tp : TypeRef )
173
+ private inline def onGadtBounds (inline op : TypeBounds => Boolean ): Boolean =
174
+ val bounds = gadtBounds(tp.symbol)
175
+ bounds != null && op(bounds)
176
+
172
177
protected def isSubType (tp1 : Type , tp2 : Type , a : ApproxState ): Boolean = {
173
178
val savedApprox = approx
174
179
val savedLeftRoot = leftRoot
@@ -465,19 +470,15 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
465
470
case AndType (tp21, tp22) => constrainRHSVars(tp21) && constrainRHSVars(tp22)
466
471
case _ => true
467
472
468
- // An & on the left side loses information. We compensate by also trying the join.
469
- // This is less ad-hoc than it looks since we produce joins in type inference,
470
- // and then need to check that they are indeed supertypes of the original types
471
- // under -Ycheck. Test case is i7965.scala.
472
- def containsAnd (tp : Type ): Boolean = tp.dealiasKeepRefiningAnnots match
473
- case tp : AndType => true
474
- case OrType (tp1, tp2) => containsAnd(tp1) || containsAnd(tp2)
475
- case _ => false
476
-
477
473
widenOK
478
474
|| joinOK
479
475
|| (tp1.isSoft || constrainRHSVars(tp2)) && recur(tp11, tp2) && recur(tp12, tp2)
480
476
|| containsAnd(tp1) && inFrozenGadt(recur(tp1.join, tp2))
477
+ // An & on the left side loses information. We compensate by also trying the join.
478
+ // This is less ad-hoc than it looks since we produce joins in type inference,
479
+ // and then need to check that they are indeed supertypes of the original types
480
+ // under -Ycheck. Test case is i7965.scala.
481
+
481
482
case tp1 : MatchType =>
482
483
val reduced = tp1.reduced
483
484
if (reduced.exists) recur(reduced, tp2) else thirdTry
@@ -559,40 +560,35 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
559
560
case tp2 : TypeParamRef =>
560
561
compareTypeParamRef(tp2)
561
562
case tp2 : RefinedType =>
562
- def compareRefinedSlow : Boolean = {
563
+ def compareRefinedSlow : Boolean =
563
564
val name2 = tp2.refinedName
564
- recur(tp1, tp2.parent) &&
565
- (name2 == nme.WILDCARD || hasMatchingMember(name2, tp1, tp2))
566
- }
567
- def compareRefined : Boolean = {
565
+ recur(tp1, tp2.parent)
566
+ && (name2 == nme.WILDCARD || hasMatchingMember(name2, tp1, tp2))
567
+
568
+ def compareRefined : Boolean =
568
569
val tp1w = tp1.widen
569
570
val skipped2 = skipMatching(tp1w, tp2)
570
- if ((skipped2 eq tp2) || ! Config .fastPathForRefinedSubtype)
571
- tp1 match {
572
- case tp1 : AndType =>
573
- // TODO: this should really be an in depth analysis whether LHS contains
574
- // an AndType, or has an AndType as bound. What matters is to predict
575
- // whether we will be forced into an either later on.
576
- tp2.parent match
577
- case _ : RefinedType | _ : AndType =>
578
- // maximally decompose RHS to limit the bad effects of the `either` that is necessary
579
- // since LHS is an AndType
580
- recur(tp1, decomposeRefinements(tp2, Nil ))
581
- case _ =>
582
- // Delay calling `compareRefinedSlow` because looking up a member
583
- // of an `AndType` can lead to a cascade of subtyping checks
584
- // This twist is needed to make collection/generic/ParFactory.scala compile
585
- fourthTry || compareRefinedSlow
586
- case tp1 : HKTypeLambda =>
587
- // HKTypeLambdas do not have members.
588
- fourthTry
589
- case _ =>
590
- compareRefinedSlow || fourthTry
591
- }
571
+ if (skipped2 eq tp2) || ! Config .fastPathForRefinedSubtype then
572
+ if containsAnd(tp1) then
573
+ tp2.parent match
574
+ case _ : RefinedType | _ : AndType =>
575
+ // maximally decompose RHS to limit the bad effects of the `either` that is necessary
576
+ // since LHS contains an AndType
577
+ recur(tp1, decomposeRefinements(tp2, Nil ))
578
+ case _ =>
579
+ // Delay calling `compareRefinedSlow` because looking up a member
580
+ // of an `AndType` can lead to a cascade of subtyping checks
581
+ // This twist is needed to make collection/generic/ParFactory.scala compile
582
+ fourthTry || compareRefinedSlow
583
+ else if tp1.isInstanceOf [HKTypeLambda ] then
584
+ // HKTypeLambdas do not have members.
585
+ fourthTry
586
+ else
587
+ compareRefinedSlow || fourthTry
592
588
else // fast path, in particular for refinements resulting from parameterization.
593
589
isSubRefinements(tp1w.asInstanceOf [RefinedType ], tp2, skipped2) &&
594
590
recur(tp1, skipped2)
595
- }
591
+
596
592
compareRefined
597
593
case tp2 : RecType =>
598
594
def compareRec = tp1.safeDealias match {
@@ -1709,6 +1705,17 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
1709
1705
case _ =>
1710
1706
refines.map(RefinedType (tp, _, _): Type ).reduce(AndType (_, _))
1711
1707
1708
+ /** Can comparing this type on the left lead to an either? This is the case if
1709
+ * the type is and AndType or contains embedded occurrences of AndTypes
1710
+ */
1711
+ def containsAnd (tp : Type ): Boolean = tp match
1712
+ case tp : AndType => true
1713
+ case OrType (tp1, tp2) => containsAnd(tp1) || containsAnd(tp2)
1714
+ case tp : TypeParamRef => containsAnd(bounds(tp).hi)
1715
+ case tp : TypeRef => containsAnd(tp.info.hiBound) || tp.onGadtBounds(gbounds => containsAnd(gbounds.hi))
1716
+ case tp : TypeProxy => containsAnd(tp.superType)
1717
+ case _ => false
1718
+
1712
1719
/** Does type `tp1` have a member with name `name` whose normalized type is a subtype of
1713
1720
* the normalized type of the refinement `tp2`?
1714
1721
* Normalization is as follows: If `tp2` contains a skolem to its refinement type,
0 commit comments