@@ -478,7 +478,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
478478 tp2.isRef(AnyClass , skipRefined = false )
479479 || ! tp1.evaluating && recur(tp1.ref, tp2)
480480 case AndType (tp11, tp12) =>
481- if ( tp11.stripTypeVar eq tp12.stripTypeVar) recur(tp11, tp2)
481+ if tp11.stripTypeVar eq tp12.stripTypeVar then recur(tp11, tp2)
482482 else thirdTry
483483 case tp1 @ OrType (tp11, tp12) =>
484484 compareAtoms(tp1, tp2) match
@@ -898,8 +898,27 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
898898
899899 canWidenAbstract && acc(true , tp)
900900
901- def tryBaseType (cls2 : Symbol ) = {
902- val base = nonExprBaseType(tp1, cls2).boxedIfTypeParam(tp1.typeSymbol)
901+ def tryBaseType (cls2 : Symbol ) =
902+
903+ def computeBase (tp : Type ): Type = tp.widenDealias match
904+ case tp @ AndType (tp1, tp2) =>
905+ // We have to treat AndTypes specially, since the normal treatment
906+ // of `(T1 & T2).baseType(C)` combines the base types of T1 and T2 via glb
907+ // which drops any types that don't exist. That forgets possible solutions.
908+ // For instance, in i18266.scala, we get to a subgoal `R & Row[Int] <: Row[String]`
909+ // where R is an uninstantiated type variable. The base type computation
910+ // of the LHS drops the non-existing base type of R and results in
911+ // `Row[Int]`, which leads to a subtype failure since `Row[Int] <: Row[String]`
912+ // does not hold. The new strategy is to declare that the base type computation
913+ // failed since R does not have a base type, and to proceed to fourthTry instead,
914+ // where we try both sides of an AndType individually.
915+ val b1 = computeBase(tp1)
916+ val b2 = computeBase(tp2)
917+ if b1.exists && b2.exists then tp.derivedAndType(b1, b2) else NoType
918+ case _ =>
919+ nonExprBaseType(tp, cls2).boxedIfTypeParam(tp.typeSymbol)
920+
921+ val base = computeBase(tp1)
903922 if base.exists && (base ne tp1)
904923 && (! caseLambda.exists
905924 || widenAbstractOKFor(tp2)
@@ -912,7 +931,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
912931 // expands to a match type. In this case, we should try to reduce the type
913932 // and compare the redux. This is done in fourthTry
914933 else fourthTry
915- }
934+ end tryBaseType
916935
917936 def fourthTry : Boolean = tp1 match {
918937 case tp1 : TypeRef =>
@@ -989,7 +1008,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
9891008 }
9901009 }
9911010 compareHKLambda
992- case AndType (tp11, tp12) =>
1011+ case tp1 @ AndType (tp11, tp12) =>
9931012 val tp2a = tp2.dealiasKeepRefiningAnnots
9941013 if (tp2a ne tp2) // Follow the alias; this might avoid truncating the search space in the either below
9951014 return recur(tp1, tp2a)
@@ -1009,8 +1028,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
10091028 return recur(AndType (tp11, tp121), tp2) && recur(AndType (tp11, tp122), tp2)
10101029 case _ =>
10111030 }
1012- val tp1norm = simplifyAndTypeWithFallback(tp11, tp12, tp1)
1013- if ( tp1 ne tp1norm) recur(tp1norm, tp2)
1031+ val tp1norm = trySimplify( tp1)
1032+ if tp1 ne tp1norm then recur(tp1norm, tp2)
10141033 else either(recur(tp11, tp2), recur(tp12, tp2))
10151034 case tp1 : MatchType =>
10161035 def compareMatch = tp2 match {
@@ -2506,8 +2525,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25062525 final def andType (tp1 : Type , tp2 : Type , isErased : Boolean = ctx.erasedTypes): Type =
25072526 andTypeGen(tp1, tp2, AndType .balanced(_, _), isErased = isErased)
25082527
2509- final def simplifyAndTypeWithFallback (tp1 : Type , tp2 : Type , fallback : Type ): Type =
2510- andTypeGen(tp1, tp2, (_, _) => fallback)
2528+ /** Try to simplify AndType, or return the type itself if no simplifiying opportunities exist. */
2529+ private def trySimplify (tp : AndType ): Type =
2530+ andTypeGen(tp.tp1, tp.tp2, (_, _) => tp)
25112531
25122532 /** Form a normalized conjunction of two types.
25132533 * Note: For certain types, `|` is distributed inside the type. This holds for
0 commit comments