Light Mode

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

GROOVY-9381: Add native async/await support#2387

Open
daniellansun wants to merge 1 commit intomasterfrom
GROOVY-9381_3
Open

GROOVY-9381: Add native async/await support#2387
daniellansun wants to merge 1 commit intomasterfrom
GROOVY-9381_3

Conversation

Copy link
Contributor

daniellansun commented Mar 1, 2026 *
edited
Loading

daniellansun mentioned this pull request Mar 1, 2026
daniellansun requested review from blackdrag and paulk-asert March 1, 2026 17:52
daniellansun self-assigned this Mar 1, 2026
daniellansun requested a review from glaforge March 1, 2026 18:15
Copy link

codecov-commenter commented Mar 1, 2026 *
edited
Loading

Codecov Report

Patch coverage is 89.16563% with 87 lines in your changes missing coverage. Please review.
Project coverage is 67.3514%. Comparing base (7d8349c) to head (9124f63).
Report is 12 commits behind head on master.

Files with missing lines Patch % Lines
.../org/apache/groovy/runtime/async/AsyncSupport.java 88.3895% 17 Missing and 14 partials
...va/groovy/concurrent/AwaitableAdapterRegistry.java 84.8921% 7 Missing and 14 partials
...ehaus/groovy/transform/AsyncASTTransformation.java 82.2917% 6 Missing and 11 partials
...che/groovy/runtime/async/AsyncStreamGenerator.java 88.3721% 3 Missing and 7 partials
...odehaus/groovy/transform/AsyncTransformHelper.java 93.9394% 0 Missing and 4 partials
...va/org/apache/groovy/parser/antlr4/AstBuilder.java 95.8333% 3 Missing
...org/apache/groovy/runtime/async/GroovyPromise.java 96.2963% 0 Missing and 1 partial
Additional details and impacted files

@@ Coverage Diff @@
## master #2387 +/- ##
==================================================
+ Coverage 66.7571% 67.3514% +0.5943%
- Complexity 29856 31353 +1497
==================================================
Files 1382 1392 +10
Lines 116130 118679 +2549
Branches 20471 21511 +1040
==================================================
+ Hits 77525 79932 +2407
- Misses 32275 32384 +109
- Partials 6330 6363 +33
Files with missing lines Coverage D
src/main/java/groovy/concurrent/AsyncStream.java 100.0000% <100.0000%> (o)
src/main/java/groovy/concurrent/AwaitResult.java 100.0000% <100.0000%> (o)
src/main/java/groovy/concurrent/Awaitable.java 100.0000% <100.0000%> (o)
.../main/java/groovy/concurrent/AwaitableAdapter.java 100.0000% <100.0000%> (o)
...g/apache/groovy/parser/antlr4/ModifierManager.java 93.4210% <100.0000%> (o)
...ain/java/org/codehaus/groovy/ast/ModifierNode.java 77.7778% <100.0000%> (+0.4193%)
...org/apache/groovy/runtime/async/GroovyPromise.java 96.2963% <96.2963%> (o)
...va/org/apache/groovy/parser/antlr4/AstBuilder.java 86.8007% <95.8333%> (+0.2935%)
...odehaus/groovy/transform/AsyncTransformHelper.java 93.9394% <93.9394%> (o)
...che/groovy/runtime/async/AsyncStreamGenerator.java 88.3721% <88.3721%> (o)
... and 3 more

... and 14 files with indirect coverage changes

New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

asf-gitbox-commits force-pushed the GROOVY-9381_3 branch 19 times, most recently from ec35b7d to 5f8acbb Compare March 7, 2026 16:53
daniellansun requested a review from Copilot March 7, 2026 17:49
Copilot started reviewing on behalf of daniellansun March 7, 2026 17:50 View session
Copilot AI reviewed Mar 7, 2026
Copy link

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 implements GROOVY-9381 by adding native async/await syntax to the Groovy language (including for await, yield return async generators, and defer), plus runtime support and extensive documentation/tests.

Changes:

  • Extend the Groovy grammar + AST builder to parse/compile async, await, for await, yield return, and defer.
  • Add/extend runtime primitives (Awaitable, AsyncStream, adapters/registry, promise + generator implementation) and @Async AST transformation support.
  • Add comprehensive tests and new spec documentation; add Reactor/RxJava test dependencies for adapter interop coverage.

Reviewed changes

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

