JDK-8166396 : 5.5: Clean up description of legal conversions in casts
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 8
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2016-09-20
  • Updated: 2018-08-03
  • Resolved: 2017-01-25
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 9
9Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
The start of 5.5 lists various conversions that are allowed in a casting context.

"Casting contexts allow the use of one of:
��� an identity conversion (��5.1.1)
��� a widening primitive conversion (��5.1.2)
��� a narrowing primitive conversion (��5.1.3)
��� a widening and narrowing primitive conversion (��5.1.4)
��� a widening reference conversion (��5.1.5) optionally followed by either an unboxing conversion (��5.1.8) or an unchecked conversion (��5.1.9)
��� a narrowing reference conversion (��5.1.6) optionally followed by either an unboxing conversion (��5.1.8) or an unchecked conversion (��5.1.9)
��� a boxing conversion (��5.1.7) optionally followed by a widening reference conversion (��5.1.5)
��� an unboxing conversion (��5.1.8) optionally followed by a widening primitive conversion (��5.1.2)."

 This list has various problems:
- It doesn't include all allowed reference type casts (per 5.5.1), such as from Runnable to Cloneable
- It doesn't allow widening before unboxing followed by primitive widening, even though javac does (see JDK-8166326)
- The use of "widening and narrowing primitive conversion" adds unnecessary complexity, since we could just as easily describe this as "a widening primitive conversion followed by a narrowing primitive conversion". (Cleaning this up means deleting 5.1.4, though, a disruption that may not be worth it.)
- It gives the impression that any listed conversion is allowed, even though some unchecked conversions are not (per 5.5.1)
- It is redundant, since the next paragraph restates it more precisely.

Propose rewriting to merge with the subsequent description and to accurately reflect the set of legal conversions.
Comments
Rewritten 5.5: Casting contexts allow the operand of a cast operator (��15.16) to be converted to the type explicitly named by the cast operator. ***Compared to assignment contexts and method invocation contexts, casting contexts allow the use of more of the conversions defined in 5.1, and allow more combinations of those conversions.*** ***If the expression is of a primitive type, then a casting context allows*** the use of one of ***the following***: - an identity conversion (5.1.1) - a widening primitive conversion (5.1.2) - a narrowing primitive conversion (5.1.3) - a widening and narrowing primitive conversion (5.1.4) - a boxing conversion (5.1.7) ***[delete "optionally..."]*** - ***a boxing conversion followed by a widening reference conversion (5.1.5)*** ***If the expression is of a reference type, then a casting context allows the use of one of the following:*** - ***an identity conversion (5.1.1)*** - a widening reference conversion (5.1.5) ***[delete "optionally..."]*** - a narrowing reference conversion (5.1.6) ***[delete "optionally..."]*** - ***an unboxing conversion (5.1.9)*** - ***an unboxing conversion followed by a widening primitive conversion (5.1.2)*** - ***a widening reference conversion followed by an unboxing conversion*** - ***a widening reference conversion, followed by an unboxing conversion, followed by a widening primitive conversion*** - ***a narrowing reference conversion followed by an unboxing conversion*** **If the expression has the null type, then the expression may be cast to any reference type.** **If a casting context makes use of a narrowing reference conversion that is checked or partially unchecked (5.1.6.2), the class of the value will be tested at run time, possibly causing a `ClassCastException` (5.1.6.3). Otherwise, no such run time check is performed.** Value set conversion (5.1.13) is applied after the type conversion. ***[Delete "the compile-time legality..." and subsequent bullets.]***
17-01-2017

