@@ -1207,9 +1207,12 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1207
1207
case mt : MethodicType =>
1208
1208
p(mt.narrow)
1209
1209
case _ =>
1210
- followApply && tp.member(nme.apply).hasAltWith(d => p( TermRef (tp, nme.apply, d)) )
1210
+ followApply && hasApplyWith(tp)(p )
1211
1211
}
1212
1212
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
+
1213
1216
/** Does `tp` have an extension method named `name` with this-argument `argType` and
1214
1217
* result matching `resultType`?
1215
1218
*/
@@ -1272,46 +1275,78 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1272
1275
* assumption that for i = 1,...,n each ai is an abstract type name bounded
1273
1276
* from below by Li and from above by Ui.
1274
1277
* 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
1276
1279
* b. as specific as a member of any other type `tp2` if `tp1` is compatible
1277
1280
* 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.
1278
1305
*/
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
+ }
1315
1350
1316
1351
/** Test whether value type `tp1` is as specific as value type `tp2`.
1317
1352
* Let's abbreviate this to `tp1 <:s tp2`.
@@ -1402,8 +1437,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1402
1437
1403
1438
def compareWithTypes (tp1 : Type , tp2 : Type ) = {
1404
1439
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 )
1407
1442
1408
1443
overload.println(i " compare( $alt1, $alt2)? $tp1 $tp2 $ownerScore $winsType1 $winsType2" )
1409
1444
if (ownerScore == 1 )
@@ -1481,7 +1516,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1481
1516
altType.widen match {
1482
1517
case tp : PolyType => recur(constrained(tp).resultType, followApply)
1483
1518
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 ))
1485
1520
}
1486
1521
case _ => true
1487
1522
}
@@ -1582,7 +1617,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1582
1617
else isVarArgs || hasDefault
1583
1618
case tp =>
1584
1619
numArgs == 0 ||
1585
- followApply && onMethod (tp, followApply = true )(sizeFits(_, followApply = false ))
1620
+ followApply && hasApplyWith (tp)(sizeFits(_, followApply = false ))
1586
1621
}
1587
1622
1588
1623
def narrowBySize (alts : List [TermRef ]): List [TermRef ] =
0 commit comments