Skip to content

Commit ec0eb3f

Browse files
committed
Don't flip contravariant type arguments for overloading resolution
Flipping contravariant type arguments was needed for implicit search where it will be replaced by a more general scheme. But it makes no sense for overloading resolution. For overloading resolution, we want to pick the most specific alternative, analogous to us picking the most specific instantiation when we force a fully defined type.
1 parent 7ecdee6 commit ec0eb3f

File tree

5 files changed

+22
-7
lines changed

5 files changed

+22
-7
lines changed

compiler/src/dotty/tools/dotc/core/Mode.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ object Mode {
4141
val Pattern: Mode = newMode(0, "Pattern")
4242
val Type: Mode = newMode(1, "Type")
4343

44+
val PatternOrTypeBits: Mode = Pattern | Type
45+
4446
val ImplicitsEnabled: Mode = newMode(2, "ImplicitsEnabled")
4547
val InferringReturnType: Mode = newMode(3, "InferringReturnType")
4648

@@ -120,8 +122,6 @@ object Mode {
120122
/** Read original positions when unpickling from TASTY */
121123
val ReadPositions: Mode = newMode(17, "ReadPositions")
122124

123-
val PatternOrTypeBits: Mode = Pattern | Type
124-
125125
/** We are elaborating the fully qualified name of a package clause.
126126
* In this case, identifiers should never be imported.
127127
*/

compiler/src/dotty/tools/dotc/typer/Applications.scala

+4-2
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,7 @@ trait Applications extends Compatibility {
16371637
* an alternative that takes more implicit parameters wins over one
16381638
* that takes fewer.
16391639
*/
1640-
def compare(alt1: TermRef, alt2: TermRef)(using Context): Int = trace(i"compare($alt1, $alt2)", overload) {
1640+
def compare(alt1: TermRef, alt2: TermRef, preferGeneral: Boolean = false)(using Context): Int = trace(i"compare($alt1, $alt2)", overload) {
16411641
record("resolveOverloaded.compare")
16421642

16431643
/** Is alternative `alt1` with type `tp1` as specific as alternative
@@ -1722,7 +1722,9 @@ trait Applications extends Compatibility {
17221722
* the intersection of its parent classes instead.
17231723
*/
17241724
def isAsSpecificValueType(tp1: Type, tp2: Type)(using Context) =
1725-
if (ctx.mode.is(Mode.OldOverloadingResolution))
1725+
if !preferGeneral || ctx.mode.is(Mode.OldOverloadingResolution) then
1726+
// Normal specificity test for overloading resultion (where `preferGeneral` is false)
1727+
// and in mode Scala3-migration when we compare with the old Scala 2 rules.
17261728
isCompatible(tp1, tp2)
17271729
else {
17281730
val flip = new TypeMap {

compiler/src/dotty/tools/dotc/typer/Implicits.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1291,7 +1291,7 @@ trait Implicits:
12911291
def compareAlternatives(alt1: RefAndLevel, alt2: RefAndLevel): Int =
12921292
if alt1.ref eq alt2.ref then 0
12931293
else if alt1.level != alt2.level then alt1.level - alt2.level
1294-
else explore(compare(alt1.ref, alt2.ref))(using searchContext())
1294+
else explore(compare(alt1.ref, alt2.ref, preferGeneral = true))(using searchContext())
12951295

12961296
/** If `alt1` is also a search success, try to disambiguate as follows:
12971297
* - If alt2 is preferred over alt1, pick alt2, otherwise return an
@@ -1327,7 +1327,7 @@ trait Implicits:
13271327
ctx.typerState
13281328

13291329
diff = inContext(searchContext().withTyperState(comparisonState)) {
1330-
compare(ref1, ref2)
1330+
compare(ref1, ref2, preferGeneral = true)
13311331
}
13321332
case _ =>
13331333
if diff < 0 then alt2

compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ trait ImportSuggestions:
296296
var i = 0
297297
var diff = 0
298298
while i < filled && diff == 0 do
299-
diff = compare(ref, top(i))(using noImplicitsCtx)
299+
diff = compare(ref, top(i), preferGeneral = true)(using noImplicitsCtx)
300300
if diff > 0 then
301301
rest += top(i)
302302
top(i) = ref
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class A
2+
class B
3+
class C[-T]
4+
5+
def foo(using A): C[Any] = ???
6+
def foo(using B): C[Int] = ???
7+
8+
9+
@main def Test =
10+
given A = A()
11+
given B = B()
12+
val x = foo
13+
val _: C[Any] = x

0 commit comments

Comments
 (0)