[code-reflection] RFR: Add support for more types
Maurizio Cimadamore
mcimadamore at openjdk.org
Tue Apr 23 13:12:52 UTC 2024
This PR adds support for type-variables and wildcard type arguments in the code model `JavaType`'s hierarchy.
This allows the code model to reflect the source types much more accurately, as we no longer need to erase the source type at the first sign of a non-denotable type. Instead, we can use the a modified (see below) version of the `Types::upwards` function (type projection) to compute the closest **denotable** upper bound to the type found in the source code. This means that the type associated with every op in the model is a (denotable) supertype of the type in the javac AST. The fact that such type is denotable has three important consequences:
* the type can be expressed in the source code (in case the code model needs to be lifted back into Java source)
* the type must be expressible in the syntax of bytecode signature attributes (this is important e.g. for the local variable type attribute)
* the type can be resolved to its runtime counterpart in `j.l.r.Type` (not implemented in this PR), as explained below
Some parser changes were required to support this, so that we can serialize and deserialize the new types accordingly.
A new method has been added to `JavaType`, namely `JavaType::erasure`, which computes the erasure of a `JavaType`. This might come in handy when lowering the model into bytecode. Since supporting erasure is crucial, modelling of types has been carefully chosen as to facilitate that operation as much as possible: that is why, for example, `TypeVariableRef` contains the "principal" type-variable bound (so that we can define erasure for type-variables in a straightforward fashion, as the erasure of the primary bound).
#### Denotable projections
The code model type associated with an op result is computed by applying a modified version of `Types::upwards` - that is, the function that implements type projections as specified in [JLS 4.10.5](https://docs.oracle.com/javase/specs/jls/se22/html/jls-4.html#jls-4.10.5). The original projection algorithm is designed to leave intersection types in place - while this is handy, as it maximizes the applicability of the type inferred for local variables declared with `var`, for the code model use this is not suitable, as we'd like to get to a denotable type in the end (jshell has a similar problem, which was addressed in a more ad-hoc way).
It is generally possible to project an intersection type using only one of its bounds, e.g.
List<A & B>
Is projected to:
List<? extends A>
There are, however, problems when projecting intersection types that are on the right of some lower-bounded wildcard - e.g.
List<? super A & B>
In this case, projecting to `List<? super A>` is not valid, as `List<? super A>` is not a supertype of `List<? super A & B>`. For this reason, in these cases we have to fallback to an unbounded wildcard `List<?>`.
#### Runtime resolution
Support for runtime resolution of elements in the `JavaType` hierarchy is possible, as there is a subtype of `j.l.r.Type` for each of the subtypes in `JavaType`. The main problem is being able to resolve type-variables: in the current modelling, type-variable types only have a name, and names can be ambiguous. That is, it could be possible for a type-variable with same name to be defined at different levels in the source code:
class Foo<X> { //1
<X> void test() { ... } // 2
}
To allow for better disambiguation we need to add *ownership* information to the `TypeVariableRef` class. This could point to either another `JavaType` (if the type-variable is a class type-variable), or to a `MethodRef` in case the type-variable is defined in a method. In this PR I didn't want to tackle to problem of modelling this additional information (that will come in a follow-up PR). Once the proper ownership info is in place, we might add code to enable runtime resolution of `JavaType`s.
-------------
Commit messages:
- Add erasure test
- Add bound to type-variables
- Drop spurious changes
- Drop intersections and unions
- Fix tests after merge
- Merge branch 'code-reflection' into projections
- Add test for union type
- Drop method type support from ReflectMethods::normalize
- Fix tests
- Inital push
Changes: https://git.openjdk.org/babylon/pull/51/files
Webrev: https://webrevs.openjdk.org/?repo=babylon&pr=51&range=00
Stats: 827 lines in 19 files changed: 579 ins; 22 del; 226 mod
Patch: https://git.openjdk.org/babylon/pull/51.diff
Fetch: git fetch https://git.openjdk.org/babylon.git pull/51/head:pull/51
PR: https://git.openjdk.org/babylon/pull/51
More information about the babylon-dev
mailing list