Skip to content

GROOVY-10156: Unreachable bytecode in switch statement#2538

Open
daniellansun wants to merge 1 commit into
masterfrom
GROOVY-10156
Open

GROOVY-10156: Unreachable bytecode in switch statement#2538
daniellansun wants to merge 1 commit into
masterfrom
GROOVY-10156

Conversation

@daniellansun
Copy link
Copy Markdown
Contributor

No description provided.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses GROOVY-10156 by refining switch bytecode generation to avoid synthetic unreachable fall-through jumps and adding regression coverage around switch control-flow cases.

Changes:

  • Adds switch fall-through analysis for cases, labels, try/finally, synchronized blocks, and nested switches.
  • Updates switch and synchronized bytecode emission to skip unnecessary labels/jumps.
  • Adds bytecode-focused regression tests for enum switches and labeled switch scenarios.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java Uses switch flow analysis to avoid emitting unnecessary case/default jump targets and synchronized fall-through jumps.
src/main/java/org/codehaus/groovy/classgen/asm/CompileStack.java Adds switch label registration for named break targets.
src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java Implements switch fall-through analysis helpers.
src/test/groovy/bugs/Groovy10156.groovy Adds regression tests checking for absence of the unreachable bytecode sequence.

Comment on lines +1331 to +1332
if (localLabels.contains(label)) {
return SwitchFlow.FALL_THROUGH;
Comment on lines +1364 to +1369
return SwitchFlow.of(maybeFallsThroughSwitch(switchStatement), false);
}

return SwitchFlow.of(maybeFallsThrough(statement), false);
}

Comment thread src/test/groovy/bugs/Groovy10156.groovy Outdated
Comment on lines +421 to +423
private void assertNoUnreachableSequenceInTestMethod(final String source) {
def bytecode = compile(classNamePattern: 'C', method: 'test', source)
assert !bytecode.hasStrictSequence(UNREACHABLE_SEQUENCE)
@asf-gitbox-commits asf-gitbox-commits force-pushed the GROOVY-10156 branch 5 times, most recently from 1cafcc0 to 06dcecf Compare May 17, 2026 07:47
@sonarqubecloud
Copy link
Copy Markdown

@testlens-app
Copy link
Copy Markdown

testlens-app Bot commented May 17, 2026

🚨 TestLens detected 49 failed tests 🚨

Here is what you can do:

  1. Inspect the test failures carefully.
  2. If you are convinced that some of the tests are flaky, you can mute them below.
  3. Finally, trigger a rerun by checking the rerun checkbox.

Test Summary

Check Project/Task Test Runs
Build and test / lts (17, macos-latest) :test AsyncAwaitTest > testAwaitPlainFutureWithExceptionUnwrap()
Build and test / lts (17, macos-latest) :test AsyncAwaitTest > testAwaitPlainFutureWithExceptionUnwrap()
Build and test / lts (17, macos-latest) :test AsyncAwaitTest > testBuiltInAdapterPlainFutureExecutionException()
Build and test / lts (17, macos-latest) :test AsyncAwaitTest > testBuiltInAdapterPlainFutureExecutionException()
Build and test / lts (17, macos-latest) :test AsyncAwaitTest > testBuiltInAdapterPlainFutureWithError()
Build and test / lts (17, macos-latest) :test AsyncAwaitTest > testBuiltInAdapterPlainFutureWithError()
Build and test / lts (17, macos-latest) :test Groovy11362 > testCatchException()
Build and test / lts (17, macos-latest) :test Groovy11362 > testCatchException()
Build and test / lts (17, macos-latest) :test Groovy8229Bug > testFinallyBlockInClosureCalledOnce()
Build and test / lts (17, macos-latest) :test Groovy8229Bug > testFinallyBlockInClosureCalledOnce()
Build and test / lts (17, macos-latest) :test Groovy9805 > testSameLineAssignments2()
Build and test / lts (17, macos-latest) :test Groovy9805 > testSameLineAssignments2()
Build and test / lts (17, macos-latest) :test Groovy9805 > testSameLineAssignments3()
Build and test / lts (17, macos-latest) :test Groovy9805 > testSameLineAssignments3()
Build and test / lts (17, macos-latest) :test Groovy9805 > testSameLineAssignments4()
Build and test / lts (17, macos-latest) :test Groovy9805 > testSameLineAssignments4()
Build and test / lts (17, ubuntu-latest) :test Groovy11362 > testCatchException()
Build and test / lts (17, ubuntu-latest) :test Groovy11362 > testCatchException()
Build and test / lts (17, ubuntu-latest) :test Groovy8229Bug > testFinallyBlockInClosureCalledOnce()
Build and test / lts (17, ubuntu-latest) :test Groovy8229Bug > testFinallyBlockInClosureCalledOnce()
Build and test / lts (17, ubuntu-latest) :test Groovy9805 > testSameLineAssignments2()
Build and test / lts (17, ubuntu-latest) :test Groovy9805 > testSameLineAssignments2()
Build and test / lts (17, ubuntu-latest) :test Groovy9805 > testSameLineAssignments3()
Build and test / lts (17, ubuntu-latest) :test Groovy9805 > testSameLineAssignments3()
Build and test / lts (17, ubuntu-latest) :test Groovy9805 > testSameLineAssignments4()
Build and test / lts (17, ubuntu-latest) :test Groovy9805 > testSameLineAssignments4()
Build and test / lts (21, ubuntu-latest) :test Groovy11362 > testCatchException()
Build and test / lts (21, ubuntu-latest) :test Groovy11362 > testCatchException()
Build and test / lts (21, ubuntu-latest) :test Groovy8229Bug > testFinallyBlockInClosureCalledOnce()
Build and test / lts (21, ubuntu-latest) :test Groovy8229Bug > testFinallyBlockInClosureCalledOnce()
Build and test / lts (21, ubuntu-latest) :test Groovy9805 > testSameLineAssignments2()
Build and test / lts (21, ubuntu-latest) :test Groovy9805 > testSameLineAssignments2()
Build and test / lts (21, ubuntu-latest) :test Groovy9805 > testSameLineAssignments3()
Build and test / lts (21, ubuntu-latest) :test Groovy9805 > testSameLineAssignments3()
Build and test / lts (21, ubuntu-latest) :test Groovy9805 > testSameLineAssignments4()
Build and test / lts (21, ubuntu-latest) :test Groovy9805 > testSameLineAssignments4()
Build and test / lts (25, ubuntu-latest) :test AsyncAwaitTest > testAwaitPlainFutureWithExceptionUnwrap()
Build and test / lts (25, ubuntu-latest) :test AsyncAwaitTest > testBuiltInAdapterPlainFutureExecutionException()
Build and test / lts (25, ubuntu-latest) :test AsyncAwaitTest > testBuiltInAdapterPlainFutureWithError()
Build and test / lts (25, ubuntu-latest) :test Groovy11362 > testCatchException()
Build and test / lts (25, ubuntu-latest) :test Groovy11362 > testCatchException()
Build and test / lts (25, ubuntu-latest) :test Groovy8229Bug > testFinallyBlockInClosureCalledOnce()
Build and test / lts (25, ubuntu-latest) :test Groovy8229Bug > testFinallyBlockInClosureCalledOnce()
Build and test / lts (25, ubuntu-latest) :test Groovy9805 > testSameLineAssignments2()
Build and test / lts (25, ubuntu-latest) :test Groovy9805 > testSameLineAssignments2()
Build and test / lts (25, ubuntu-latest) :test Groovy9805 > testSameLineAssignments3()
Build and test / lts (25, ubuntu-latest) :test Groovy9805 > testSameLineAssignments3()
Build and test / lts (25, ubuntu-latest) :test Groovy9805 > testSameLineAssignments4()
Build and test / lts (25, ubuntu-latest) :test Groovy9805 > testSameLineAssignments4()

🏷️ Commit: d4955f0
▶️ Tests: 56091 executed
⚪️ Checks: 56/56 completed

Test Failures (first 5 of 49)

AsyncAwaitTest > testAwaitPlainFutureWithExceptionUnwrap() (:test in Build and test / lts (17, macos-latest))
java.lang.RuntimeException: future-err
	at TestScript195$_run_closure1.doCall(TestScript195.groovy:7)
	at TestScript195$_run_closure1.doCall(TestScript195.groovy)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:502)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:298)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1090)
	at groovy.lang.Closure.call(Closure.java:557)
	at groovy.lang.Closure.call(Closure.java:511)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)
