@@ -169,6 +169,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
169169 private inline def inFrozenGadtAndConstraint [T ](inline op : T ): T =
170170 inFrozenGadtIf(true )(inFrozenConstraint(op))
171171
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+
172177 protected def isSubType (tp1 : Type , tp2 : Type , a : ApproxState ): Boolean = {
173178 val savedApprox = approx
174179 val savedLeftRoot = leftRoot
@@ -465,19 +470,15 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
465470 case AndType (tp21, tp22) => constrainRHSVars(tp21) && constrainRHSVars(tp22)
466471 case _ => true
467472
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-
477473 widenOK
478474 || joinOK
479475 || (tp1.isSoft || constrainRHSVars(tp2)) && recur(tp11, tp2) && recur(tp12, tp2)
480476 || 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+
481482 case tp1 : MatchType =>
482483 val reduced = tp1.reduced
483484 if (reduced.exists) recur(reduced, tp2) else thirdTry
@@ -559,40 +560,35 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
559560 case tp2 : TypeParamRef =>
560561 compareTypeParamRef(tp2)
561562 case tp2 : RefinedType =>
562- def compareRefinedSlow : Boolean = {
563+ def compareRefinedSlow : Boolean =
563564 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 =
568569 val tp1w = tp1.widen
569570 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
592588 else // fast path, in particular for refinements resulting from parameterization.
593589 isSubRefinements(tp1w.asInstanceOf [RefinedType ], tp2, skipped2) &&
594590 recur(tp1, skipped2)
595- }
591+
596592 compareRefined
597593 case tp2 : RecType =>
598594 def compareRec = tp1.safeDealias match {
@@ -1709,6 +1705,17 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
17091705 case _ =>
17101706 refines.map(RefinedType (tp, _, _): Type ).reduce(AndType (_, _))
17111707
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+
17121719 /** Does type `tp1` have a member with name `name` whose normalized type is a subtype of
17131720 * the normalized type of the refinement `tp2`?
17141721 * Normalization is as follows: If `tp2` contains a skolem to its refinement type,
0 commit comments