JDK-8028800 : Lambda Spec: Support capture when a nested invocation returns an inference variable
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2013-11-21
  • Updated: 2014-05-30
  • Resolved: 2013-12-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
abstract class A2<T>{
   abstract <S> S pick(S x, S y);
   abstract <S1> void m(A2<S1> a)

   void test(A2<Integer> y, A2<Long> x){
        m(pick(x, y));
   }
}

Even though the return type of 'pick' is not wildcard-parameterized, for certain instantiations it can be.  The greedy inference strategy of JLS 7 would then perform capture on the instantiated return type before performing inference for 'm'.  The Lambda Spec instead skips capture (see 18.5.2) and produces an error.
Comments
I've settled on a heuristic that attempts to detect when capture of the returned inference variable will be necessary. Updated text for 18.5.2: If the invocation is a poly expression, let R be the return type of m, and let T be the invocation's target type. Then ***one of the following cases*** apply, producing a new bound set, B3: - If R �� is a parameterized type, G<A1, ..., An>, and one of A1, ..., An is a wildcard, then, for fresh inference variables ��1, ..., ��n, the constraint formula ���G<��1, ..., ��n> ��� T��� is reduced and incorporated, along with the bound G<��1, ..., ��n> = capture(G<A1, ..., An>), with B2. - ***If R �� is an inference variable ��, and one of the following conditions are true, then then �� is resolved in B2, and where the resulting instantiation of �� is U, the constraint formula ���U ��� T��� is reduced and incorporated.*** -- ***T is a reference type, but is not a wildcard-parameterized type, and either i) B2 contains a bound of one of the forms �� = S or S <: ��, where S is a wildcard-parameterized type, or ii) B2 contains two bounds of the forms S1 <: �� and S2 <: ��, where S1 and S2 are have supertypes that are two different parameterizations of the same generic class or interface.*** -- ***T is a parameterization of a generic class or interface, G, and B2 contains a bound of one of the forms �� = S or S <: ��, where there exists no type of the form G<...> that is a supertype of S, but the raw type G is a supertype of S.*** -- ***T is a primitive type, and one of the primitive wrapper classes mentioned in 5.1.7 is an instantiation, upper bound, or lower bound for �� in B2.*** - Otherwise, the constraint formula ���R �� ��� T��� is reduced and incorporated with B2.
18-12-2013

More precisely, the upper bounds of capture(L) include all the upper bounds of L. (The reverse is not true, which is the root cause of this problem.)
18-12-2013

I don't think we should take upper bounds into account in making a decision to greedily resolve the return variable. Some examples of why this would cause problems: <L extends List<?>> L makeList(); ArrayList<?> l = makeList(); void m1(ArrayList<?> l); m1(makeList()); <T> void m2(ArrayList<T> l); m2(makeList()); <T> T id(T arg); m2(id(makeList())); All of these should be solvable currently, but adding a greedy resolution of L would break them. Intuition: capture(L) has the same upper bounds as L; but capture(L) may have different lower bounds or eq bounds.
18-12-2013

Should also consider the case in which the return type is an inference variable and may be required to perform unchecked conversion.
05-12-2013