bug
bug copied to clipboard
Fail to resolve overloaded method when type inference is required
Here is a snippet to illustrate the problem:
class Foo[A] {
def compose(a: Foo[A]): Foo[A] = new Foo[A]
def compose(b: Bar[A]): Bar[A] = new Bar[A]
// non overloaded method
def composeBar(b: Bar[A]): Bar[A] = new Bar[A]
}
class Bar[A] {
def compose(a: Foo[A]): Bar[A] = new Bar[A]
def compose(b: Bar[A]): Bar[A] = new Bar[A]
}
object Test {
val fooS = new Foo[String]
val barS = new Bar[String]
def barA[A] = new Bar[A]
// foos and bars compose together
fooS compose fooS
barS compose barS
fooS compose barS
barS compose fooS
// here it fails with the following error
// error: overloaded method value compose with alternatives:
// (b: Bar[String])Bar[String] <and>
// (a: Foo[String])Foo[String]
// cannot be applied to (Bar[Nothing])
fooS compose barA
// but it works if you add a type annotation or a non overloaded method
fooS compose barA[String]
fooS composeBar barA
}
This issue is particularly important for monocle because all optics (Iso, Lens, Prism, ...) compose together which means we need to define 8 different compose methods instead of a single method overloaded 8 times.
Imported From: https://issues.scala-lang.org/browse/SI-10046?orig=1 Reporter: Julien Truffaut (julien-truffaut) Affected Versions: 2.11.8, 2.12.0
Jean-Baptiste Giraudeau (jbgi) said: In case this could be an incentive to fix this issue, the test case compile just fine in java:
class Test {
static class Foo<A> {
Foo<A> compose(Foo<A> a) {
return new Foo<>();
}
Bar<A> compose(Bar<A> b) {
return new Bar<>();
}
}
static class Bar<A> {
Bar<A> compose(Foo<A> a) {
return new Bar<>();
}
Bar<A> compose(Bar<A> b) {
return new Bar<>();
}
}
static <A> Bar<A> barA() {
return new Bar<>();
}
public static void main(String[] args) {
Foo<String> fooS = new Foo<>();
// Compile just fine:
fooS.compose(barA());
}
}
This kind of limitations means that the scala user-experience (of java 8 libraries in particular) can be inferior to the java user-experience. Resolving regressions vs Java 8 should, imo, be given major priority (at least from a marketing pov ;-)).
@som-snytt said: Maybe the missing param type exception for function literals can be extended to this case, so that a single missing type param is inferred from the type args of the candidate expected types.
Problem statement:
scala> class D[A] ; class C[A] { def f(x: C[A]): C[A] = new C[A] ; def f(x: D[A]): D[A] = new D[A] }
defined class D
defined class C
scala> def d[A]: D[A] = new D[A]
d: [A]=> D[A]
scala> new C[String]().f(d)
<console>:14: error: overloaded method value f with alternatives:
(x: D[String])D[String] <and>
(x: C[String])C[String]
cannot be applied to (D[Nothing])
new C[String]().f(d)
^
This is not a workaround.
scala> class D[A] ; class C[A] { def f(x: A => C[A]): C[A] = new C[A] ; def f(x: A => D[A]): D[A] = new D[A] }
defined class D
defined class C
scala> def d[A]: D[A] = new D[A]
d: [A]=> D[A]
scala> new C[String]().f(x => d)
<console>:14: error: overloaded method value f with alternatives:
(x: String => D[String])D[String] <and>
(x: String => C[String])C[String]
cannot be applied to (String => D[Nothing])
new C[String]().f(x => d)
^
scala> new C[String]().f(x => d[x.type])
<console>:14: error: overloaded method value f with alternatives:
(x: String => D[String])D[String] <and>
(x: String => C[String])C[String]
cannot be applied to (String => D[_ <: String with Singleton])
new C[String]().f(x => d[x.type])
^
Julien Truffaut (julien-truffaut) said: At the moment, I can see one way to fix the issue but I am very unfamiliar with the internal API. Here is what I found so far:
In Typers -> preSelectOverloaded, we could try to remove overloaded candidates that cannot match, e.g. there is no way that a Bar[A] can be a Foo[String]. If we can do that then the issue would be resolved because there would be only one alternative. However, it seems that the Tree barA hasn't been type checked in preSelectOverloaded, so I don't know how to access type information.
@som-snytt said: I think it's a spec issue and not just a matter of implementation. It takes two cuts at which alternatives apply, first by shape and second after type checking the args (without an expected type).
Julien Truffaut (julien-truffaut) said: Would you mind to point me at the part of the spec you mentioned?
@som-snytt said: http://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#overloading-resolution
That is 6.26.3. (The table of contents is temporarily pointing to a phantom 2.13 version.)
#10542 seems similar?