Inference error
Dan Smith
daniel.smith at oracle.com
Wed Dec 12 12:29:03 PST 2012
On Dec 12, 2012, at 11:05 AM, Sam Pullara <spullara at gmail.com> wrote:
> The code itself might be a bad idea, just experimenting, but:
>
> https://github.com/spullara/java-future-jdk8/commit/2fa4321a450ca56e3a0958214c7cdcd9bca1ad84
>
> The third test fails to compile with this error:
>
> java: no suitable method found for curry(map::put,java.lang.String)
> method spullara.util.Currier.<T,U,V>curry(spullara.util.Currier.C2<T,U,V>,U) is not applicable
> (Cannot instantiate inference variables U,V because of an inference loop)
Here's what inference in this case looks like.
interface C2<T,U,V> { T invoke(U u, V v); }
interface C1<T,U> { T invoke(U u); }
<T, U, V> C1<T, V> curry(C2<T, U, V> get, U u);
Map<String, Integer> map = new HashMap<>();
C1<Integer, Integer> c1 = curry(map::put, "test");
For applicability testing, there are two inference constraints:
map::put -> C2<alpha, beta, gamma>
"test" -> beta
---
The currently-implemented strategy infers
beta :> String
and then resolves
beta = String
But we know nothing about gamma at this point, and the first constraint can't be resolved until we have concrete parameter types (instantiations for beta and gamma) to work with. So inference is stuck, and an error occurs.
---
What we plan to implement (this is alluded to in the 0.6.0 spec, but not explained in the inference section yet; I'm going to send a high-level summary soon) is this:
"test" -> beta
reduces to
beta :> String
while
map::put -> C2<alpha, beta, gamma>
is "stuck" and set aside for later. This 'curry' method is considered "provisionally applicable".
_After_ overload resolution is done, we can come back and look at a new constraint:
C1<alpha,gamma> <: C1<Integer,Integer>
giving us
alpha = Integer
gamma = Integer
And then we can resolve beta=String and gamma=Integer, updating the 'map::put' constraint to
map::put -> C2<alpha, String, Integer>
Which works out.
---
Except that your example makes interesting use of overloading:
<T, U> C0<T> curry(C1<T, U> get, U u); // don't want this
<T, U, V> C1<T, V> curry(C2<T, U, V> get, U u); // want this
With a naive approach, both of these would be provisionally applicable, since the method reference constraint would be "stuck" in both cases, and so there would be an ambiguity. We're looking at three different ideas that would avoid that problem:
1) Enhance "potentially applicable" for method references, so that the first candidate is dismissed because there's no unary 'put' method.
2) Since there is only one possible interpretation of 'map::put', handle that method reference bottom-up rather than the usual top-down approach.
3) Eagerly resolve U before overload resolution, since it doesn't show up in the return type. This would "unstuck" the constraint targeting C1 in the first candidate, which would be enough to demonstrate that the first candidate is inapplicable.
Some or all of these may make the cut. We've been focusing our efforts on lambda expressions, not method references, as we get the framework in place, and then these things can be tweaked.
—Dan
More information about the lambda-spec-experts
mailing list