JDK-8002099 : Add support for intersection types in cast expression
  • Type: Sub-task
  • Component: tools
  • Sub-Component: javac
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2012-11-01
  • Updated: 2017-05-17
  • Resolved: 2012-11-30
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
8 b68Fixed
Related Reports
Relates :  
Relates :  
Description
Allow cast where target type is an intersection type - example:

(C & I1 & I2)foo

As a side-effect, this enables an handy opt-in mechanism for denoting serializable lambdas:

(Serializable & Predicate<String>)s->false;


Comments
Biggest part of this task is to surface syntax for allowing intersection types in cast expression - an already convoluted area of the javac parser featuring multiple ambiguities (parenthesized expression vs. cast vs. implicit/explicit lambdas). Type-checking support for intersection type support in cast expression is mostly already there since JDK 5; in particular there are three interesting cases (assume S is the source type and T is the target type of a cast): 1) S is an intersection type, T is a reference type 2) T is an intersection type, S is a reference type 3) both S and T are intersection types. One might think that, given the spec only comes up with intersection types in capture conversion and inference, the only case in which javac has to worry about intersection types in cast is (1). However, javac handles (2) and (3) too (see below): (2) is allowed because of the loose generic well-formedness check that is implemented in javac - if you have a type declaration like: class Foo<X extends B> and a parameterized type like: Foo<? extends T> javac will say that the above parameterized type is well-formed iff T is castable to B. Now, if B is an intersection type, it's clear why javac needs to support (2). (3) is also supported because javac supports 'precise' type-distinctness tests in cast conversion; most of the times the spec won't say much about a generic cast being ill-formed, because the spec rules for proving that two types are 'provable distinct' are very weak (and, to some extent, there's a reason to that: not to incur into decidability issues). For instance, a cast like this: String s = (String)(Comparable<? extends Number>)null; Is accepted by the spec, but not by javac which scans the wildcards and sees that the wildcard bound is incompatible with the (supertype of) target type of the cast. Bringing this to the next level, consider the following example: class Test<X extends Runnable & Comparable<Integer>, Y extends Runnable & Comparable<String>> { void m(X x, Y y) { x = (X)y; } } Javac reject this and it has to do so by implementing a full-blown intersection type cast along the lines of (3) [this means checking that every type in S is castable to every type in T]. Javac even handles unchecked warnings correctly - if any of the sub-cast issues an unchecked warning, the whole cast is unchecked.
01-11-2012