@@ -1031,33 +1031,43 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1031
1031
tp.member(nme.apply).hasAltWith(d => p(TermRef (tp, nme.apply, d)))
1032
1032
}
1033
1033
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.
1036
1051
*
1037
1052
* @param alt1, alt2 Non-overloaded references indicating the two choices
1038
1053
* @param level1, level2 If alternatives come from a comparison of two contextual
1039
1054
* implicit candidates, the nesting levels of the candidates.
1040
1055
* 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
1041
1059
*
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:
1044
1062
*
1045
1063
* - A1 is nested more deeply than A2
1046
1064
* - The nesting levels of A1 and A2 are the same, and A1's owner derives from A2's owner
1047
1065
* - A1's type is more specific than A2's type.
1048
1066
*/
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) {
1050
1068
1051
1069
assert(alt1 ne alt2)
1052
1070
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
-
1061
1071
/** Is alternative `alt1` with type `tp1` as specific as alternative
1062
1072
* `alt2` with type `tp2` ?
1063
1073
*
@@ -1165,55 +1175,56 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1165
1175
1166
1176
val owner1 = if (alt1.symbol.exists) alt1.symbol.owner else NoSymbol
1167
1177
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
+
1168
1183
val tp1 = stripImplicit(alt1.widen)
1169
1184
val tp2 = stripImplicit(alt2.widen)
1170
-
1171
- def winsOwner1 =
1172
- nesting1 > nesting2 || nesting1 == nesting2 && isDerived(owner1, owner2)
1173
1185
def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2)
1174
- def winsOwner2 =
1175
- nesting2 > nesting1 || nesting1 == nesting2 && isDerived(owner2, owner1)
1176
1186
def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
1177
1187
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
1195
1198
}}
1196
1199
1197
1200
def narrowMostSpecific (alts : List [TermRef ])(implicit ctx : Context ): List [TermRef ] = track(" narrowMostSpecific" ) {
1198
1201
alts match {
1199
1202
case Nil => alts
1200
1203
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
+ }
1201
1210
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 {
1203
1212
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
1207
1219
}
1208
- val best = winner (alt, alts1)
1220
+ val best :: rest = survivors (alt :: Nil , alts1)
1209
1221
def asGood (alts : List [TermRef ]): List [TermRef ] = alts match {
1210
1222
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)
1213
1224
case nil =>
1214
1225
Nil
1215
1226
}
1216
- best :: asGood(alts )
1227
+ best :: asGood(rest )
1217
1228
}
1218
1229
}
1219
1230
0 commit comments