@@ -1683,19 +1683,43 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
16831683 * @param tparams2 The type parameters of the type constructor applied to `args2`
16841684 */
16851685 def isSubArgs (args1 : List [Type ], args2 : List [Type ], tp1 : Type , tparams2 : List [ParamInfo ]): Boolean = {
1686+
16861687 /** The bounds of parameter `tparam`, where all references to type paramneters
16871688 * are replaced by corresponding arguments (or their approximations in the case of
16881689 * wildcard arguments).
16891690 */
16901691 def paramBounds (tparam : Symbol ): TypeBounds =
16911692 tparam.info.substApprox(tparams2.asInstanceOf [List [Symbol ]], args2).bounds
16921693
1693- def recurArgs (args1 : List [Type ], args2 : List [Type ], tparams2 : List [ParamInfo ]): Boolean =
1694- if (args1.isEmpty) args2.isEmpty
1694+ /** Test all arguments. Incomplete argument tests (according to isIncomplete) are deferred in
1695+ * the first run and picked up in the second.
1696+ */
1697+ def recurArgs (args1 : List [Type ], args2 : List [Type ], tparams2 : List [ParamInfo ],
1698+ canDefer : Boolean ,
1699+ deferred1 : List [Type ], deferred2 : List [Type ], deferredTparams2 : List [ParamInfo ]): Boolean =
1700+ if args1.isEmpty then
1701+ args2.isEmpty
1702+ && (deferred1.isEmpty
1703+ || recurArgs(
1704+ deferred1.reverse, deferred2.reverse, deferredTparams2.reverse,
1705+ canDefer = false , Nil , Nil , Nil ))
16951706 else args2.nonEmpty && tparams2.nonEmpty && {
16961707 val tparam = tparams2.head
16971708 val v = tparam.paramVarianceSign
16981709
1710+ /** An argument test is incomplete if it implies a comparison A <: B where
1711+ * A is an AndType or B is an OrType. In these cases we need to run an
1712+ * either, which can lose solutions if there are type variables involved.
1713+ * So we defer such tests to run last, on the chance that some other argument
1714+ * comparison will instantiate or constrain type variables first.
1715+ */
1716+ def isIncomplete (arg1 : Type , arg2 : Type ): Boolean =
1717+ val arg1d = arg1.strippedDealias
1718+ val arg2d = arg2.strippedDealias
1719+ (v >= 0 ) && (arg1d.isInstanceOf [AndType ] || arg2d.isInstanceOf [OrType ])
1720+ ||
1721+ (v <= 0 ) && (arg1d.isInstanceOf [OrType ] || arg2d.isInstanceOf [AndType ])
1722+
16991723 /** Try a capture conversion:
17001724 * If the original left-hand type `leftRoot` is a path `p.type`,
17011725 * and the current widened left type is an application with wildcard arguments
@@ -1781,10 +1805,26 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
17811805 else if v > 0 then isSubType(arg1, arg2)
17821806 else isSameType(arg2, arg1)
17831807
1784- isSubArg(args1.head, args2.head)
1785- } && recurArgs(args1.tail, args2.tail, tparams2.tail)
1808+ val arg1 = args1.head
1809+ val arg2 = args2.head
1810+ val rest1 = args1.tail
1811+ if ! canDefer
1812+ || rest1.isEmpty && deferred1.isEmpty
1813+ // skip the incompleteness test if this is the last argument and no previous argument tests were incomplete
1814+ || ! isIncomplete(arg1, arg2)
1815+ then
1816+ isSubArg(arg1, arg2)
1817+ && recurArgs(
1818+ rest1, args2.tail, tparams2.tail, canDefer,
1819+ deferred1, deferred2, deferredTparams2)
1820+ else
1821+ recurArgs(
1822+ rest1, args2.tail, tparams2.tail, canDefer,
1823+ arg1 :: deferred1, arg2 :: deferred2, tparams2.head :: deferredTparams2)
1824+ }
1825+
1826+ recurArgs(args1, args2, tparams2, canDefer = true , Nil , Nil , Nil )
17861827
1787- recurArgs(args1, args2, tparams2)
17881828 }
17891829
17901830 /** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where
0 commit comments