Skip to content

Commit e8cc49b

Browse files
committed
Fix varargs overload resolution with wildcard types
Fixes #24072 When comparing overloaded methods where one is non-varargs with wildcard types (e.g., `Class[? <: T]`) and another is varargs, the non-varargs method should be preferred. Previously, the compiler failed to distinguish these methods , and results in an ambiguity error. ```scala def blub[T](a: Class[? <: T]): Unit // m1 def blub[T](a: Class[T], ints: Int*): Unit // m2 blub(classOf[Object]) // m1 should be picked, but fails to resolve ```` The problem is `compare(m1, m2)` returned 0 because: - (1). `m2` (varargs) is correctly considered "not as good" as `m1`. - (2). `m1` (non-varargs) was also considered "not as good" as `m2`. (but `m1` should be as good as `m2`! because `Class[Concrete]` can be applied to both m1 and m2). The (2) occurred because `Class[? <: T]` is not a subtype of `Class[T]` (due to invariance). Consequently, `isApplicableMethodRef(m2, Class[? <: T])` returned `false` because `isCompatible(Class[? <: T], Class[T])` returned `false` during the applicability check against the method. This commit adds special handling in `TestApplication.argOK` to check if wildcard upper bounds are compatible with their formal types during overload resolution, in addition to `isCompatible`.
1 parent c9309e7 commit e8cc49b

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,27 @@ trait Applications extends Compatibility {
883883
case SAMType(samMeth, samParent) => argtpe <:< samMeth.toFunctionType(isJava = samParent.classSymbol.is(JavaDefined))
884884
case _ => false
885885

886-
isCompatible(argtpe, formal)
886+
// For overload resolution, allow wildcard upper bounds to match their bound type.
887+
// For example, given:
888+
// def blub[T](a: Class[? <: T]): String = "a"
889+
// def blub[T](a: Class[T], ints: Int*): String = "b"
890+
// blub(classOf[Object])
891+
//
892+
// The non-varargs overload should be preferred. While Class[? <: T] is not a
893+
// subtype of Class[T] (Class is invariant), for overload resolution we consider
894+
// Class[? <: T] "applicable" where Class[T] is expected by checking if the
895+
// wildcard's upper bound is a subtype of the formal type parameter.
896+
def wildcardArgOK =
897+
(argtpe, formal) match
898+
case (AppliedType(tycon1, args1), AppliedType(tycon2, args2))
899+
if tycon1 =:= tycon2 && args1.length == args2.length =>
900+
args1.lazyZip(args2).forall {
901+
case (TypeBounds(_, hi), formal) => hi relaxed_<:< formal
902+
case (arg, formal) => arg =:= formal
903+
}
904+
case _ => false
905+
906+
isCompatible(argtpe, formal) || wildcardArgOK
887907
// Only allow SAM-conversion to PartialFunction if implicit conversions
888908
// are enabled. This is necessary to avoid ambiguity between an overload
889909
// taking a PartialFunction and one taking a Function1 because

tests/run/overload_repeated/B_2.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ object Test {
1313
def bar4[T](x: T): Int = 1
1414
def bar4[T](x: T, xs: T*): Int = 2
1515

16+
// https://github.com/scala/scala3/issues/24072
17+
def bar5[T](a: Class[? <: T]): Int = 1
18+
def bar5[T](a: Class[T], ints: Int*): Int = 2
19+
20+
def bar6[T](a: Int): Int = 1
21+
def bar6[T](a: Class[T], ints: Int*): Int = 2
22+
1623
def main(args: Array[String]): Unit = {
1724
// In Java, varargs are always less specific than non-varargs (see
1825
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2),
@@ -28,5 +35,7 @@ object Test {
2835
assert(bar2("") == 1) // same in Scala 2
2936
assert(bar3("") == 1) // same in Scala 2
3037
assert(bar4("") == 1) // same in Scala 2
38+
assert(bar5(classOf[Object]) == 1) // same in Scala2
39+
assert(bar6(classOf[Object]) == 2) // same in Scala2
3140
}
3241
}

0 commit comments

Comments
 (0)