JDK-8055219 : Handling of non-standard inputs in javax.lang.model.util.Types
  • Type: Bug
  • Component: core-libs
  • Sub-Component: javax.lang.model
  • Affected Version: 8
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2014-08-15
  • Updated: 2024-09-24
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
tbdUnresolved
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Sub Tasks
JDK-8340721 :  
Description
The behavior of the javax.lang.model.util.Types methods is very lightly specified, relying primarily on the corresponding definitions in the JLS.  This fails, however, to account for the mismatch between the API's concept of "TypeMirror", and the JLS's more restricted concept of "Type".

In general, inputs like WildcardTypes and UnionTypes are allowed in places that they should not, exposing arbitrary implementation details.  In order to have clearly-defined, standard behavior in these cases, and in order to minimize constraints on the implementation to not perturb these implementation details, it is best to limit the set of acceptable inputs and throw more IllegalArgumentExceptions.

ErrorType is special, because it is designed for error recovery, so this is one case in which the existing behavior is probably okay (but it should be clearly specified).

It would also be useful to more precisely define what constitutes a "valid" result of methods like ArrayType.getComponentType() and ExecutableType.getReturnType().

Specific comments:

---

isSameType

spec: True if the types "represent the same type"; exception for wildcards, which are never "the same" as anything, even themselves (the argument for this behavior doesn't really make sense)

actual: In general, true if the two types are the same; also true if ExecutableTypes can be made the same with alpha-renaming (as in JLS 8.4.4, 8.4.2); always true when one argument is an ErrorType; and false for all wildcards.

expected: Unclear whether this is meant to be a true "type" operation, or a more general TypeMirror operation.  If restricted to types, should have IAE for WildcardType, NoType, and UnionType.  If a more general TypeMirror test, should treat WildcardTypes like other TypeMirrors (do they represent the same thing?).  Either way, the behavior of ExecutableType and ErrorType should be clearly stated.

---

isSubtype, isAssignable

spec: Refers to the JLS definitions; IAE for ExecutableType or packages; behavior of other TypeMirrors unspecified

actual: Matches the spec, but is a mess outside of that scope.  Wildcards: true if same (but false for two instances of the same wildcard); for '? super T' on rhs, recurs on T (as if the wildcard were a type variable).  NoTypes: none <: none, void <: void, otherwise false (but I noticed a NPE for Object <: none).  Unions: unclear -- for union on lhs true if true for all elements; for union on rhs, maybe discards all but first element?  ErrorType: always true

expected: IAE for WildcardType, NoneType, and UnionType (the concept of subtyping is simply foreign to these constructs, just like for ExecutableType).  Need to clearly state ErrorType behavior.

---

contains

spec: Refers to the JLS definitions; IAE for ExecutableType or packages; behavior of other TypeMirrors unspecified

actual: Matches spec, with additions: none, void, unions, and primitives contain themselves; ErrorType on either side is always true.

expected: NPE for TypeMirrors that cannot be type arguments: NoType, UnionType, PrimitiveType.  Need to clearly state ErrorType behavior.

---

directSupertypes

spec: does not define the term "direct supertype", although JLS does (4.10) (undefined for non-types, defined for primitives); IAE for ExecutableType or packages

actual: WildcardType, ErrorType, PrimitiveType, NONE and VOID (NoTypes): empty list; UnionType: lub of the elements, maybe?

expected: IAE for WildcardType, UnionType, NoType (if you don't participate in subtyping, you don't have supertypes); primitives should be either IAE or return the actual direct super, as defined by JLS (4.10.1); ErrorType is fine to return an empty list, but this should clarified in the spec

---

erasure

spec: refers to JLS, which defines erasure for all types and for method signatures (but nothing else); IAE for package name

actual: WildcardType erases to its erased upper bound; ExecutableType erases each type, along the lines of JLS but generalizing beyond the signature to return and thrown types; UnionType erases the first element; ErrorType and NONE/VOID return the input unchanged

expected: IAE for WildcardType, UnionType, and NoType; should clarify spec on ErrorType and ExecutableType

---

unboxedType

spec: IAE when the "given type has no unboxing conversion"

actual: matches spec

expected: fine, but could be more explicit that there will always be an IAE for non-DeclaredTypes.

---

capture

spec: refers to JLS, which defines capture for all types (but nothing else); IAE for executable or package name

actual: WildcardType, UnionType, NONE/VOID, ErrorType: return the type unchanged; IAE for executable or package

expected: IAE for non-types (WildcardType, UnionType, NoType); clearly specify that ErrorType returns itself

---

getArrayType

spec: IAE if an input TypeMirror is "not valid"

actual: allows creation of primitive arrays, UnionType arrays, and '<none>[]' (!); IAE for WildcardType, ExecutableType, and other NoTypes; no error for ErrorTypes.

expected: IAE for all inputs that are neither ReferenceType nor PrimitiveType (including IAE for UnionTypes and NONE).

---

getWildcardType

spec: IAE if an input TypeMirror is "not valid"

actual: IAE for PrimitiveType, WildcardType, UnionType, ExecutableType, and NoTypes; no error for ErrorTypes.

expected: behavior is fine, but spec should be more clear -- that is, IAE for all non-ReferenceTypes.

---

getDeclaredType

spec: IAE if an input TypeMirror is "not valid"

actual: WildcardTypes, UnionTypes, and ErrorTypes are allowed; IAE for PrimitiveType, ExecutableType, and NoTypes.

expected: IAE for all inputs that are neither ReferenceType nor WildcardType (including IAE for UnionTypes).

---

asMemberOf

spec: IAE "if the element is not a valid one for the given type"

actual: for all type arguments, substitutes them directly into the Element's declared type; e.g., the type of method 'next' in 'Iterator<? super String>' is '()? super String' (!)

expected: Only ReferenceTypes should be used for substitution; a WildcardType as a type argument should prompt either IAE or capture (I prefer the IAE, because the theoretical justification for performing capture here is a little shaky; compare JLS 3 4.5.2 to JLS 7 4.5.2)

---

Suggested valid component types of TypeMirrors (for inclusion in the javadoc of each TypeMirror):

ArrayType: componentType is a ReferenceType or PrimitiveType

DeclaredType: enclosingType is a DeclaredType or NONE; typeArguments are ReferenceTypes or WildcardTypes

ExecutableType: parameterTypes and thrownTypes are ReferenceTypes or PrimitiveTypes; returnType is ReferenceType, PrimitiveType, or VOID

IntersectionType: bounds are ReferenceTypes

TypeVariable: lowerBound and upperBound are ReferenceTypes

UnionType: alternatives are ReferenceTypes

WildcardType: extendsBound and superBound are ReferenceTypes

Comments
> actual: In general, true if the two types are the same; also true if ExecutableTypes can be made the same with alpha-renaming (as in JLS 8.4.4, 8.4.2); From JLS, it looks more like theta-renaming :) Jokes aside, I filed this bug some time ago to capture the fact that ExecutableType does not care about method names where they are significant: https://bugs.openjdk.org/browse/JDK-8304733.
26-08-2024