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