JDK-8054941 : 4.5: Possibly modify well-formedness restriction for wildcards?
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 8,9
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2014-08-12
  • Updated: 2021-11-04
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
JLS 4.5: "A parameterized type C<T1,...,Tn> is well-formed if ... When subjected to capture conversion (ยง5.1.10) resulting in the type C<X1,...,Xn>, each type argument Xi is a subtype of S[F1:=X1,...,Fn:=Xn] for each bound type S in Bi.  It is a compile-time error if a parameterized type is not well-formed."

javac does not enforce the restriction.  Instead, it checks the wildcard bound directly against the declaration-site bound (see checkExtends in Check.java).  For upper bounds, this involves a castability check.  For lower bounds, this involves a novel check called 'notSoftSubtypes'.

Questions:

- There are types that pass the javac check but not the JLS capture check.  If we allow these types to be considered valid, what happens when they actually get captured somewhere downstream?  Are we violating invariants of the type checker?

- Are there any types that pass the JLS capture check but not the javac check?  If so, are there good reasons to prohibit them?

This bug may be resolved by updating JLS, producing a new bug requiring javac to conform to JLS, or some of both.
Comments
Here's an example of what can go wrong if incompatible upper/lower bounds are allowed to exist on capture variables. The program attempts to treat an Integer as if it were a String via an indirection through a capture variable (CAP extends String super T, where T is instantiated to Integer). It compiles in JDK 8 and JDK 9, but fails at runtime with a ClassCastException. class CaptureTransitivity { static interface I<S> {} static interface IString<S extends String> extends I<S> {} static <X> X id(I<X> token, X val) { return val; } static <T> String makeString(T arg) { IString<? super T> token = null; return id(token, arg).intern(); } public static void main(String... args) { String s = CaptureTransitivity.<Integer>makeString(23); } } (Based on a test case provided by Ross Tate)
09-03-2016

The priority has been raised to P2, because it's a conformance, TCK-red issue. Following tests fail because of this issue: lang/INFR/infr065/infr06502m004/infr06502m004.html lang/INFR/infr065/infr06502m104/infr06502m104.html lang/INFR/infr065/infr06502m105/infr06502m105.html lang/INFR/infr065/infr06502m005/infr06502m005.html lang/INFR/infr065/infr06502m014/infr06502m014.html lang/INFR/infr065/infr06502m114/infr06502m114.html lang/INFR/infr065/infr06502m025/infr06502m025.html lang/INFR/infr065/infr06502m125/infr06502m125.html lang/INFR/infr065/infr06502m115/infr06502m115.html lang/INFR/infr065/infr06502m015/infr06502m015.html lang/INFR/infr065/infr06502m023/infr06502m023.html lang/INFR/infr065/infr06502m123/infr06502m123.html
07-10-2014

The lower bound case is wrong in both JLS and javac. Example: class C<T extends Number> {} JLS has no restrictions, which is clearly incorrect. We can't have C<? super String>. javac's "soft subtype" check attempts to interpret type variables existentially rather than universally (e.g., "is T a subtype of Foo for some instantiation of T?") So, in the scope of an unbounded type variable X, C<? super X> is allowed, which is no good, either. The key constraint is that capture variables introduce new subtyping relationships -- CAP extends Foo super Bar says that Bar <: CAP and CAP <: Foo. We can't allow capture variables to arbitrarily introduce new subtyping relationships (via transitivity, Bar <: Foo; above, String <: Number and X <: Number). So the subtyping relationship between the lower and upper bound needs to exist already.
30-08-2014