AsyncAwaitTest > testAwaitPlainFutureWithExceptionUnwrap() (:test in Build and test / lts (17, macos-latest))
java.lang.RuntimeException: future-err
	at TestScript195$_run_closure1.doCall(TestScript195.groovy:7)
	at TestScript195$_run_closure1.doCall(TestScript195.groovy)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:502)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:298)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1090)
	at groovy.lang.Closure.call(Closure.java:557)
	at groovy.lang.Closure.call(Closure.java:511)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)
AsyncAwaitTest > testBuiltInAdapterPlainFutureExecutionException() (:test in Build and test / lts (17, macos-latest))
java.lang.IllegalStateException: plain-future-ex
	at TestScript262$_run_closure1.doCall(TestScript262.groovy:8)
	at TestScript262$_run_closure1.doCall(TestScript262.groovy)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:502)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:298)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1090)
	at groovy.lang.Closure.call(Closure.java:557)
	at groovy.lang.Closure.call(Closure.java:511)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)
AsyncAwaitTest > testBuiltInAdapterPlainFutureExecutionException() (:test in Build and test / lts (17, macos-latest))
java.lang.IllegalStateException: plain-future-ex
	at TestScript262$_run_closure1.doCall(TestScript262.groovy:8)
	at TestScript262$_run_closure1.doCall(TestScript262.groovy)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:502)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:298)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1090)
	at groovy.lang.Closure.call(Closure.java:557)
	at groovy.lang.Closure.call(Closure.java:511)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)
AsyncAwaitTest > testBuiltInAdapterPlainFutureWithError() (:test in Build and test / lts (17, macos-latest))
java.lang.RuntimeException: adapt-err
	at TestScript271$_run_closure1.doCall(TestScript271.groovy:8)
	at TestScript271$_run_closure1.doCall(TestScript271.groovy)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:502)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:298)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1090)
	at groovy.lang.Closure.call(Closure.java:557)
	at groovy.lang.Closure.call(Closure.java:511)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)

Muted Tests

Select tests to mute in this pull request:

  • AsyncAwaitTest > testAwaitPlainFutureWithExceptionUnwrap()
  • AsyncAwaitTest > testBuiltInAdapterPlainFutureExecutionException()
  • AsyncAwaitTest > testBuiltInAdapterPlainFutureWithError()
  • Groovy11362 > testCatchException()
  • Groovy8229Bug > testFinallyBlockInClosureCalledOnce()
  • Groovy9805 > testSameLineAssignments2()
  • Groovy9805 > testSameLineAssignments3()
  • Groovy9805 > testSameLineAssignments4()

Reuse successful test results:

  • ♻️ Only rerun the tests that failed or were muted before

Click the checkbox to trigger a rerun:

  • Rerun jobs

Learn more about TestLens at testlens.app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants