@@ -1191,6 +1191,10 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
11911191 *
11921192 * - A1's owner derives from A2's owner.
11931193 * - A1's type is more specific than A2's type.
1194+ *
1195+ * If that tournament yields a draw, a tiebreak is applied where
1196+ * an alternative that takes more implicit parameters wins over one
1197+ * that takes fewer.
11941198 */
11951199 def compare (alt1 : TermRef , alt2 : TermRef )(implicit ctx : Context ): Int = track(" compare" ) { trace(i " compare( $alt1, $alt2) " , overload) {
11961200
@@ -1290,12 +1294,49 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12901294 (flip(tp1) relaxed_<:< flip(tp2)) || viewExists(tp1, tp2)
12911295 }
12921296
1297+ // # skipped implicit parameters in tp1 - # skipped implicit parameters in tp2
1298+ var implicitBalance : Int = 0
1299+
1300+ /** Widen the result type of synthetic implied methods from the implementation class to the
1301+ * type that's implemented. Example
1302+ *
1303+ * implied I[X] for T { ... }
1304+ *
1305+ * This desugars to
1306+ *
1307+ * class I[X] extends T { ... }
1308+ * implied def I[X]: I[X] = new I[X]
1309+ *
1310+ * To compare specificity we should compare with `T`, not with its implementation `I[X]`.
1311+ * No such widening is performed for implied aliases, which are not synthetic. E.g.
1312+ *
1313+ * implied J[X] for T = rhs
1314+ *
1315+ * already has the right result type `T`. Neither is widening performed for implied
1316+ * objects, since these are anyway taken to be more specific than methods
1317+ * (by condition 3a above).
1318+ */
1319+ def widenImplied (tp : Type , alt : TermRef ): Type = tp match {
1320+ case mt : MethodType if mt.isImplicitMethod =>
1321+ mt.derivedLambdaType(mt.paramNames, mt.paramInfos, widenImplied(mt.resultType, alt))
1322+ case pt : PolyType =>
1323+ pt.derivedLambdaType(pt.paramNames, pt.paramInfos, widenImplied(pt.resultType, alt))
1324+ case _ =>
1325+ if (alt.symbol.is(SyntheticImpliedMethod ))
1326+ tp.parents match {
1327+ case Nil => tp
1328+ case ps => ps.reduceLeft(AndType (_, _))
1329+ }
1330+ else tp
1331+ }
1332+
12931333 /** Drop any implicit parameter section */
1294- def stripImplicit (tp : Type ): Type = tp match {
1334+ def stripImplicit (tp : Type , weight : Int ): Type = tp match {
12951335 case mt : MethodType if mt.isImplicitMethod =>
1336+ implicitBalance += mt.paramInfos.length * weight
12961337 resultTypeApprox(mt)
12971338 case pt : PolyType =>
1298- pt.derivedLambdaType(pt.paramNames, pt.paramInfos, stripImplicit(pt.resultType))
1339+ pt.derivedLambdaType(pt.paramNames, pt.paramInfos, stripImplicit(pt.resultType, weight ))
12991340 case _ =>
13001341 tp
13011342 }
@@ -1304,21 +1345,32 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
13041345 val owner2 = if (alt2.symbol.exists) alt2.symbol.owner else NoSymbol
13051346 val ownerScore = compareOwner(owner1, owner2)
13061347
1307- val tp1 = stripImplicit(alt1.widen)
1308- val tp2 = stripImplicit(alt2.widen)
1309- def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2)
1310- def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
1311-
1312- overload.println(i " compare( $alt1, $alt2)? $tp1 $tp2 $ownerScore $winsType1 $winsType2" )
1313-
1314- if (ownerScore == 1 )
1315- if (winsType1 || ! winsType2) 1 else 0
1316- else if (ownerScore == - 1 )
1317- if (winsType2 || ! winsType1) - 1 else 0
1318- else if (winsType1)
1319- if (winsType2) 0 else 1
1320- else
1321- if (winsType2) - 1 else 0
1348+ def compareWithTypes (tp1 : Type , tp2 : Type ) = {
1349+ def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2)
1350+ def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
1351+
1352+ overload.println(i " compare( $alt1, $alt2)? $tp1 $tp2 $ownerScore $winsType1 $winsType2" )
1353+ if (ownerScore == 1 )
1354+ if (winsType1 || ! winsType2) 1 else 0
1355+ else if (ownerScore == - 1 )
1356+ if (winsType2 || ! winsType1) - 1 else 0
1357+ else if (winsType1)
1358+ if (winsType2) 0 else 1
1359+ else
1360+ if (winsType2) - 1 else 0
1361+ }
1362+
1363+ val fullType1 = widenImplied(alt1.widen, alt1)
1364+ val fullType2 = widenImplied(alt2.widen, alt2)
1365+ val strippedType1 = stripImplicit(fullType1, - 1 )
1366+ val strippedType2 = stripImplicit(fullType2, + 1 )
1367+
1368+ val result = compareWithTypes(strippedType1, strippedType2)
1369+ if (result != 0 ) result
1370+ else if (implicitBalance != 0 ) - implicitBalance.signum
1371+ else if ((strippedType1 `ne` fullType1) || (strippedType2 `ne` fullType2))
1372+ compareWithTypes(fullType1, fullType2)
1373+ else 0
13221374 }}
13231375
13241376 def narrowMostSpecific (alts : List [TermRef ])(implicit ctx : Context ): List [TermRef ] = track(" narrowMostSpecific" ) {
0 commit comments