[code-reflection] RFR: Support storing the code that builds the code model [v11]

Maurizio Cimadamore mcimadamore at openjdk.org
Thu Feb 27 11:38:17 UTC 2025


On Wed, 26 Feb 2025 18:06:44 GMT, Mourad Abbay <mabbay at openjdk.org> wrote:

>> In this PR we allow the user to decide how to store the code model. The first option is `TEXT`, if this is selected, we store the textual representation of the code model. The second option is `CODE_BUILDR`, if this is selected, we store the code that builds the code model. All work done here is around the second option, because the first option is already supported.
>
> Mourad Abbay has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Ensure that block params are inserted in the correct order

src/jdk.incubator.code/share/classes/jdk/incubator/code/internal/CodeModelToAST.java line 102:

> 100:     }
> 101: 
> 102:     private JCTree invokeOpToJCMethodInvocation(CoreOp.InvokeOp invokeOp) {

This method has some issues -- but perhaps we can keep it for now.
The main problem is that we seem to copy types from the invoked method declaration and put them "as is" in the generated AST. This works only as long as the invoked method doesn't have any generic type. For instance, consider a call to `List::add`. The signature of this method accepts `X` which is a type parameter of `List<X>`. I believe the code you have copies the `X` from the declared signature and sticks it into the javac's `MethodType` instance attached to the method call. Since this method type is used to describe the use-site (the call), and not the declaration, the type seems incorrect. E.g. calling `List<String>:add` should have a type of `add(String)` not `add(X)`. (btw, a similar problem is present for field access, if the type of the accessed field is a type-variable -- so it's not just an issue with method calls).

The type of the invoked method/accessed field should always be adjusted with `Types.memberType` first. This method takes two parameters:

* the receiver type you are using to call the instance method/access the instance field
* the symbol you are trying to access

And returns the _instantiated_ type of that symbol at that receiver type. Examples:


memberType(List<String>, add(X)->void) -> (String)->void
memberType(List<Integer>, add(X)->void) -> (Integer)->void


Once you address this, there is still another problem with generic methods -- as methods can have their own type-variables too. To figure out what is the type to be replaced for these type-variables you generally need to run inference -- which seems way too much for what we're trying to do here. The issue here is that the code model you are processing doesn't expose these details, and so generating the AST needs to "trace back" whatever steps where done when generating this model -- which is an hard problem.

I hope we can get away with just working with erased types, and maybe insert type-conversion to convert the type of the invoked method/accessed field so that it matches the expected op result type.

src/jdk.incubator.code/share/classes/jdk/incubator/code/internal/CodeModelToAST.java line 128:

> 126:             var lastParam = invokeOp.invokeDescriptor().type().parameterTypes().getLast();
> 127:             Assert.check(lastParam instanceof ArrayType);
> 128:             methodInvocation.varargsElement = typeElementToType(((ArrayType) lastParam).componentType());

Same problem as described above -- here we're copying the vararg array at the declaration site into a type at the use-site -- for something like `List::of` this won't give the result you expect.

-------------

PR Review Comment: https://git.openjdk.org/babylon/pull/305#discussion_r1973406083
PR Review Comment: https://git.openjdk.org/babylon/pull/305#discussion_r1973407675


More information about the babylon-dev mailing list