diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java index d747e21bfc6..04f2649ec63 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java @@ -74,8 +74,13 @@ public TypeBinding resolveType(BlockScope scope) { ReferenceBinding enclosingReceiverType = scope.enclosingReceiverType(); // interface-qualified this selects a default method in a super interface, // but here we are only interested in supers of *enclosing instances*: - if (enclosingReceiverType != null && !enclosingReceiverType.isInterface() && scope.isInsideEarlyConstructionContext(enclosingReceiverType, false)) - scope.problemReporter().errorExpressionInEarlyConstructionContext(this); + if (enclosingReceiverType != null && !enclosingReceiverType.isInterface()) { + TypeBinding typeToCheck = (enclosingReceiverType.isCompatibleWith(this.resolvedType)) + ? enclosingReceiverType // cannot reference super of the current type + : this.resolvedType; // assumeably not a super but an outer type + if (scope.isInsideEarlyConstructionContext(typeToCheck, false)) + scope.problemReporter().errorExpressionInEarlyConstructionContext(this); + } return this.resolvedType = (this.currentCompatibleType.isInterface() ? this.currentCompatibleType : this.currentCompatibleType.superclass()); 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 d3f1b7e2874..77140f3ae32 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 @@ -2182,4 +2182,103 @@ public class TestFlow { """; runner.runNegativeTest(); } + + public void testGH3094() { + Runner runner = new Runner(false); + runner.testFiles = new String[] { + "X.java", + """ + public class X { + class Nested extends X1 { + X1 xy; + class DeeplyNested extends NestedInX1 { + DeeplyNested(float f) { + Nested.super.x1.super(); // Error here + } + } + } + public static void main(String... args) { + Nested nest = new X().new Nested(); + nest.x1 = new X1(); + nest.new DeeplyNested(1.1f); + } + } + class X1 { + X1 x1; + class NestedInX1 {} + } + """ + }; + runner.runConformTest(); + } + + public void testGH3094_2() { + Runner runner = new Runner(false); + runner.testFiles = new String[] { + "X.java", + """ + public class X { + class Nested extends X1 { + X1 xy; + class DeeplyNested extends NestedInX1 { + DeeplyNested(float f) { + Nested.this.x1.super(); + } + } + } + public static void main(String... args) { + Nested nest = new X().new Nested(); + nest.x1 = new X1(); + nest.new DeeplyNested(1.1f); + } + } + class X1 { + X1 x1; + class NestedInX1 {} + } + """ + }; + runner.runConformTest(); + } + + public void testGH3094_3() { + Runner runner = new Runner(false); + runner.testFiles = new String[] { + "X.java", + """ + public class X { + class Nested extends X1 { + X1 xy; + Nested() { + class DeeplyNested extends NestedInX1 { + DeeplyNested(float f) { + Nested.this.x1.super(); + } + } + super(); + } + } + } + class X1 { + X1 x1; + class NestedInX1 {} + } + """ + }; + runner.expectedCompilerLog = + """ + ---------- + 1. WARNING in X.java (at line 5) + class DeeplyNested extends NestedInX1 { + ^^^^^^^^^^^^ + The type DeeplyNested is never used locally + ---------- + 2. ERROR in X.java (at line 7) + Nested.this.x1.super(); + ^^^^^^^^^^^^^^ + Cannot read field x1 in an early construction context + ---------- + """; + runner.runNegativeTest(); + } }