Open hmf opened 3 years ago
Annotating the expected value, the inference appears to chose the first overload, ignoring whether it can find instances for Not
and then immediately reports that A = Int != typeof (1,2.0,"3")
and B = (Double, String, Char) != typeof '4'
.
Annotating the expected value, the inference appears to chose the first overload, ignoring whether it can find instances for Not
This is expected behavior: as per the specification, overloading resolution is done using only the first parameter list, once an overload is chosen, the others won't be revisited even if the following parameter lists don't match:
class A {
def foo(x: Int)(y: String): Unit = {}
def foo(x: Any)(y: Int): Unit = {}
foo(1)(1) // error in Scala 2 and 3 because the first overload is chosen.
}
@smarter This is strange. As noted above it works perfectly if I do not make the type explicit. Why should this change because of a "simple" type declaration? From a non-expert's point of view this seems inconsistent. I assumed type inference is "undirectional".
Additionally does this mean that using @targetName
or implicit dummy parameters should not work to disambiguate the overloads (@targetName
is a different case)? Short of having distinct names is there any way to circumvent this? I am hoping to support stuff like 1 && 2, 1 && (1,2,3), ... Not having overloading here is not practical.
Apologies for the questions but this "ruins" the planned API.
EDIT: I played around with the example above. If instead of the Any
I use a specific well defined type then it works - no need to disambiguate. I see you used that to simulate the inference required in my example.
TIA
I assumed type inference is "undirectional".
No, it's bidirectional. But I agree that adding a type annotation shouldn't break things, I don't know what's going on here but I'm guessing it's related to match types and could be minimized further.
No, it's bidirectional.
oops, that's what I wanted to say
Ok. I am going to see if I can avoid the overloading.
could be minimized further.
I will take another look to see if I can reduce it further. If you have any suggestions, let me know.
Thank you
One more data point that may help diagnose this. The following is an example that shows that if we explicitly set the implicit parameter, then compilation also succeeds.
@targetName("func4_right")
def func4[A,B<:Tuple](a : A, b : B)(implicit ev: Not[A<:<Tuple]): *:[A,B] = a *: b
@targetName("func4_left")
def func4[A<:Tuple,B](a : A, b : B)(implicit ev: Not[B<:<Tuple]): Tuple.Concat[A,Tuple1[B]] = a ++ Tuple1(b)
def testMinimalOverload(): Unit = {
val p1: (Int, Int, Int) = (1,2,3)
val p2: Int = 4
val c2 = func4(p1, p2)
val c4: (Int, Int, Int, Int) = func4(p1, p2)(summon[Not[p2.type <:<Tuple]]) // ok
val c6: (Int, Int, Int, Int) = func4(p1, p2) // fails
}
And this is an example that works, which seems to be inconsent with the Tuple example above:
@targetName("func5_right")
def func5[A,B<:Int](a : A, b : B)(implicit ev: Not[A<:<Int]): A = a
@targetName("func5_left")
def func5[A<:Int,B](a : A, b : B)(implicit ev: Not[B<:<Int]): B = b
def testMinimalOverload(): Unit = {
val p2: Int = 4
val c8:(String,Int) = func5(("s",1), p2)
val c10:(Int,String) = func5(p2, (1,"s"))
}
Minimized code
Motivation: the goal is to have a single overloaded method (lets call it
func3
) that can be used to concatenateTuple
s. The library user should also be able to concatenate an element to a tuple using the same method name. Examples include:func3(1, (2,3))
,func3((1,2), 3)
,func3(1, 2)
andfunc3((1,2), (3,3))
.The code below successfully does this:
Output
Note that the types seem to be correct, however when I attempt to explicitly type the returned value so:
I get the following errors:
Expectation
I expected to have no type errors. I have noticed that if I rename one of the functions and use the type it works. Note that
func31
is an exact copy of@targetName("func3_left")
but causes no issue. This is why I tried using@targetName
, but it makes no difference.While investigating this, someone tried this in the REPL and observed that the type was "unreduced". I was told that this is not the expected behavior. I am just adding this information here just in case it is of any use.
Tested with
3.0.0-M2