@@ -1046,17 +1046,25 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1046
1046
* - The nesting levels of A1 and A2 are the same, and A1's owner derives from A2's owner
1047
1047
* - A1's type is more specific than A2's type.
1048
1048
*/
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) {
1049
+ 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
1050
1051
1051
assert(alt1 ne alt2)
1052
1052
1053
- /** Is class or module class `sym1` derived from class or module class `sym2`?
1053
+ /** Compare owner inheritance level.
1054
+ * @param sym1 The first owner
1055
+ * @param sym2 The second owner
1056
+ * @return 1 if `sym1` properly derives from `sym2`
1057
+ * -1 if `sym2` properly derives from `sym1`
1058
+ * 0 otherwise
1054
1059
* Module classes also inherit the relationship from their companions.
1055
1060
*/
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)
1061
+ def compareOwner (sym1 : Symbol , sym2 : Symbol ): Int =
1062
+ if (sym1 == sym2) 0
1063
+ else if (sym1 isSubClass sym2) 1
1064
+ else if (sym2 isSubClass sym1) - 1
1065
+ else if (sym2 is Module ) compareOwner(sym1, sym2.companionClass)
1066
+ else if (sym1 is Module ) compareOwner(sym1.companionClass, sym2)
1067
+ else 0
1060
1068
1061
1069
/** Is alternative `alt1` with type `tp1` as specific as alternative
1062
1070
* `alt2` with type `tp2` ?
@@ -1165,55 +1173,59 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1165
1173
1166
1174
val owner1 = if (alt1.symbol.exists) alt1.symbol.owner else NoSymbol
1167
1175
val owner2 = if (alt2.symbol.exists) alt2.symbol.owner else NoSymbol
1176
+ val ownerScore =
1177
+ if (nesting1 > nesting2) 1
1178
+ else if (nesting1 < nesting2) - 1
1179
+ else compareOwner(owner1, owner2)
1180
+
1168
1181
val tp1 = stripImplicit(alt1.widen)
1169
1182
val tp2 = stripImplicit(alt2.widen)
1170
-
1171
- def winsOwner1 =
1172
- nesting1 > nesting2 || nesting1 == nesting2 && isDerived(owner1, owner2)
1173
1183
def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2)
1174
- def winsOwner2 =
1175
- nesting2 > nesting1 || nesting1 == nesting2 && isDerived(owner2, owner1)
1176
1184
def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
1177
1185
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
1186
+ overload.println(i " compare( $alt1, $alt2)? $tp1 $tp2 $ownerScore $winsType1 $winsType2" )
1187
+
1188
+ if (ownerScore == 1 )
1189
+ if (winsType1 || ! winsType2) 1 else 0
1190
+ else if (ownerScore == - 1 )
1191
+ if (winsType2 || ! winsType1) - 1 else 0
1192
+ else if (winsType1)
1193
+ if (winsType2) 0 else 1
1194
+ else
1195
+ if (winsType2) - 1 else 0
1195
1196
}}
1196
1197
1198
+ def isAsGood (alt1 : TermRef , alt2 : TermRef , nesting1 : Int = 0 , nesting2 : Int = 0 )(implicit ctx : Context ): Boolean =
1199
+ compare(alt1, alt2, nesting1, nesting2) >= 0
1200
+
1197
1201
def narrowMostSpecific (alts : List [TermRef ])(implicit ctx : Context ): List [TermRef ] = track(" narrowMostSpecific" ) {
1198
1202
alts match {
1199
1203
case Nil => alts
1200
1204
case _ :: Nil => alts
1205
+ case alt1 :: alt2 :: Nil =>
1206
+ compare(alt1, alt2) match {
1207
+ case 1 => alt1 :: Nil
1208
+ case - 1 => alt2 :: Nil
1209
+ case 0 => alts
1210
+ }
1201
1211
case alt :: alts1 =>
1202
- def winner ( bestSoFar : TermRef , alts : List [TermRef ]): TermRef = alts match {
1212
+ def survivors ( previous : List [ TermRef ] , alts : List [TermRef ]): List [ TermRef ] = alts match {
1203
1213
case alt :: alts1 =>
1204
- winner(if (isAsGood(alt, bestSoFar)) alt else bestSoFar, alts1)
1205
- case nil =>
1206
- bestSoFar
1214
+ compare(previous.head, alt) match {
1215
+ case 1 => survivors(previous, alts1)
1216
+ case - 1 => survivors(alt :: previous.tail, alts1)
1217
+ case 0 => survivors(alt :: previous, alts1)
1218
+ }
1219
+ case Nil => previous
1207
1220
}
1208
- val best = winner (alt, alts1)
1221
+ val best :: rest = survivors (alt :: Nil , alts1)
1209
1222
def asGood (alts : List [TermRef ]): List [TermRef ] = alts match {
1210
1223
case alt :: alts1 =>
1211
- if ((alt eq best) || ! isAsGood(alt, best)) asGood(alts1)
1212
- else alt :: asGood(alts1)
1224
+ if (compare(alt, best) < 0 ) asGood(alts1) else alt :: asGood(alts1)
1213
1225
case nil =>
1214
1226
Nil
1215
1227
}
1216
- best :: asGood(alts )
1228
+ best :: asGood(rest )
1217
1229
}
1218
1230
}
1219
1231
0 commit comments