RFR: 8349754: Invalid "early reference" error when class extends an outer class
Gavin Bierman
gavin.bierman at oracle.com
Wed Feb 12 12:19:02 UTC 2025
Thanks Maurizio. I’ll take a look at this for the spec for the next release.
Gavin
On 12 Feb 2025, at 10:19, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:
On Mon, 10 Feb 2025 20:51:34 GMT, Archie Cobbs <acobbs at openjdk.org<mailto:acobbs at openjdk.org>> wrote:
The compiler is generating a bogus error for this input:
$ cat Outer.java
class Outer {
private int i;
class Sub extends Outer {
Sub() {
i = 42;
super();
}
}
}
$ javac --enable-preview --source 24 Outer.java
Outer.java:5: error: cannot reference i before supertype constructor has been called
i = 42;
^
Note: Outer.java uses preview features of Java SE 24.
Note: Recompile with -Xlint:preview for details.
1 error
The trick here is that the expression `i` refers to `Outer.this.i`, not `this.i`, but the error checking logic is mistakenly assuming the latter. This patch adds an exception for this case, which happens when the field is `private` and declared in a class which is both a superclass and an outer class.
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 context of a subclass of C.
There's no reference to the fact that the instance variable being referred to must be a member of C. This is different, for instance, from what happens for 6.5.7.1 (simple method names), where membership is mentioned.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/23545#discussion_r1952360600
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20250212/be8d4ebd/attachment-0001.htm>
More information about the compiler-dev
mailing list