Show a summary per file
File Description
versions.properties Adds version pins for Reactor and RxJava3 used by new integration tests.
build.gradle Adds Reactor/RxJava3 as testImplementation dependencies.
gradle/verification-metadata.xml Adds verification metadata entries for new test dependencies.
src/antlr/GroovyLexer.g4 Introduces lexer tokens for async, await, defer.
src/antlr/GroovyParser.g4 Adds grammar support for async closure/lambda, await expressions, for await, yield return, and defer.
src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java Lowers new syntax into runtime calls (e.g., AsyncSupport.await, stream conversion/cleanup, defer, yieldReturn).
src/main/java/org/codehaus/groovy/ast/ModifierNode.java Treats ASYNC as a non-bytecode modifier (opcode 0).
src/main/java/org/codehaus/groovy/transform/AsyncTransformHelper.java Centralizes AST construction + scanning/rewriting for async constructs.
src/main/java/org/codehaus/groovy/transform/AsyncASTTransformation.java Implements @Async transformation using shared helper logic (await rewrite, generator/defer handling).
src/main/java/groovy/transform/Async.java Adds @Async annotation and documentation.
src/main/java/groovy/concurrent/* Adds new async public API (Awaitable, AsyncStream, adapters/registry, AwaitResult).
src/main/java/org/apache/groovy/runtime/async/* Adds runtime implementations (GroovyPromise, AsyncStreamGenerator) used by compiler output.
src/spec/doc/core-async-await.adoc Adds user-facing language documentation/spec for async/await.
src/test/groovy/org/codehaus/groovy/transform/* Adds extensive test coverage for async/await, generators, defer, adapters, and virtual threads.

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

| VOLATILE
| DEF
| VAR
| ASYNC
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

Adding ASYNC to the general modifier rule means async can now appear anywhere modifiers are allowed (e.g., on fields, variables, classes) and will likely be silently ignored (since it maps to opcode 0). If async is intended to be a method-only modifier, consider restricting it in the grammar or adding a parse/semantic error when async is used in unsupported contexts, to avoid misleading code compiling without effect.

Suggested change
| ASYNC

Copilot uses AI. Check for mistakes.
Comment on lines +153 to +158
def customPool = Executors.newFixedThreadPool(2, { r ->
def t = new Thread(r)
t.setName("custom-async-" + t.getId())
t
})
Awaitable.setExecutor(customPool)
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

The custom fixed thread pool created here is never shut down. Since the thread factory creates non-daemon threads, this can leak threads and potentially hang the test JVM. Please ensure the executor is shut down (preferably in the existing finally block) after restoring the previous executor.

Copilot uses AI. Check for mistakes.
Comment on lines +180 to +190
Awaitable.setExecutor(Executors.newSingleThreadExecutor())
assert Awaitable.getExecutor() != originalExecutor
// Reset to null -- should restore default
Awaitable.setExecutor(null)
def restored = Awaitable.getExecutor()
assert restored != null
// Verify it works
def task = async { 42 }; def awaitable = task()
assert await(awaitable) == 42
// Restore original
Awaitable.setExecutor(originalExecutor)
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

This test sets the global executor to a newSingleThreadExecutor but never shuts that executor down. Even though the executor is reset to null later, the underlying thread can remain alive and leak across the suite. Please shut down the created executor (e.g., keep a reference and shutdown in a finally block).

Suggested change
Awaitable.setExecutor(Executors.newSingleThreadExecutor())
assert Awaitable.getExecutor() != originalExecutor
// Reset to null -- should restore default
Awaitable.setExecutor(null)
def restored = Awaitable.getExecutor()
assert restored != null
// Verify it works
def task = async { 42 }; def awaitable = task()
assert await(awaitable) == 42
// Restore original
Awaitable.setExecutor(originalExecutor)
def customExecutor = Executors.newSingleThreadExecutor()
try {
Awaitable.setExecutor(customExecutor)
assert Awaitable.getExecutor() != originalExecutor
// Reset to null -- should restore default
Awaitable.setExecutor(null)
def restored = Awaitable.getExecutor()
assert restored != null
// Verify it works
def task = async { 42 }; def awaitable = task()
assert await(awaitable) == 42
} finally {
// Restore original and shut down custom executor to avoid thread leaks
Awaitable.setExecutor(originalExecutor)
customExecutor.shutdown()
}

Copilot uses AI. Check for mistakes.
Comment on lines +202 to +207
static Executor myPool = Executors.newFixedThreadPool(1, { r ->
def t = new Thread(r)
t.setName("my-pool-thread")
t
})

Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

The static Executor created via Executors.newFixedThreadPool uses non-daemon threads and is never shut down. This can leak threads for the remainder of the test run and may prevent the JVM from exiting. Consider using daemon threads (as other tests do) and/or explicitly shutting down the pool at the end of the script.

Copilot uses AI. Check for mistakes.
asf-gitbox-commits force-pushed the GROOVY-9381_3 branch 2 times, most recently from c3808d6 to 1afcb33 Compare March 8, 2026 05:25
asf-gitbox-commits force-pushed the GROOVY-9381_3 branch 5 times, most recently from 7dde6e5 to 9124f63 Compare March 10, 2026 16:53
daniellansun changed the title GROOVY-9381: Support async/await like ES7 GROOVY-9381: Add native async/await support Mar 10, 2026
asf-gitbox-commits force-pushed the GROOVY-9381_3 branch from 9124f63 to 5df6414 Compare March 10, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

Copilot code review Copilot Copilot left review comments

paulk-asert Awaiting requested review from paulk-asert

blackdrag Awaiting requested review from blackdrag

glaforge Awaiting requested review from glaforge

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

3 participants