@@ -1031,33 +1031,43 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
10311031 tp.member(nme.apply).hasAltWith(d => p(TermRef (tp, nme.apply, d)))
10321032 }
10331033
1034- /** In a set of overloaded applicable alternatives, is `alt1` at least as good as
1035- * `alt2`? Also used for implicits disambiguation.
1034+ /** Compare owner inheritance level.
1035+ * @param sym1 The first owner
1036+ * @param sym2 The second owner
1037+ * @return 1 if `sym1` properly derives from `sym2`
1038+ * -1 if `sym2` properly derives from `sym1`
1039+ * 0 otherwise
1040+ * Module classes also inherit the relationship from their companions.
1041+ */
1042+ def compareOwner (sym1 : Symbol , sym2 : Symbol )(implicit ctx : Context ): Int =
1043+ if (sym1 == sym2) 0
1044+ else if (sym1 isSubClass sym2) 1
1045+ else if (sym2 isSubClass sym1) - 1
1046+ else if (sym2 is Module ) compareOwner(sym1, sym2.companionClass)
1047+ else if (sym1 is Module ) compareOwner(sym1.companionClass, sym2)
1048+ else 0
1049+
1050+ /** Compare to alternatives of an overloaded call or an implicit search.
10361051 *
10371052 * @param alt1, alt2 Non-overloaded references indicating the two choices
10381053 * @param level1, level2 If alternatives come from a comparison of two contextual
10391054 * implicit candidates, the nesting levels of the candidates.
10401055 * In all other cases the nesting levels are both 0.
1056+ * @return 1 if 1st alternative is preferred over 2nd
1057+ * -1 if 2nd alternative is preferred over 1st
1058+ * 0 if neither alternative is preferred over the other
10411059 *
1042- * An alternative A1 is "as good as" an alternative A2 if it wins or draws in a tournament
1043- * that awards one point for each of the following
1060+ * An alternative A1 is preferred over an alternative A2 if it wins in a tournament
1061+ * that awards one point for each of the following:
10441062 *
10451063 * - A1 is nested more deeply than A2
10461064 * - The nesting levels of A1 and A2 are the same, and A1's owner derives from A2's owner
10471065 * - A1's type is more specific than A2's type.
10481066 */
1049- def isAsGood (alt1 : TermRef , alt2 : TermRef , nesting1 : Int = 0 , nesting2 : Int = 0 )(implicit ctx : Context ): Boolean = track(" isAsGood " ) { trace(i " isAsGood ( $alt1, $alt2) " , overload) {
1067+ def compare (alt1 : TermRef , alt2 : TermRef , nesting1 : Int = 0 , nesting2 : Int = 0 )(implicit ctx : Context ): Int = track(" compare " ) { trace(i " compare ( $alt1, $alt2) " , overload) {
10501068
10511069 assert(alt1 ne alt2)
10521070
1053- /** Is class or module class `sym1` derived from class or module class `sym2`?
1054- * Module classes also inherit the relationship from their companions.
1055- */
1056- def isDerived (sym1 : Symbol , sym2 : Symbol ): Boolean =
1057- if (sym1 isSubClass sym2) true
1058- else if (sym2 is Module ) isDerived(sym1, sym2.companionClass)
1059- else (sym1 is Module ) && isDerived(sym1.companionClass, sym2)
1060-
10611071 /** Is alternative `alt1` with type `tp1` as specific as alternative
10621072 * `alt2` with type `tp2` ?
10631073 *
@@ -1165,55 +1175,56 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
11651175
11661176 val owner1 = if (alt1.symbol.exists) alt1.symbol.owner else NoSymbol
11671177 val owner2 = if (alt2.symbol.exists) alt2.symbol.owner else NoSymbol
1178+ val ownerScore =
1179+ if (nesting1 > nesting2) 1
1180+ else if (nesting1 < nesting2) - 1
1181+ else compareOwner(owner1, owner2)
1182+
11681183 val tp1 = stripImplicit(alt1.widen)
11691184 val tp2 = stripImplicit(alt2.widen)
1170-
1171- def winsOwner1 =
1172- nesting1 > nesting2 || nesting1 == nesting2 && isDerived(owner1, owner2)
11731185 def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2)
1174- def winsOwner2 =
1175- nesting2 > nesting1 || nesting1 == nesting2 && isDerived(owner2, owner1)
11761186 def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
11771187
1178- overload.println(i " isAsGood( $alt1, $alt2)? $tp1 $tp2 $winsOwner1 $winsType1 $winsOwner2 $winsType2" )
1179-
1180- // Assume the following probabilities:
1181- //
1182- // P(winsOwnerX) = 2/3
1183- // P(winsTypeX) = 1/3
1184- //
1185- // Then the call probabilities of the 4 basic operations are as follows:
1186- //
1187- // winsOwner1: 1/1
1188- // winsOwner2: 1/1
1189- // winsType1 : 7/9
1190- // winsType2 : 4/9
1191-
1192- if (winsOwner1) /* 6/9 */ ! winsOwner2 || /* 4/9 */ winsType1 || /* 8/27 */ ! winsType2
1193- else if (winsOwner2) /* 2/9 */ winsType1 && /* 2/27 */ ! winsType2
1194- else /* 1/9 */ winsType1 || /* 2/27 */ ! winsType2
1188+ overload.println(i " compare( $alt1, $alt2)? $tp1 $tp2 $ownerScore $winsType1 $winsType2" )
1189+
1190+ if (ownerScore == 1 )
1191+ if (winsType1 || ! winsType2) 1 else 0
1192+ else if (ownerScore == - 1 )
1193+ if (winsType2 || ! winsType1) - 1 else 0
1194+ else if (winsType1)
1195+ if (winsType2) 0 else 1
1196+ else
1197+ if (winsType2) - 1 else 0
11951198 }}
11961199
11971200 def narrowMostSpecific (alts : List [TermRef ])(implicit ctx : Context ): List [TermRef ] = track(" narrowMostSpecific" ) {
11981201 alts match {
11991202 case Nil => alts
12001203 case _ :: Nil => alts
1204+ case alt1 :: alt2 :: Nil =>
1205+ compare(alt1, alt2) match {
1206+ case 1 => alt1 :: Nil
1207+ case - 1 => alt2 :: Nil
1208+ case 0 => alts
1209+ }
12011210 case alt :: alts1 =>
1202- def winner ( bestSoFar : TermRef , alts : List [TermRef ]): TermRef = alts match {
1211+ def survivors ( previous : List [ TermRef ] , alts : List [TermRef ]): List [ TermRef ] = alts match {
12031212 case alt :: alts1 =>
1204- winner(if (isAsGood(alt, bestSoFar)) alt else bestSoFar, alts1)
1205- case nil =>
1206- bestSoFar
1213+ compare(previous.head, alt) match {
1214+ case 1 => survivors(previous, alts1)
1215+ case - 1 => survivors(alt :: previous.tail, alts1)
1216+ case 0 => survivors(alt :: previous, alts1)
1217+ }
1218+ case Nil => previous
12071219 }
1208- val best = winner (alt, alts1)
1220+ val best :: rest = survivors (alt :: Nil , alts1)
12091221 def asGood (alts : List [TermRef ]): List [TermRef ] = alts match {
12101222 case alt :: alts1 =>
1211- if ((alt eq best) || ! isAsGood(alt, best)) asGood(alts1)
1212- else alt :: asGood(alts1)
1223+ if (compare(alt, best) < 0 ) asGood(alts1) else alt :: asGood(alts1)
12131224 case nil =>
12141225 Nil
12151226 }
1216- best :: asGood(alts )
1227+ best :: asGood(rest )
12171228 }
12181229 }
12191230
0 commit comments