From 2e92ca9b256866523cf5847396e5e9005a93316c Mon Sep 17 00:00:00 2001 From: Srikanth Sankaran Date: Fri, 14 Nov 2025 08:03:47 +0530 Subject: [PATCH] Inconsistent classfile encountered on annotated generic types * Fixes https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4622 --- .../compiler/lookup/SourceTypeBinding.java | 2 +- .../core/tests/builder/IncrementalTests.java | 54 +++++++++++++ .../RecordsRestrictedClassTest.java | 78 +++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java index 5eb64c1256e..b24400ece09 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java @@ -2474,7 +2474,7 @@ public RecordComponentBinding[] setComponents(RecordComponentBinding[] component for (RecordComponentBinding component : components) { for (FieldBinding field : this.fields) { - if (CharOperation.equals(field.name, component.name) && field.type == null) { // field got built before record component resolution + if (CharOperation.equals(field.name, component.name)) { // field got built before record component resolution field.type = component.type; field.modifiers |= component.modifiers & ExtraCompilerModifiers.AccGenericSignature; field.tagBits |= component.tagBits & (TagBits.AnnotationNullMASK | TagBits.AnnotationOwningMASK); diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/IncrementalTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/IncrementalTests.java index e8156913b02..722e6ae161a 100644 --- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/IncrementalTests.java +++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/IncrementalTests.java @@ -1781,4 +1781,58 @@ public Request(String id, T payload) { env.removeProject(projectPath); } + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4622 + // Inconsistent classfile encountered on annotated generic types + public void testIssue4622() throws JavaModelException { + IPath projectPath = env.addProject("Project", "19"); + env.addExternalJars(projectPath, Util.getJavaClassLibs()); + + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(projectPath, ""); + + IPath root = env.addPackageFragmentRoot(projectPath, "src"); + env.setOutputFolder(projectPath, "bin"); + + env.addClass(root, "", "Record", + """ + import java.lang.annotation.Target; + + public record Record( + Patch<@ValidUrlTemplate(value = UrlValidationType.AA, message = "{}") String> labelUrl) { + } + + class Patch { + public T field; + } + + enum UrlValidationType { + AA, BB + } + + @Target(java.lang.annotation.ElementType.TYPE_USE) + @interface ValidUrlTemplate { + UrlValidationType value(); + String message(); + } + """); + fullBuild(projectPath); + expectingNoProblems(); + + env.addClass(root, "", "Driver", + """ + public class Driver { + public Record r; + + public static void main(String [] args) { + System.out.println("OK!"); + } + } + """); + + incrementalBuild(projectPath); + expectingNoProblems(); + + env.removeProject(projectPath); + } + } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java index 52662a99eb9..3fe309c7499 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java @@ -11610,4 +11610,82 @@ enum RequiredMode { " )\n"; verifyClassFile(expectedOutput, "test/Broken.class", ClassFileBytesDisassembler.SYSTEM); } +// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4622 +// Inconsistent classfile encountered on annotated generic types +public void testIssue4622() throws Exception { + this.runConformTest( + new String[] { + "test/Record.java", + """ + package test; + + import java.lang.annotation.Target; + + public record Record( + Patch<@ValidUrlTemplate(value = UrlValidationType.AA, message = "{}") String> labelUrl) { + + public static void main(String [] args) { + System.out.println("OK!"); + } + } + + class Patch { + public T field; + } + + enum UrlValidationType { + AA, BB + } + + @Target(java.lang.annotation.ElementType.TYPE_USE) + @interface ValidUrlTemplate { + UrlValidationType value(); + String message(); + } + """, + }, + "OK!"); + String expectedOutput = + " // Field descriptor #6 Ltest/Patch;\n" + + " // Signature: Ltest/Patch;\n" + + " private final test.Patch labelUrl;\n" + + " RuntimeInvisibleTypeAnnotations: \n" + + " #10 @test.ValidUrlTemplate(\n" + + " #11 value=test.UrlValidationType.AA(enum type #12.#13)\n" + + " #14 message=\"{}\" (constant type)\n" + + " target type = 0x13 FIELD\n" + + " location = [TYPE_ARGUMENT(0)]\n" + + " )\n" + + " \n" + + " // Method descriptor #17 ([Ljava/lang/String;)V\n" + + " // Stack: 2, Locals: 1\n" + + " public static void main(java.lang.String[] args);\n" + + " 0 getstatic java.lang.System.out : java.io.PrintStream [19]\n" + + " 3 ldc [25]\n" + + " 5 invokevirtual java.io.PrintStream.println(java.lang.String) : void [27]\n" + + " 8 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 9]\n" + + " [pc: 8, line: 10]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 9] local: args index: 0 type: java.lang.String[]\n" + + " \n" + + " // Method descriptor #37 ()Ltest/Patch;\n" + + " // Signature: ()Ltest/Patch;\n" + + " // Stack: 1, Locals: 1\n" + + " public test.Patch labelUrl();\n" + + " 0 aload_0 [this]\n" + + " 1 getfield test.Record.labelUrl : test.Patch [39]\n" + + " 4 areturn\n" + + " Line numbers:\n" + + " [pc: 0, line: 6]\n" + + " RuntimeInvisibleTypeAnnotations: \n" + + " #10 @test.ValidUrlTemplate(\n" + + " #11 value=test.UrlValidationType.AA(enum type #12.#13)\n" + + " #14 message=\"{}\" (constant type)\n" + + " target type = 0x14 METHOD_RETURN\n" + + " location = [TYPE_ARGUMENT(0)]\n" + + " )"; + verifyClassFile(expectedOutput, "test/Record.class", ClassFileBytesDisassembler.SYSTEM); +} } \ No newline at end of file