*** Full changes for 5.1.6 *** [Notation: the ** delimiter indicates insertions/rewrites, and the ~~ delimiter indicates deletions. Square brackets are editorial, not meant to be printed.] 5.1.6 Narrowing Reference Conversion ------------------------------------ ~~Six kinds of conversions are called the _narrowing reference conversions: ...~~ [Deleted: these are now covered by more comprehensive rules in 5.1.6.1.] **A _narrowing reference conversion_ treats values of a reference type _S_ as values of a different reference type _T_, where _S_ is not a subtype of _T_. The supported pairs of types are defined in 5.1.6.1. Unlike widening reference conversion (5.1.5), the types need not be directly related. However, there are restrictions that prohibit conversion between certain pairs of types when it can be statically proven that no single reference can have both types.** **The conversion requires** a test at run time to find out whether the actual reference value is a legitimate value of the new type **_T_**. If not, then a `ClassCastException` is thrown **(5.1.6.3)**. **In some cases, the type _T_ cannot be fully checked at run time; the programmer is notified with an _unchecked warning_ at compile time (5.1.6.2).** **5.1.6.1 Allowed Narrowing Reference Conversions** --------------------------------------------------- [Moved from 5.5.1.] **A narrowing reference conversion from reference type _S_ to reference type _T_ is allowed if all of the following are true:** - **_S_ is _not_ a subtype (4.10) of _T_** - **If there exists a parameterized type _X_ that is a supertype of _T_, and a parameterized type _Y_ that is a supertype of _S_, such that the erasures of _X_ and _Y_ are the same, then _X_ and _Y_ are not provably distinct (4.5).** [This condition is restated throughout the existing rules, but is much clearer if we state it just once.] - **One of the following cases applies:** - **_S_ and _T_ are class types, and** either _|S| <: |T|_, or _|T| <: |S|_. - **_S_ and _T_ are interface types.** - **_S_ is a class type,** _T_ is an interface type, **and** if _S_ **names** a `final` class (8.1.1), then **that class implements the interface named by _T_**. [This clarifies the existing rule, which is unclear about whether "implements" means subtyping or subclassing. The latter is intended: for example, String --> Comparable<X> is a legal unchecked cast.] - **_S_ is an interface type, _T_ is a class type, and if _T_ names a `final` class (8.1.1), then that class implements the interface named by _S_.** ["Implements the interface named by _S_" is a much more compact way to state the conditions described over two paragraphs in the existing rules.] - _S_ is an array type _SC[]_, that is, an array of components of type _SC_ **;** _T_ is an array type _TC[]_, that is, an array of components of type _TC_ **; and there is a narrowing reference conversion allowed from _SC_ to _TC_.** - **_S_ is the class type `Object` and** _T_ is an array type. [This and the next rule do not go in the opposite direction, from array type _S_ to class/interface type _T_, because the only valid choices for _T_ violate the "not a subtype" rule: such cases are widening, not narrowing, reference conversions.] - **_S_ is one of the interface types** `java.io.Serializable` or `Cloneable` (the only interfaces implemented by arrays) **and** _T_ is an array type. - _S_ is a type variable **and a narrowing reference conversion is allowed from** the upper bound of _S_ ~~in place of _S_~~ **to _T_**. [This case doesn't mention widening from the upper bound of S to T, because that would be a widening reference conversion from S to T.] - _T_ is a type variable **and one of an identity conversion, widening reference conversion, or narrowing reference conversion is allowed from _S_ to** the upper bound of _T_ ~~in place of _T_~~. - _S_ is an intersection type, **_S1 & ... & Sn_, and for all _i_, _1 ��� i ��� n_, one of an identity conversion, widening reference conversion, or narrowing reference conversion is allowed from _Si_ to _T_.** - _T_ is an intersection type, _T1 & ... & Tn_, **and for all _i_, _1 ��� i ��� n_, one of an identity conversion, widening reference conversion, or narrowing reference conversion is allowed from _S_ to _Ti_.** Example **5.1.6.1-1 Narrowing Reference** Conversion for **Class and Interface** Types ... Example **5.1.6.1-2 Narrowing Reference** Conversion for Array Types ... **5.1.6.2 Checked and Unchecked Narrowing Reference Conversions** ----------------------------------------------------------------- [Moved from 5.5.2.] A **narrowing reference conversion** from a type _S_ to a parameterized type (4.5) _T_ is _unchecked_ unless at least one of the following is true: - ~~_S <: T_~~ [Deleted: this is not a narrowing reference conversion.] - All of the type arguments (4.5.1) of _T_ are unbounded wildcards - _T <: S_ and _S_ has no subtype _X_ other than _T_ where the type arguments of _X_ are not contained in the type arguments of _T_. A **narrowing reference conversion** from a type _S_ to a type variable _T_ is **always _unchecked_**. A **narrowing reference conversion** from a type _S_ to an intersection type _T1 & ... & Tn_ is **_unchecked_** if there exists a _Ti_ (_1 ��� i ��� n_) such that **_S_ is not a subtype of _Ti_ and** a **narrowing reference conversion** from _S_ to _Ti_ is unchecked. An unchecked **narrowing reference conversion** from _S_ to a non-intersection type _T_ is _completely unchecked_ if **_|S| <: |T|_** ~~the cast from _|S|_ to _|T|_ is statically known to be correct~~. Otherwise, it is _partially unchecked_. An unchecked **narrowing reference conversion** from _S_ to an intersection type _T1 & ... & Tn_ is _completely unchecked_ if, for all _i_ (_1 ��� i ��� n_), **either _S <: Ti_ or** a **narrowing reference conversion** from _S_ to _Ti_ is ~~either statically known to be correct or~~ completely unchecked. Otherwise, it is _partially unchecked_. An unchecked **narrowing reference conversion** causes a compile-time unchecked warning, unless suppressed by the `SuppressWarnings` annotation (9.6.4.5). A **narrowing reference conversion** is _checked_ if ~~it is not statically known to be correct and~~ it is not _unchecked_. **5.1.6.3 Narrowing Reference Conversions at Run Time** ------------------------------------------------------- [Moved from 5.5.2 and 5.5.3.] **All checked and partially unchecked narrowing reference conversions require** a run-time validity check. **If the conversion is** to an intersection type, **_T1 & ... & Tn_**, then for all _i_ (_1 ��� i ��� n_) any run-time check required for a **conversion** from _S_ to _Ti_ is also required for the **conversion** to the intersection type. **Otherwise, the check is as follows:** - If the value at run time is `null`, then the **conversion** is allowed. - Otherwise, let _R_ be the class of the object referred to by the run-time reference value, and let _T_ be the erasure (4.6) of the type **being converted to**. [I've simplified the above paragraphs from 5.5.2 a lot. We don't need to itemize all the cases. Fully unchecked conversions should be ignored. Intersections need special treatment. In every other case, all we need to to figure out what _T_ is (the erasure of the conversion target) and what _R_ is (the value's runtime type, regardless of its static type). From there, we can apply the rules from 5.5.3.] - If _R_ is an ordinary class (not an array class): - If _T_ is a class type, then _R_ must be either the same class (4.3.4) as _T_ or a subclass of T, or a **`ClassCastException`** is thrown. - If _T_ is an interface type, then _R_ must implement (8.1.5) interface _T_, or a **`ClassCastException`** is thrown. - If _T_ is an array type, then a **`ClassCastException`** is thrown. - If _R_ is a class representing an array type _RC[]_, that is, an array of components of type _RC_: - If _T_ is a class type, then _T_ must be `Object` (4.3.2), or a **`ClassCastException`** is thrown. - If _T_ is an interface type, then a **`ClassCastException`** is thrown unless _T_ is the type `java.io.Serializable` or the type `Cloneable` (the only interfaces implemented by arrays). ~~This case could slip past the compile-time checking if, for example, a reference to an array were stored in a variable of type Object.~~ [Deleted comment: you could make a similar comment about every bullet in this list. That's how casting works: a value with imprecise static typing is checked dynamically. We shouldn't be trying to explain it at this point.] - If _T_ is an array type _TC[]_, that is, an array of components of type _TC_, then a **`ClassCastException`** is thrown unless **either** _TC_ and _RC_ are the same primitive type, **or** _TC_ and _RC_ are reference types and **are allowed by** a recursive application of these run-time rules ~~for casting~~. - If _R_ is an interface: [Note:] Note that _R_ cannot be an interface when these rules are first applied for any given **conversion**, but _R_ may be an interface if the rules are applied recursively because the run-time reference value may refer to an array whose **component** type is an interface type. - If _T_ is a class type, then _T_ must be `Object` (4.3.2), or a **`ClassCastException`** is thrown. - If _T_ is an interface type, then _R_ must be either the same interface as _T_ or a subinterface of _T_, or a **`ClassCastException`** is thrown. - If _T_ is an array type, then a **`ClassCastException`** is thrown. Example **5.1.6.3-1**. Incompatible Types at Run Time ...
13-01-2017

