RFR: 8357653: Inner classes of type parameters emitted as raw types in signatures [v6]
Maurizio Cimadamore
mcimadamore at openjdk.org
Mon Jul 7 17:24:41 UTC 2025
On Mon, 7 Jul 2025 17:10:34 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:
>> Aggelos Biboudis has updated the pull request incrementally with one additional commit since the last revision:
>>
>> Improve comments of asEnclosingSuper/asOuterSuper
>
> src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java line 2240:
>
>> 2238: * with the given symbol. If none exists, return null.
>> 2239: *
>> 2240: * This is typically used when there is an explicit qualification of a type.
>
> I don't think this is quite correct. The "classic" case for `asOuterType` is something like this (AFAIU):
>
>
> class Sup<F> {
> public F f;
> }
>
> class Outer {
> static class Sub extends Sup<String> {
> class I {
> void test() {
> String f2 = f;
> }
> }
> }
> }
>
>
> Here, we see an access to a field `f`. The "site" for this method call is `I` (the class where the access comes from). What is the instantiated type of `m()` ? To answer that question we need to:
>
> 1. compute an instantiated receiver type -- e.g. some type that is related to `I` and that matches `Sup` (the class where `f` is declared). In this case such type is `Sup<String>`
> 2. replace the type parameters in the instantiated receiver type in the (declared) signature of the field -- `[F=String]F` = `String`. That is the field signature we should use.
>
> Step (1) here is typically done using `asOuterType`. This will keep trying with all the enclosing types of the input type. So, first `I`, then `Sub`. It will not try to use `Outer` -- which is correct as inside `I` we can't really access instance members in `Outer` (since `I` is an inner class of `Sub`, and `Sub` is `static`). So, from a coding perspective, using `getEnclosingType()` here is "more correct", as using `enclClass()` would "overshoot".
>
> (That said, since we lookup from inner to outer, it is very likely that `asOuterSuper` and `asEnclosingSuper` yield the same result, even in this case -- although I'd prefer if our code did the correct thing and refused to look into unrelated classes).
In other words, sometimes (in `Types.memberType`) we have to find the instantiated owner type of a given instance member (field or method), so we can determine the member's instantiated type.
This only happens when the member access is a simple name (because if it is, say `<expr>.m()`, then we know of which type `m` is a member of -- namely the type of `<expr>`).
When the member access is a simple name, the input type to `memberType` is usually the class type in which access occurs -- and since the member can sometimes be a member of an enclosing class of the current class, we need to recurse.
Note that there would be nothing wrong in using `enclClass()` -- because, at the end of the day, `enclClass()` is what we used to resolve the symbol reference in the first place (see `Resolve::findVar` / `Resolve::findMethod` -- which uses `env.outer` -- which is like `enclClass`).
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/25451#discussion_r2190677909
More information about the compiler-dev
mailing list