[code-reflection] RFR: Refactor code for computing denotable projection of types
Maurizio Cimadamore
mcimadamore at openjdk.org
Tue Nov 25 19:25:31 UTC 2025
On Tue, 25 Nov 2025 19:07:45 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:
> The code reflection support needs a way to compute the closest fully denotable supertype of the type of an expression. To do this we build on [type projections](https://docs.oracle.com/javase/specs/jls/se25/html/jls-4.html#jls-4.10.5), but this doesn't work fully, because type projectios still allow intersection types in, and the `JavaType` API (or the `j.l.r.Type` API) doesn't have a way to model these.
>
> For this reason, we had to tweak the compiler code in `Types` to accept an extra parameter to tell the projection to also discard intersection/union types. While this works, this creates a lot of noise in the compiler codebase, so I've been looking for a lower-maintenance alternative.
>
> The basic idea behind this PR is to apply a normalization pass _before_ we compute a vanilla type projection. This normalization pass essentially replaces any intersection type with a fresh type variable whose bound is the first bound of the intersection.
>
> As an example, consider the type: `Foo<A & B & C>`:
>
> 1. we first transform this type into `Foo<#1>` where `#1` is a fresh type-variable with upper bound `A`
> 2. we then add `#1` to the list of type variables to be "projected"
> 3. we then compute the upward projectin of `Foo<#1>`, and obtain `Foo<? extends A>`.
>
> This process is sound because (a) replacing `A & B & C` with a fresh type variable with bound `A & B & C` is sound, and because (b) upward projection will always map such type variables into some kind of wildcard (so dropping some bounds from the intersection doesn't make any difference) -- unless the type is a toplevel type, in which case, again dropping a bound doesn't make any difference.
test/langtools/tools/javac/reflect/DenotableTypesTest.java line 241:
> 239: @Reflect
> 240: @IR("""
> 241: func @"test11" ()java.type:"void" -> {
When discussing things with Dan to make sure things were really sound, we came up with a bunch of potentially problematic situation for which I've added tests. They basically test intersections, array of intersections and intersections of intersections (!!).
-------------
PR Review Comment: https://git.openjdk.org/babylon/pull/707#discussion_r2561123660
More information about the babylon-dev
mailing list