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