diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java index 2847abaca77..f466e132259 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java @@ -921,18 +921,22 @@ public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo f if ((this.bits & Binding.FIELD) != 0) { FieldBinding fieldBinding = (FieldBinding) this.binding; FieldBinding codegenField = fieldBinding.original(); - if (((this.bits & ASTNode.DepthMASK) != 0) - && ((codegenField.isPrivate() // private access - && !currentScope.enclosingSourceType().isNestmateOf(codegenField.declaringClass) ) - || (codegenField.isProtected() // implicit protected access - && codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage()))) { - if (this.syntheticAccessors == null) - this.syntheticAccessors = new MethodBinding[2]; - this.syntheticAccessors[isReadAccess ? SingleNameReference.READ : SingleNameReference.WRITE] = - ((SourceTypeBinding)currentScope.enclosingSourceType(). - enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess, false /*not super access*/); - currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess); - return; + if ((this.bits & ASTNode.DepthMASK) != 0) { + if ((codegenField.isPrivate() // private access + && !currentScope.enclosingSourceType().isNestmateOf(codegenField.declaringClass)) + || (codegenField.isProtected() // implicit protected access + && codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) { + if (this.syntheticAccessors == null) + this.syntheticAccessors = new MethodBinding[2]; + this.syntheticAccessors[isReadAccess ? SingleNameReference.READ : SingleNameReference.WRITE] = + ((SourceTypeBinding) currentScope.enclosingSourceType(). + enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess, false /* not super access */); + currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess); + return; + } + if (!codegenField.isStatic() && currentScope.enclosingSourceType() instanceof NestedTypeBinding nestedType) { + nestedType.requestEnclosingInstancePathTo(codegenField.declaringClass); + } } } } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java index 163998c7aad..492de70b505 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java @@ -1072,9 +1072,14 @@ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, Fl outerScope = outerScope.enclosingInstanceScope(); earlySeen = methodScope.isInsideEarlyConstructionContext(nestedType.enclosingType(), false); } - if (JavaFeature.FLEXIBLE_CONSTRUCTOR_BODIES.isSupported(currentScope.compilerOptions())) { + if (JavaFeature.FLEXIBLE_CONSTRUCTOR_BODIES.isSupported(currentScope.compilerOptions()) + && nestedType.enclosingInstances != null) // only if access to enclosing instance has already been requested + { // JEP 482: this is the central location for organizing synthetic arguments and fields // to serve far outer instances even in inner early construction context. + // Only SingleNameReference.manageSyntheticAccessIfNecessary() may add more synth outers later on + // (using NestedTypeBinding.requestEnclosingInstancePathTo()). + // // Locations MethodBinding.computeSignature() and BlockScope.getEmulationPath() will faithfully // use the information generated here, to decide about signature and call sequence. while (outerScope != null) { @@ -1138,8 +1143,8 @@ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, Fl */ public void manageEnclosingInstanceAccessIfNecessary(ClassScope currentScope, FlowInfo flowInfo) { if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - NestedTypeBinding nestedType = (NestedTypeBinding) this.binding; - nestedType.addSyntheticArgumentAndField(this.binding.enclosingType()); + NestedTypeBinding nestedType = (NestedTypeBinding) this.binding; + nestedType.addSyntheticArgumentAndField(this.binding.enclosingType()); } } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java index 6ae4f749718..071ccb43d99 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java @@ -126,14 +126,27 @@ public SyntheticArgumentBinding addSyntheticArgumentAndField(ReferenceBinding ta if (!isPrototype()) throw new IllegalStateException(); if (this.scope.isInsideEarlyConstructionContext(targetEnclosingType, false)) return null; - SyntheticArgumentBinding synthLocal = addSyntheticArgument(targetEnclosingType); - if (synthLocal == null) return null; + return doAddSyntheticArgumentAndField(targetEnclosingType); +} +private SyntheticArgumentBinding doAddSyntheticArgumentAndField(ReferenceBinding targetEnclosingType) { + SyntheticArgumentBinding synthLocal = addSyntheticArgument(targetEnclosingType); + if (synthLocal == null) + return null; if (synthLocal.matchingField == null) synthLocal.matchingField = addSyntheticFieldForInnerclass(targetEnclosingType); return synthLocal; } +public void requestEnclosingInstancePathTo(ReferenceBinding targetEnclosingClass) { + if (isCompatibleWith(targetEnclosingClass)) + return; + if (getSyntheticField(targetEnclosingClass, false) == null) + doAddSyntheticArgumentAndField(targetEnclosingClass); + if (this.enclosingType instanceof NestedTypeBinding nestedType) + nestedType.requestEnclosingInstancePathTo(targetEnclosingClass); +} + /* Answer the receiver's enclosing type... null if the receiver is a top level type. */ @Override diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SuperAfterStatementsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SuperAfterStatementsTest.java index 1999735189b..708022e01a2 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SuperAfterStatementsTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SuperAfterStatementsTest.java @@ -2056,7 +2056,12 @@ class C4 { // not early for C3 ^^ Cannot read field f2 in an early construction context ---------- - 2. WARNING in C1.java (at line 18) + 2. ERROR in C1.java (at line 15) + new C4(); + ^^^^^^^^ + No enclosing instance of the type C1 is accessible in scope + ---------- + 3. WARNING in C1.java (at line 18) super(); ^^^^^^^^ You are using a preview language feature that may or may not be supported in a future release @@ -2355,4 +2360,78 @@ class Local {} ""); } + public void testCtorRef_neg () { + runNegativeTest(new String[] { + "Outer.java", + """ + import java.util.function.Supplier; + @SuppressWarnings("unused") + class Outer { + void m() { } + class Inner { + Inner() { + class Foo { + void g() { + m(); + } + } + super(); + class Bar { + static void r() { + Supplier sfoo = Foo::new; + } + }; + } + } + } + """ + }, + """ + ---------- + 1. ERROR in Outer.java (at line 9) + m(); + ^^^ + No enclosing instance of the type Outer is accessible in scope + ---------- + 2. WARNING in Outer.java (at line 12) + super(); + ^^^^^^^^ + You are using a preview language feature that may or may not be supported in a future release + ---------- + """); + } + + public void testCtorRef_pos () { + runConformTest(new String[] { + "Outer.java", + """ + import java.util.function.Supplier; + class Outer { + void m() { } + class Inner { + Inner() { + class Foo { + void g() { + System.out.print("g"); + // m(); + } + } + super(); + class Bar { + static void r() { + Supplier sfoo = Foo::new; + sfoo.get().g(); + } + }; + Bar.r(); + } + } + public static void main(String... args) { + new Outer().new Inner(); + } + } + """ + }, + "g"); + } }