@@ -1169,6 +1169,12 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
11691169 if (keepConstraint) isApp else ctx.test(implicit ctx => isApp)
11701170 }
11711171
1172+ /** Is given method reference applicable to type arguments `targs` and argument trees `args` without inferring views?
1173+ * @param resultType The expected result type of the application
1174+ */
1175+ def isDirectlyApplicableMethodRef (methRef : TermRef , targs : List [Type ], args : List [Tree ], resultType : Type )(implicit ctx : Context ): Boolean =
1176+ ctx.test(implicit ctx => new ApplicableToTreesDirectly (methRef, targs, args, resultType).success)
1177+
11721178 /** Is given method reference applicable to argument types `args`?
11731179 * @param resultType The expected result type of the application
11741180 */
@@ -1192,27 +1198,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
11921198 isApplicableMethodRef(_, args, resultType)
11931199 }
11941200
1195- /** Is given method type applicable to type arguments `targs` and argument trees `args` without inferring views,
1196- * possibly after inserting an `apply`?
1197- * @param resultType The expected result type of the application
1198- */
1199- def isDirectlyApplicableType (tp : Type , targs : List [Type ], args : List [Tree ], resultType : Type )(implicit ctx : Context ): Boolean =
1200- onMethod(tp, targs.nonEmpty || args.nonEmpty) { methRef =>
1201- ctx.test(implicit ctx => new ApplicableToTreesDirectly (methRef, targs, args, resultType).success)
1202- }
1203-
12041201 private def onMethod (tp : Type , followApply : Boolean )(p : TermRef => Boolean )(implicit ctx : Context ): Boolean = tp match {
12051202 case methRef : TermRef if methRef.widenSingleton.isInstanceOf [MethodicType ] =>
12061203 p(methRef)
12071204 case mt : MethodicType =>
12081205 p(mt.narrow)
12091206 case _ =>
1210- followApply && hasApplyWith(tp)(p )
1207+ followApply && tp.member(nme.apply).hasAltWith(d => p( TermRef (tp, nme.apply, d)) )
12111208 }
12121209
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-
12161210 /** Does `tp` have an extension method named `name` with this-argument `argType` and
12171211 * result matching `resultType`?
12181212 */
@@ -1257,10 +1251,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12571251 * If that tournament yields a draw, a tiebreak is applied where
12581252 * an alternative that takes more implicit parameters wins over one
12591253 * that takes fewer.
1260- *
1261- * @param followApply if true consider `apply` members when comparing with a method reference
12621254 */
1263- def compare (alt1 : TermRef , alt2 : TermRef , followApply : Boolean )(implicit ctx : Context ): Int = track(" compare" ) { trace(i " compare( $alt1, $alt2) " , overload) {
1255+ def compare (alt1 : TermRef , alt2 : TermRef )(implicit ctx : Context ): Int = track(" compare" ) { trace(i " compare( $alt1, $alt2) " , overload) {
12641256
12651257 assert(alt1 ne alt2)
12661258
@@ -1275,78 +1267,44 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12751267 * assumption that for i = 1,...,n each ai is an abstract type name bounded
12761268 * from below by Li and from above by Ui.
12771269 * 3. A member of any other type `tp1` is:
1278- * a. always as specific as a method or a polymorphic method
1270+ * a. always as specific as a method or a polymorphic method.
12791271 * b. as specific as a member of any other type `tp2` if `tp1` is compatible
12801272 * 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.
13051273 */
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- }
1274+ def isAsSpecific (alt1 : TermRef , tp1 : Type , alt2 : TermRef , tp2 : Type ): Boolean = trace(i " isAsSpecific $tp1 $tp2" , overload) { tp1 match {
1275+ case tp1 : MethodType => // (1)
1276+ val formals1 =
1277+ if (tp1.isVarArgsMethod && tp2.isVarArgsMethod) tp1.paramInfos.map(_.repeatedToSingle)
1278+ else tp1.paramInfos
1279+ isApplicableMethodRef(alt2, formals1, WildcardType ) ||
1280+ tp1.paramInfos.isEmpty && tp2.isInstanceOf [LambdaType ]
1281+ case tp1 : PolyType => // (2)
1282+ val nestedCtx = ctx.fresh.setExploreTyperState()
1283+
1284+ {
1285+ implicit val ctx = nestedCtx
1286+
1287+ // Fully define the PolyType parameters so that the infos of the
1288+ // tparams created below never contain TypeRefs whose underling types
1289+ // contain uninstantiated TypeVars, this could lead to cycles in
1290+ // `isSubType` as a TypeVar might get constrained by a TypeRef it's
1291+ // part of.
1292+ val tp1Params = tp1.newLikeThis(tp1.paramNames, tp1.paramInfos, defn.AnyType )
1293+ fullyDefinedType(tp1Params, " type parameters of alternative" , alt1.symbol.span)
1294+
1295+ val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags , tp1.instantiateParamInfos(_))
1296+ isAsSpecific(alt1, tp1.instantiate(tparams.map(_.typeRef)), alt2, tp2)
1297+ }
1298+ case _ => // (3)
1299+ tp2 match {
1300+ case tp2 : MethodType => true // (3a)
1301+ case tp2 : PolyType if tp2.resultType.isInstanceOf [MethodType ] => true // (3a)
1302+ case tp2 : PolyType => // (3b)
1303+ ctx.test(implicit ctx => isAsSpecificValueType(tp1, constrained(tp2).resultType))
1304+ case _ => // (3b)
1305+ isAsSpecificValueType(tp1, tp2)
1306+ }
1307+ }}
13501308
13511309 /** Test whether value type `tp1` is as specific as value type `tp2`.
13521310 * Let's abbreviate this to `tp1 <:s tp2`.
@@ -1437,8 +1395,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14371395
14381396 def compareWithTypes (tp1 : Type , tp2 : Type ) = {
14391397 val ownerScore = compareOwner(alt1.symbol.maybeOwner, alt2.symbol.maybeOwner)
1440- def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2, followApply )
1441- def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1, followApply )
1398+ def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2)
1399+ def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
14421400
14431401 overload.println(i " compare( $alt1, $alt2)? $tp1 $tp2 $ownerScore $winsType1 $winsType2" )
14441402 if (ownerScore == 1 )
@@ -1465,20 +1423,20 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14651423 else compareWithTypes(fullType1, fullType2) // continue by comparing implicits parameters
14661424 }}
14671425
1468- def narrowMostSpecific (alts : List [TermRef ], followApply : Boolean )(implicit ctx : Context ): List [TermRef ] = track(" narrowMostSpecific" ) {
1426+ def narrowMostSpecific (alts : List [TermRef ])(implicit ctx : Context ): List [TermRef ] = track(" narrowMostSpecific" ) {
14691427 alts match {
14701428 case Nil => alts
14711429 case _ :: Nil => alts
14721430 case alt1 :: alt2 :: Nil =>
1473- compare(alt1, alt2, followApply ) match {
1431+ compare(alt1, alt2) match {
14741432 case 1 => alt1 :: Nil
14751433 case - 1 => alt2 :: Nil
14761434 case 0 => alts
14771435 }
14781436 case alt :: alts1 =>
14791437 def survivors (previous : List [TermRef ], alts : List [TermRef ]): List [TermRef ] = alts match {
14801438 case alt :: alts1 =>
1481- compare(previous.head, alt, followApply ) match {
1439+ compare(previous.head, alt) match {
14821440 case 1 => survivors(previous, alts1)
14831441 case - 1 => survivors(alt :: previous.tail, alts1)
14841442 case 0 => survivors(alt :: previous, alts1)
@@ -1488,7 +1446,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14881446 val best :: rest = survivors(alt :: Nil , alts1)
14891447 def asGood (alts : List [TermRef ]): List [TermRef ] = alts match {
14901448 case alt :: alts1 =>
1491- if (compare(alt, best, followApply ) < 0 ) asGood(alts1) else alt :: asGood(alts1)
1449+ if (compare(alt, best) < 0 ) asGood(alts1) else alt :: asGood(alts1)
14921450 case nil =>
14931451 Nil
14941452 }
@@ -1507,21 +1465,17 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15071465 /** Is `alt` a method or polytype whose result type after the first value parameter
15081466 * section conforms to the expected type `resultType`? If `resultType`
15091467 * is a `IgnoredProto`, pick the underlying type instead.
1510- * If `alt`does not have method or poly type, and `followApply` is true, consider
1511- * all apply members instead. In all other cases return `true`.
15121468 */
1513- def resultConforms (altSym : Symbol , altType : Type , resultType : Type )(implicit ctx : Context ): Boolean = {
1514- def recur ( altType : Type , followApply : Boolean ) : Boolean = resultType.revealIgnored match {
1469+ def resultConforms (altSym : Symbol , altType : Type , resultType : Type )(implicit ctx : Context ): Boolean =
1470+ resultType.revealIgnored match {
15151471 case resultType : ValueType =>
15161472 altType.widen match {
1517- case tp : PolyType => recur( constrained(tp).resultType, followApply )
1473+ case tp : PolyType => resultConforms(altSym, constrained(tp).resultType, resultType )
15181474 case tp : MethodType => constrainResult(altSym, tp.resultType, resultType)
1519- case _ => ! followApply || hasApplyWith(altType)(recur(_, followApply = false ))
1475+ case _ => true
15201476 }
15211477 case _ => true
15221478 }
1523- recur(altType, followApply = true )
1524- }
15251479
15261480 /** If the `chosen` alternative has a result type incompatible with the expected result
15271481 * type `pt`, run overloading resolution again on all alternatives that do match `pt`.
@@ -1535,7 +1489,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15351489 * probability of pruning the search. result type comparisons are neither cheap nor
15361490 * do they prune much, on average.
15371491 */
1538- def adaptByResult (chosen : TermRef ) = pt match {
1492+ def adaptByResult (chosen : TermRef , alts : List [ TermRef ] ) = pt match {
15391493 case pt : FunProto if ! ctx.test(implicit ctx => resultConforms(chosen.symbol, chosen, pt.resultType)) =>
15401494 val conformingAlts = alts.filter(alt =>
15411495 (alt ne chosen) && ctx.test(implicit ctx => resultConforms(alt.symbol, alt, pt.resultType)))
@@ -1551,13 +1505,42 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15511505 case _ => chosen
15521506 }
15531507
1554- var found = resolveOverloaded(alts, pt, Nil )(ctx.retractMode(Mode .ImplicitsEnabled ))
1555- if (found.isEmpty && ctx.mode.is(Mode .ImplicitsEnabled ))
1556- found = resolveOverloaded(alts, pt, Nil )
1557- found match {
1558- case alt :: Nil => adaptByResult(alt) :: Nil
1559- case _ => found
1508+ def resolve (alts : List [TermRef ]) = {
1509+ var found = resolveOverloaded(alts, pt, Nil )(ctx.retractMode(Mode .ImplicitsEnabled ))
1510+ if (found.isEmpty && ctx.mode.is(Mode .ImplicitsEnabled ))
1511+ found = resolveOverloaded(alts, pt, Nil )
1512+ found match {
1513+ case alt :: Nil => adaptByResult(alt, alts) :: Nil
1514+ case _ => found
1515+ }
1516+ }
1517+
1518+ /** Try an apply method, if
1519+ * - the result is applied to value arguments and alternative is not a method, or
1520+ * - the result is applied to type arguments and alternatuve is not polymorphic
1521+ */
1522+ val tryApply : Type => Boolean = alt => pt match {
1523+ case pt : FunProto => ! alt.widen.stripPoly.isInstanceOf [MethodType ]
1524+ case pt : PolyProto => ! alt.widen.isInstanceOf [PolyType ]
1525+ case _ => false
15601526 }
1527+
1528+ /** Replace each alternative by its apply members where necesssary */
1529+ def applyMembers (alt : TermRef ): List [TermRef ] =
1530+ if (tryApply(alt)) alt.member(nme.apply).alternatives.map(TermRef (alt, nme.apply, _))
1531+ else alt :: Nil
1532+
1533+ /** Fall back from an apply method to its original alternative */
1534+ def retract (alt : TermRef ): TermRef =
1535+ if (alt.name == nme.apply && ! alts.contains(alt))
1536+ alts.find(_.symbol == alt.prefix.termSymbol).getOrElse(alt)
1537+ else alt
1538+
1539+ if (alts.exists(tryApply)) {
1540+ val expanded = alts.flatMap(applyMembers)
1541+ resolve(expanded).map(retract)
1542+ }
1543+ else resolve(alts)
15611544 }
15621545
15631546 /** This private version of `resolveOverloaded` does the bulk of the work of
@@ -1591,21 +1574,17 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15911574 }
15921575
15931576 def narrowByTypes (alts : List [TermRef ], argTypes : List [Type ], resultType : Type ): List [TermRef ] =
1594- alts filter (isApplicableType(_, argTypes, resultType))
1595-
1596- val numArgs = pt match {
1597- case pt @ FunProto (args, resultType) => args.length
1598- case _ => 0
1599- }
1577+ alts filter (isApplicableMethodRef(_, argTypes, resultType))
16001578
16011579 val candidates = pt match {
16021580 case pt @ FunProto (args, resultType) =>
1581+ val numArgs = args.length
16031582 val normArgs = args.mapConserve {
16041583 case Block (Nil , expr) => expr
16051584 case x => x
16061585 }
16071586
1608- def sizeFits (alt : TermRef , followApply : Boolean ): Boolean = alt.widen.stripPoly match {
1587+ def sizeFits (alt : TermRef ): Boolean = alt.widen.stripPoly match {
16091588 case tp : MethodType =>
16101589 val ptypes = tp.paramInfos
16111590 val numParams = ptypes.length
@@ -1615,13 +1594,12 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
16151594 else if (numParams < numArgs) isVarArgs
16161595 else if (numParams > numArgs + 1 ) hasDefault
16171596 else isVarArgs || hasDefault
1618- case tp =>
1619- numArgs == 0 ||
1620- followApply && hasApplyWith(tp)(sizeFits(_, followApply = false ))
1597+ case _ =>
1598+ numArgs == 0
16211599 }
16221600
16231601 def narrowBySize (alts : List [TermRef ]): List [TermRef ] =
1624- alts.filter(sizeFits(_, followApply = true ))
1602+ alts.filter(sizeFits(_))
16251603
16261604 def narrowByShapes (alts : List [TermRef ]): List [TermRef ] = {
16271605 if (normArgs exists untpd.isFunctionWithUnknownParamType)
@@ -1633,11 +1611,11 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
16331611
16341612 def narrowByTrees (alts : List [TermRef ], args : List [Tree ], resultType : Type ): List [TermRef ] = {
16351613 val alts2 = alts.filter(alt =>
1636- isDirectlyApplicableType (alt, targs, args, resultType)
1614+ isDirectlyApplicableMethodRef (alt, targs, args, resultType)
16371615 )
16381616 if (alts2.isEmpty && ! ctx.isAfterTyper)
16391617 alts.filter(alt =>
1640- isApplicableType (alt, targs, args, resultType, keepConstraint = false )
1618+ isApplicableMethodRef (alt, targs, args, resultType, keepConstraint = false )
16411619 )
16421620 else
16431621 alts2
@@ -1708,7 +1686,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
17081686 candidates.flatMap(cloneCandidate)
17091687 }
17101688
1711- val found = narrowMostSpecific(candidates, followApply = numArgs != 0 )
1689+ val found = narrowMostSpecific(candidates)
17121690 if (found.length <= 1 ) found
17131691 else pt match {
17141692 case pt @ FunProto (_, resType : FunProto ) =>
@@ -1880,4 +1858,3 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
18801858 app
18811859 }
18821860}
1883-
0 commit comments