JDK-8054721 : 18.4: Clean up resolution of capture ivars
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 8
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2014-08-08
  • Updated: 2018-06-28
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.
Other
tbd_majorUnresolved
Related Reports
Relates :  
Relates :  
Relates :  
Description
As specified, resolution does some incorrect things when it attempts to resolve capture ivars (that is, ivars that are introduced by a "capture bound").

1) Capture must not produce a variable with bounds that come from a downstream assignment, the way resolution does it (e.g., given 'C<z1> = capture(C<?>)' and 'C<z1> --> C<? extends String>', resolving 'z1 = CAP extends String').  The only valid bounds for the capture variable are the wildcard bound and declaration-site bound.

2) There can be dependency cycles that mix capture ivars and normal ivars (e.g., given 'C<z1> = capture(C<? extends t>)', with some ivar u appearing in the target type, z1 -> t -> u -> z1).  We can't just resolve them all at once; we must break the cycle somehow.

3) In the case of a cycle, where there is an unresolved non-wildcard capture ivar (e.g., z2 in the bound 'C<z1,z2> = capture(C<?,T>)'), it's incorrect to generate a new capture variable for z2.  We must resolve it to T (whatever type that represents).

The picture that emerges is that we ought to be doing something that looks like: i) resolve all ivars in the to-be-captured part of the capture bound (and maybe some of their dependencies, breaking the cycle somewhere further on?); ii) perform a _real_ capture to get valid instantiations for the capture ivars; iii) continue with resolution.

An example of a cycle:
<T> C<?,T> makeC();
<U> void take(C<? extends u, ? extends u> arg);
take(make());
// C<z1,z2> = capture(C<?,t>)
// z1 -> t -> u -> z1

Comments
While fixing this section: the phrase "has proper upper bounds U1, ..., Uk" (used repeatedly) could be read incorrectly, such as thinking it means all upper bounds must be proper, or that there's a nondeterministic choice about which subset of proper bounds to select. Something like "where the proper upper bounds of ai are U1, ..., Uk, ..." would be more clear.
20-03-2017

For an even more trivial cycle, note that incorporation will take (for arbitrary T) C<x1,x2> = capture(C<?,T>) And infer x2 = T And now, if T includes ivars, we have a dependency cycle: per the equality bound, all ivars in T depend on x2; per the capture bound, x2 depends on all ivars in T.
24-10-2014

Note that, in the case of (1), _after_ we've produced a capture variable as an instantiation for the capture ivar, then we need to go back and ensure that the generated capture var is within the ivar's bounds. There's nothing to do in the spec (incorporation already handles it), but it might be overlooked in an implementation.
12-08-2014