diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java index 1625ab021dc..b5905da4203 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -215,20 +215,7 @@ private TypeBinding internalResolveLeafType(Scope scope, boolean checkBounds) { this.resolvedType = (ReferenceBinding) binding; reportInvalidType(scope); // be resilient, still attempt resolving arguments - for (int i = 0, max = this.tokens.length; i < max; i++) { - TypeReference[] args = this.typeArguments[i]; - if (args != null) { - int argLength = args.length; - for (int j = 0; j < argLength; j++) { - TypeReference typeArgument = args[j]; - if (isClassScope) { - typeArgument.resolveType((ClassScope) scope); - } else { - typeArgument.resolveType((BlockScope) scope, checkBounds); - } - } - } - } + resolveAllTypeArguments(0, scope, checkBounds, isClassScope); return null; } @@ -244,20 +231,7 @@ private TypeBinding internalResolveLeafType(Scope scope, boolean checkBounds) { if (!(this.resolvedType.isValidBinding())) { reportInvalidType(scope); // be resilient, still attempt resolving arguments - for (int j = i; j < max; j++) { - TypeReference[] args = this.typeArguments[j]; - if (args != null) { - int argLength = args.length; - for (int k = 0; k < argLength; k++) { - TypeReference typeArgument = args[k]; - if (isClassScope) { - typeArgument.resolveType((ClassScope) scope); - } else { - typeArgument.resolveType((BlockScope) scope); - } - } - } - } + resolveAllTypeArguments(0, scope, checkBounds, isClassScope); return null; } ReferenceBinding currentType = (ReferenceBinding) this.resolvedType; @@ -310,17 +284,21 @@ private TypeBinding internalResolveLeafType(Scope scope, boolean checkBounds) { } if (isClassScope) { ((ClassScope) scope).superTypeReference = keep; - if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this)) + if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this)) { + resolveAllTypeArguments(i+1, scope, checkBounds, isClassScope); return null; + } } TypeVariableBinding[] typeVariables = currentOriginal.typeVariables(); if (typeVariables == Binding.NO_TYPE_VARIABLES) { // check generic scope.problemReporter().nonGenericTypeCannotBeParameterized(i, this, currentType, argTypes); + resolveAllTypeArguments(i+1, scope, checkBounds, isClassScope); return null; } else if (argLength != typeVariables.length) { if (!isDiamond) { // check arity scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes, i); + resolveAllTypeArguments(i+1, scope, checkBounds, isClassScope); return null; } } @@ -352,8 +330,10 @@ private TypeBinding internalResolveLeafType(Scope scope, boolean checkBounds) { } else { ReferenceBinding currentOriginal = (ReferenceBinding)currentType.original(); if (isClassScope) - if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this)) + if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this)) { + resolveAllTypeArguments(0, scope, checkBounds, isClassScope); return null; + } if (currentOriginal.isGenericType()) { if (typeIsConsistent && qualifyingType != null && qualifyingType.isParameterizedType() && currentOriginal.hasEnclosingInstanceContext()) { scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.environment().createParameterizedType(currentOriginal, null, qualifyingType), i); @@ -372,6 +352,22 @@ private TypeBinding internalResolveLeafType(Scope scope, boolean checkBounds) { } return this.resolvedType; } + private void resolveAllTypeArguments(int from, Scope scope, boolean checkBounds, boolean isClassScope) { + for (int i = from, max = this.tokens.length; i < max; i++) { + TypeReference[] args = this.typeArguments[i]; + if (args != null) { + int argLength = args.length; + for (int j = 0; j < argLength; j++) { + TypeReference typeArgument = args[j]; + if (isClassScope) { + typeArgument.resolveType((ClassScope) scope); + } else { + typeArgument.resolveType((BlockScope) scope, checkBounds); + } + } + } + } + } private void createArrayType(Scope scope) { if (this.dimensions > 0) { if (this.dimensions > 255) diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java index 197f53dd884..42c079eaf23 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java @@ -35345,27 +35345,32 @@ public void test1036() { " ^^^^^^\n" + "The type String is not generic; it cannot be parameterized with arguments \n" + "----------\n" + - "20. ERROR in X.java (at line 10)\n" + + "20. ERROR in X.java (at line 9)\n" + + " String.Y y; // wrong\n" + + " ^^^^\n" + + "List cannot be resolved to a type\n" + + "----------\n" + + "21. ERROR in X.java (at line 10)\n" + " X.Y y1; // wrong\n" + " ^^^^^^^^^^^\n" + "X.Y cannot be resolved to a type\n" + "----------\n" + - "21. ERROR in X.java (at line 10)\n" + + "22. ERROR in X.java (at line 10)\n" + " X.Y y1; // wrong\n" + " ^^^^^^\n" + "Bound mismatch: The type Object is not a valid substitute for the bounded parameter of the type X\n" + "----------\n" + - "22. ERROR in X.java (at line 10)\n" + + "23. ERROR in X.java (at line 10)\n" + " X.Y y1; // wrong\n" + " ^^^^\n" + "List cannot be resolved to a type\n" + "----------\n" + - "23. ERROR in X.java (at line 11)\n" + + "24. ERROR in X.java (at line 11)\n" + " X.Y y2;\n" + " ^^^^^^^^^^^\n" + "X.Y cannot be resolved to a type\n" + "----------\n" + - "24. ERROR in X.java (at line 11)\n" + + "25. ERROR in X.java (at line 11)\n" + " X.Y y2;\n" + " ^^^^\n" + "List cannot be resolved to a type\n" + diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java index ee1133f333d..5e2c4d75f0c 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java @@ -10859,6 +10859,16 @@ public class TestClass implements TestClass.Missing1> { + ^^^^^^^^^^^^^^^^^^ + TestClass.Missing2 cannot be resolved to a type + ---------- + 3. ERROR in TestClass.java (at line 1) + public class TestClass implements TestClass.Missing1> { + ^^^^^^^^^^^^^^^^^^ + TestClass.Missing3 cannot be resolved to a type + ---------- """; runner.runNegativeTest(); } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java index 90f7870a193..34c108018be 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java @@ -10430,4 +10430,64 @@ Implicit super constructor Object() is undefined for default constructor. Must d } runner.runNegativeTest(); } +public void testGH3451() { + Runner runner = new Runner(); + String[] libs = getDefaultClassPaths(); + int len = libs.length; + System.arraycopy(libs, 0, libs = new String[len+1], 0, len); + // contained gh3451/Abstract.class refers to missing super class gh3451.Super + libs[len] = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "gh3451.jar"; + runner.classLibraries = libs; + runner.testFiles = new String[] { + "test/Bug.java", + """ + package test; + + import gh3451.Abstract; + + public class Bug { + class Impl1 extends Abstract<@Annot String> {} + class Impl2 extends Abstract.Nested<@Annot Number> {} + + Abstract a1 = new Impl1(); + Abstract a2 = new Impl2(); + } + """ + }; + runner.expectedCompilerLog = + """ + ---------- + 1. ERROR in test\\Bug.java (at line 6) + class Impl1 extends Abstract<@Annot String> {} + ^^^^^ + The hierarchy of the type Impl1 is inconsistent + ---------- + 2. ERROR in test\\Bug.java (at line 6) + class Impl1 extends Abstract<@Annot String> {} + ^^^^^^^^ + The type gh3451.Super cannot be resolved. It is indirectly referenced from required type gh3451.Abstract + ---------- + 3. ERROR in test\\Bug.java (at line 6) + class Impl1 extends Abstract<@Annot String> {} + ^^^^^ + Annot cannot be resolved to a type + ---------- + 4. ERROR in test\\Bug.java (at line 7) + class Impl2 extends Abstract.Nested<@Annot Number> {} + ^^^^^ + The hierarchy of the type Impl2 is inconsistent + ---------- + 5. ERROR in test\\Bug.java (at line 7) + class Impl2 extends Abstract.Nested<@Annot Number> {} + ^^^^^ + Annot cannot be resolved to a type + ---------- + 6. ERROR in test\\Bug.java (at line 10) + Abstract a2 = new Impl2(); + ^^^^^^^^^^^ + Type mismatch: cannot convert from Bug.Impl2 to Abstract + ---------- + """; + runner.runNegativeTest(); +} } diff --git a/org.eclipse.jdt.core.tests.compiler/workspace/gh3451.jar b/org.eclipse.jdt.core.tests.compiler/workspace/gh3451.jar new file mode 100644 index 00000000000..393b0ad4c7c Binary files /dev/null and b/org.eclipse.jdt.core.tests.compiler/workspace/gh3451.jar differ