@@ -1599,19 +1599,43 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
15991599 * @param tparams2 The type parameters of the type constructor applied to `args2`
16001600 */
16011601 def isSubArgs (args1 : List [Type ], args2 : List [Type ], tp1 : Type , tparams2 : List [ParamInfo ]): Boolean = {
1602+
16021603 /** The bounds of parameter `tparam`, where all references to type paramneters
16031604 * are replaced by corresponding arguments (or their approximations in the case of
16041605 * wildcard arguments).
16051606 */
16061607 def paramBounds (tparam : Symbol ): TypeBounds =
16071608 tparam.info.substApprox(tparams2.asInstanceOf [List [Symbol ]], args2).bounds
16081609
1609- def recurArgs (args1 : List [Type ], args2 : List [Type ], tparams2 : List [ParamInfo ]): Boolean =
1610- if (args1.isEmpty) args2.isEmpty
1610+ /** Test all arguments. Incomplete argument tests (according to isIncomplete) are deferred in
1611+ * the first run and picked up in the second.
1612+ */
1613+ def recurArgs (args1 : List [Type ], args2 : List [Type ], tparams2 : List [ParamInfo ],
1614+ canDefer : Boolean ,
1615+ deferred1 : List [Type ], deferred2 : List [Type ], deferredTparams2 : List [ParamInfo ]): Boolean =
1616+ if args1.isEmpty then
1617+ args2.isEmpty
1618+ && (deferred1.isEmpty
1619+ || recurArgs(
1620+ deferred1.reverse, deferred2.reverse, deferredTparams2.reverse,
1621+ canDefer = false , Nil , Nil , Nil ))
16111622 else args2.nonEmpty && tparams2.nonEmpty && {
16121623 val tparam = tparams2.head
16131624 val v = tparam.paramVarianceSign
16141625
1626+ /** An argument test is incomplete if it implies a comparison A <: B where
1627+ * A is an AndType or B is an OrType. In these cases we need to run an
1628+ * either, which can lose solutions if there are type variables involved.
1629+ * So we defer such tests to run last, on the chance that some other argument
1630+ * comparison will instantiate or constrain type variables first.
1631+ */
1632+ def isIncomplete (arg1 : Type , arg2 : Type ): Boolean =
1633+ val arg1d = arg1.strippedDealias
1634+ val arg2d = arg2.strippedDealias
1635+ (v >= 0 ) && (arg1d.isInstanceOf [AndType ] || arg2d.isInstanceOf [OrType ])
1636+ ||
1637+ (v <= 0 ) && (arg1d.isInstanceOf [OrType ] || arg2d.isInstanceOf [AndType ])
1638+
16151639 /** Try a capture conversion:
16161640 * If the original left-hand type `leftRoot` is a path `p.type`,
16171641 * and the current widened left type is an application with wildcard arguments
@@ -1697,10 +1721,26 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
16971721 else if v > 0 then isSubType(arg1, arg2)
16981722 else isSameType(arg2, arg1)
16991723
1700- isSubArg(args1.head.boxedUnlessFun(tp1), args2.head.boxedUnlessFun(tp1))
1701- } && recurArgs(args1.tail, args2.tail, tparams2.tail)
1724+ val arg1 = args1.head.boxedUnlessFun(tp1)
1725+ val arg2 = args2.head.boxedUnlessFun(tp1)
1726+ val rest1 = args1.tail
1727+ if ! canDefer
1728+ || rest1.isEmpty && deferred1.isEmpty
1729+ // skip the incompleteness test if this is the last argument and no previous argument tests were incomplete
1730+ || ! isIncomplete(arg1, arg2)
1731+ then
1732+ isSubArg(arg1, arg2)
1733+ && recurArgs(
1734+ rest1, args2.tail, tparams2.tail, canDefer,
1735+ deferred1, deferred2, deferredTparams2)
1736+ else
1737+ recurArgs(
1738+ rest1, args2.tail, tparams2.tail, canDefer,
1739+ arg1 :: deferred1, arg2 :: deferred2, tparams2.head :: deferredTparams2)
1740+ }
1741+
1742+ recurArgs(args1, args2, tparams2, canDefer = true , Nil , Nil , Nil )
17021743
1703- recurArgs(args1, args2, tparams2)
17041744 }
17051745
17061746 /** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where
0 commit comments