@@ -1207,9 +1207,12 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12071207 case mt : MethodicType =>
12081208 p(mt.narrow)
12091209 case _ =>
1210- followApply && tp.member(nme.apply).hasAltWith(d => p( TermRef (tp, nme.apply, d)) )
1210+ followApply && hasApplyWith(tp)(p )
12111211 }
12121212
1213+ private def hasApplyWith (tp : Type )(p : TermRef => Boolean )(implicit ctx : Context ): Boolean =
1214+ tp.member(nme.apply).hasAltWith(d => p(TermRef (tp, nme.apply, d)))
1215+
12131216 /** Does `tp` have an extension method named `name` with this-argument `argType` and
12141217 * result matching `resultType`?
12151218 */
@@ -1272,46 +1275,78 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12721275 * assumption that for i = 1,...,n each ai is an abstract type name bounded
12731276 * from below by Li and from above by Ui.
12741277 * 3. A member of any other type `tp1` is:
1275- * a. always as specific as a method or a polymorphic method.
1278+ * a. always as specific as a method or a polymorphic method
12761279 * b. as specific as a member of any other type `tp2` if `tp1` is compatible
12771280 * with `tp2`.
1281+ *
1282+ * If followApply is true, and one of the alternatives is not a method, we test instead
1283+ * whether isAsSpecific is true for all apply methods in that alternative.
1284+ * Note that this is errs on the side of not being comparable in the following case:
1285+ *
1286+ * Alternatives
1287+ *
1288+ * val x: A
1289+ * def x(y: S): B
1290+ *
1291+ * where A has members
1292+ *
1293+ * def apply(y: S1): B1
1294+ * def apply(y: S2): B2
1295+ *
1296+ * and only one of the two `apply` methods (say the first) is applicable. If the first `apply`
1297+ * is as specific as the method `x`, but not the second, we still judge the two `x`'s
1298+ * as incomparable. If we had used an "exists an apply method" instead of the "forall"
1299+ * then value `x` would be picked over method `x` instead. On the other hand, if
1300+ * the first `apply` was NOT applicable but the second one was, then we would still pick
1301+ * pick value `x` over method `x` even though the applicable second apply method was is not
1302+ * more specific than the `x` method. So in going with "forall" instead of "exists" we
1303+ * err on the side of treating alternatives as incomparable, instead of potentially
1304+ * picking the wrong one.
12781305 */
1279- def isAsSpecific (alt1 : TermRef , tp1 : Type , alt2 : TermRef , tp2 : Type ): Boolean = trace(i " isAsSpecific $tp1 $tp2" , overload) { tp1 match {
1280- case tp1 : MethodType => // (1)
1281- val formals1 =
1282- if (tp1.isVarArgsMethod && tp2.isVarArgsMethod) tp1.paramInfos.map(_.repeatedToSingle)
1283- else tp1.paramInfos
1284- val isAsSpecificMethod =
1285- if (followApply) isApplicableType(alt2, formals1, WildcardType )
1286- else isApplicableMethodRef(alt2, formals1, WildcardType )
1287- isAsSpecificMethod || tp1.paramInfos.isEmpty && tp2.isInstanceOf [LambdaType ]
1288- case tp1 : PolyType => // (2)
1289- val nestedCtx = ctx.fresh.setExploreTyperState()
1290-
1291- {
1292- implicit val ctx = nestedCtx
1293-
1294- // Fully define the PolyType parameters so that the infos of the
1295- // tparams created below never contain TypeRefs whose underling types
1296- // contain uninstantiated TypeVars, this could lead to cycles in
1297- // `isSubType` as a TypeVar might get constrained by a TypeRef it's
1298- // part of.
1299- val tp1Params = tp1.newLikeThis(tp1.paramNames, tp1.paramInfos, defn.AnyType )
1300- fullyDefinedType(tp1Params, " type parameters of alternative" , alt1.symbol.span)
1301-
1302- val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags , tp1.instantiateParamInfos(_))
1303- isAsSpecific(alt1, tp1.instantiate(tparams.map(_.typeRef)), alt2, tp2)
1304- }
1305- case _ => // (3)
1306- tp2 match {
1307- case tp2 : MethodType => true // (3a)
1308- case tp2 : PolyType if tp2.resultType.isInstanceOf [MethodType ] => true // (3a)
1309- case tp2 : PolyType => // (3b)
1310- ctx.test(implicit ctx => isAsSpecificValueType(tp1, constrained(tp2).resultType))
1311- case _ => // (3b)
1312- isAsSpecificValueType(tp1, tp2)
1313- }
1314- }}
1306+ def isAsSpecific (alt1 : TermRef , tp1 : Type , alt2 : TermRef , tp2 : Type , followApply : Boolean ): Boolean = trace(i " isAsSpecific $tp1 $tp2" , overload) {
1307+ if (followApply) {
1308+ val isMethod1 = tp1.stripPoly.isInstanceOf [MethodType ]
1309+ val isMethod2 = tp2.stripPoly.isInstanceOf [MethodType ]
1310+ if (! isMethod1 && isMethod2)
1311+ return ! hasApplyWith(tp1)(alt1app => ! isAsSpecific(alt1app, alt1app.widen, alt2, tp2, false ))
1312+ if (! isMethod2 && isMethod1)
1313+ return ! hasApplyWith(tp2)(alt2app => ! isAsSpecific(alt1, tp1, alt2app, alt2app.widen, false ))
1314+ }
1315+ tp1 match {
1316+ case tp1 : MethodType => // (1)
1317+ val formals1 =
1318+ if (tp1.isVarArgsMethod && tp2.isVarArgsMethod) tp1.paramInfos.map(_.repeatedToSingle)
1319+ else tp1.paramInfos
1320+ val isAsSpecificMethod = isApplicableMethodRef(alt2, formals1, WildcardType )
1321+ isAsSpecificMethod || tp1.paramInfos.isEmpty && tp2.isInstanceOf [LambdaType ]
1322+ case tp1 : PolyType => // (2)
1323+ val nestedCtx = ctx.fresh.setExploreTyperState()
1324+
1325+ {
1326+ implicit val ctx = nestedCtx
1327+
1328+ // Fully define the PolyType parameters so that the infos of the
1329+ // tparams created below never contain TypeRefs whose underling types
1330+ // contain uninstantiated TypeVars, this could lead to cycles in
1331+ // `isSubType` as a TypeVar might get constrained by a TypeRef it's
1332+ // part of.
1333+ val tp1Params = tp1.newLikeThis(tp1.paramNames, tp1.paramInfos, defn.AnyType )
1334+ fullyDefinedType(tp1Params, " type parameters of alternative" , alt1.symbol.span)
1335+
1336+ val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags , tp1.instantiateParamInfos(_))
1337+ isAsSpecific(alt1, tp1.instantiate(tparams.map(_.typeRef)), alt2, tp2, followApply)
1338+ }
1339+ case _ => // (3)
1340+ tp2 match {
1341+ case tp2 : MethodType => true
1342+ case tp2 : PolyType if tp2.resultType.isInstanceOf [MethodType ] => true
1343+ case tp2 : PolyType => // (3b)
1344+ ctx.test(implicit ctx => isAsSpecificValueType(tp1, constrained(tp2).resultType))
1345+ case _ => // (3b)
1346+ isAsSpecificValueType(tp1, tp2)
1347+ }
1348+ }
1349+ }
13151350
13161351 /** Test whether value type `tp1` is as specific as value type `tp2`.
13171352 * Let's abbreviate this to `tp1 <:s tp2`.
@@ -1402,8 +1437,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14021437
14031438 def compareWithTypes (tp1 : Type , tp2 : Type ) = {
14041439 val ownerScore = compareOwner(alt1.symbol.maybeOwner, alt2.symbol.maybeOwner)
1405- def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2)
1406- def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
1440+ def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2, followApply )
1441+ def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1, followApply )
14071442
14081443 overload.println(i " compare( $alt1, $alt2)? $tp1 $tp2 $ownerScore $winsType1 $winsType2" )
14091444 if (ownerScore == 1 )
@@ -1481,7 +1516,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14811516 altType.widen match {
14821517 case tp : PolyType => recur(constrained(tp).resultType, followApply)
14831518 case tp : MethodType => constrainResult(altSym, tp.resultType, resultType)
1484- case _ => ! followApply || onMethod (altType, followApply )(recur(_, followApply = false ))
1519+ case _ => ! followApply || hasApplyWith (altType)(recur(_, followApply = false ))
14851520 }
14861521 case _ => true
14871522 }
@@ -1582,7 +1617,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15821617 else isVarArgs || hasDefault
15831618 case tp =>
15841619 numArgs == 0 ||
1585- followApply && onMethod (tp, followApply = true )(sizeFits(_, followApply = false ))
1620+ followApply && hasApplyWith (tp)(sizeFits(_, followApply = false ))
15861621 }
15871622
15881623 def narrowBySize (alts : List [TermRef ]): List [TermRef ] =
0 commit comments