diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java index 20486337527..cedb55d18a2 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java @@ -14,6 +14,7 @@ package org.eclipse.jdt.internal.compiler.codegen; import java.text.MessageFormat; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import org.eclipse.jdt.internal.compiler.lookup.Scope; @@ -44,6 +45,9 @@ public class StackMapFrame { */ public boolean adoptStackShape = true; + // if the textually preceding stack frame shape is not adopted, we know nothing about this frame's verification types. + private static final VerificationTypeInfo [] UNKNOWN_STACK_ITEMS = new VerificationTypeInfo[0]; + public StackMapFrame(int initialLocalSize) { this.locals = new VerificationTypeInfo[initialLocalSize]; this.numberOfLocals = -1; @@ -118,6 +122,8 @@ public StackMapFrame duplicate() { final VerificationTypeInfo verificationTypeInfo = this.stackItems[i]; result.stackItems[i] = getCachedValue(cache, verificationTypeInfo); } + } else if (!this.adoptStackShape) { + result.stackItems = UNKNOWN_STACK_ITEMS; } return result; } @@ -404,6 +410,8 @@ public StackMapFrame merge(StackMapFrame frame, Scope scope) { for (int i = 0, max = this.numberOfStackItems; i < max; i++) { this.stackItems[i] = this.stackItems[i].merge(frame.stackItems[i], scope); } + } else if (this.stackItems == UNKNOWN_STACK_ITEMS) { + this.stackItems = Arrays.copyOf(frame.stackItems, this.numberOfStackItems = frame.numberOfStackItems); } return this; } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java index c135cb4e7e1..280ebf3ad4f 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java @@ -8604,4 +8604,71 @@ private static BigDecimal unusedMethod2(BigDecimal value, BigDecimal otherValue) }, ""); } + + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/5201 + // VerifyError: Instruction type does not match stack map with for loop in switch + public void testIssue5201() { + this.runConformTest( + new String[] { + "X.java", + """ + public class X { + public static void main(String[] args) { + System.out.println(10 + switch ("B") { + default -> { + for (int i = 0; i < 10; i++) + System.out.println(i); + yield "A"; + } + case "B" -> "B"; + }); + } + } + """ + }, + "10B"); + } + + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/5201 + // VerifyError: Instruction type does not match stack map with for loop in switch + public void testIssue5201_full() { + this.runConformTest( + new String[] { + "X.java", + """ + import java.util.Collection; + import java.util.Set; + + public class X { + + public static class Dummy { + + } + + public static class ExtendedDummy extends Dummy { + + } + + public static void main(String[] args) { + test(ExtendedDummy.class, switch ("B") { + case "A" -> { + for (int i = 0; i < 10; i++) + System.out.println(i); + + yield Set.of("NoopA"); + } + case "B" -> Set.of("NoopB"); + default -> throw new IllegalArgumentException(); + }); + } + + public static void test(Class cls, Collection entities) { + entities.forEach(e -> System.out.println(e)); + } + } + """ + }, + "NoopB"); + } + } \ No newline at end of file