- The main point of JDK-6558543 was to make the sentence "Casting contexts allow the use of ..." (including the bulleted list that follows) more authoritative. I would much prefer to leave it intact but augmented for the new conversions, and recast the "compile-time legality" paragraphs into a rule following the style of 5.2 and 5.3 (also killing the null-type bird with the same stone): "If the type of the expression cannot be converted to the type of the variable by a conversion permitted in a casting context, AND THE TYPE OF THE EXPRESSION IS NOT THE NULL TYPE, then a compile-time error occurs." followed by "If the type of the expression is the null type, then the expression may be converted to any reference type." - Tables 5.5-A and 5.5-B don't have a scenario where a widening reference conversion prior to an unboxing conversion would be possible. Should they have?
11-01-2017

On further investigation, Alex and I determined that sections 5.5.1-5.5.3 are exacerbating the issue (they're again defining the legal pairs of types, this time without mentioning any conversions, other than, vaguely, "casting conversion"). Further, we noted that "narrowing reference conversion" is intended to be used more broadly than I expected (it allows lateral conversions, like from Runnable to Cloneable). But it is defined in pre-generics terms, and hasn't been properly enhanced to account for parameterized types, etc. Proposed solution: rewrite 5.1.6 to include 5.5.1-5.5.3, which become the compile-time and run-time rules for narrowing reference conversions (see below). Then 5.5 can simply say that casting contexts allow narrowing reference conversions (see above), and all the associated rules come into play implicitly.
05-01-2017

Responding to the question about tables: they're not comprehensive, and that's okay. To properly add rows for type variables with box-type bounds, you'd need 8 or 9 new cases, which is probably more than we want.
08-12-2016

I've just revised the spec text comment, based on discussion with Alex.
08-12-2016

Another problem, fixed in the above updated text for 5.5: this section doesn't mention conversions from the null type, while 5.2 and 5.3 do.
20-09-2016

I've removed unchecked conversions from the list. This is because i) a narrowing reference conversion can achieve anything that an unchecked conversion can achieve -- unchecked conversion maps raw types and arrays of raw types to their subtypes, and ii) the rules for warnings due to unchecked casts (5.5.2) are not are not the same as the rules for warnings due to unchecked conversions (5.1.9). A specification note stating that a wanted unchecked conversion can be achieved via a narrowing reference conversion may be appropriate.
20-09-2016

Some history: - JLS 2 just lists some allowed conversions in a sentence, which reads more like "you can use casts to do these different conversions" and perhaps doesn't sound like an authoritative list of all possible sequences of conversions (it's ambiguous, though, and could also be read as authoritative). - JLS 3 introduced the structure we have in JLS 8, with a bulleted list of possible conversions or combinations of conversions. It also introduced unchecked conversions and boxing/unboxing conversions. - JLS 3 also recognized that a 'byte' to 'char' conversion is not the same as a narrowing reference conversion, and added section 5.1.4 "widening and narrowing primitive conversions" (JDK-4770188). - JLS 7 added some combinations of widening/unboxing (JDK-6558543) and included "widening and narrowing primitive conversions" on the list (previously there was no cross-reference from anywhere).
20-09-2016