RFR: 8349754: Invalid "early reference" error when class extends an outer class [v2]
Archie Cobbs
acobbs at openjdk.org
Wed Feb 12 15:38:07 UTC 2025
On Wed, 12 Feb 2025 10:15:27 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:
>> Archie Cobbs has updated the pull request incrementally with one additional commit since the last revision:
>>
>> Simplify logic using Symbol.isMemberOf() per review suggestion.
>
> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java line 4015:
>
>> 4013: // declared in a superclass S if (a) the field is private, and (b) S is also an outer class.
>> 4014: // It's OK because the expression "x" then refers to the outer instance, not the current instance.
>> 4015: if (env.enclClass.type != v.owner.type && (v.flags() & PRIVATE) != 0) {
>
> My feeling is that we should deal with this from a membership point of view. That is, `x` here is NOT a member of the subclass because it is not inherited. I'd suggest to use `Symbol::isMemberOf` (which also does the subtype check).
>
> (Note that the subclass could declare _another_ field with same name, in which case the superclass field is not inherited, even if non-private. Better to rely on existing membership logic -- the rules are finicky)
>
> If I'm not mistaken, I hope you can rewrite the full check like this:
>
>
> if (env.info.ctorPrologue &&
> (v.flags() & STATIC) == 0 &&
> v.isMemberOf(env.enclClass.sym)) { ... }
>
>
> Honestly, I'm also reading the text in the spec draft for JEP 492, I'm not sure it deals with this case correctly:
>
>> If an expression name consists of a single Identifier, then there must be exactly one declaration denoting either a local variable, formal parameter, exception parameter, or field in scope at the point at which the identifier occurs. Otherwise, a compile-time error occurs.
>
>> If the declaration denotes an instance variable of a class C ([8.3.1.1](https://docs.oracle.com/javase/specs/jls/se22/html/jls-8.html#jls-8.3.1.1)), then both all of the following must be true, or a compile-time error occurs:
>
>> The expression name does not occur in a static context ([8.1.3](https://cr.openjdk.org/~gbierman/jep492/jep492-20241218/specs/flexible-constructor-bodies-jls.html#jls-8.1.3)).
>
>> If the expression name occurs in an early construction context of C ([8.8.7](https://cr.openjdk.org/~gbierman/jep492/jep492-20241218/specs/flexible-constructor-bodies-jls.html#jls-8.8.7)), then it is the left-hand operand of a simple assignment expression ([15.26](https://docs.oracle.com/javase/specs/jls/se22/html/jls-15.html#jls-15.26)), the declaration of the named variable lacks an initializer, and the simple assignment expression is not enclosed in a lambda expression or inner class declaration that is contained in the early construction context of C.
>
>> The expression name does not occur in an early construction c...
Thanks, that is a nice simplification.
>From what I can tell we still need to make an exception for the `Foo.this.x` case, otherwise this example would fail:
class Early {
int x;
class Sub extends Early {
Sub() {
Early.this.x = 3;
super();
}
}
}
Trying to explain this to myself: The current class here is `Foo`, and `Foo.this.x` does indeed refer to a member of class `Foo`. But it refers to a different _instance_ of class `Foo` from the one under construction.
I suppose this question of "Which _instance_ of class S are we talking about?" only comes up in the compiler in the corner case when a class has S as both a superclass and an outer class, so there's not really "first class" support for answering this question, like there is for answering the question "Is x a member of S?".
Fixed in 589e6d7d2fc.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/23545#discussion_r1952895997
More information about the compiler-dev
mailing list