Dark 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: Support async/await like ES7#2387

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

GROOVY-9381: Support async/await like ES7#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 87.89407% with 96 lines in your changes missing coverage. Please review.
Project coverage is 67.2694%. Comparing base (7d8349c) to head (5f8acbb).
Report is 1 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 80.2083% 8 Missing and 11 partials
...che/groovy/runtime/async/AsyncStreamGenerator.java 81.4815% 5 Missing and 10 partials
...odehaus/groovy/transform/AsyncTransformHelper.java 93.9394% 0 Missing and 4 partials
...org/apache/groovy/runtime/async/GroovyPromise.java 88.8889% 2 Missing and 1 partial
src/main/java/groovy/concurrent/Awaitable.java 91.6667% 2 Missing
...va/org/apache/groovy/parser/antlr4/AstBuilder.java 98.5294% 1 Missing
Additional details and impacted files

@@ Coverage Diff @@
## master #2387 +/- ##
==================================================
+ Coverage 66.7571% 67.2694% +0.5123%
- Complexity 29856 31196 +1340
==================================================
Files 1382 1392 +10
Lines 116130 118238 +2108
Branches 20471 21355 +884
==================================================
+ Hits 77525 79538 +2013
- Misses 32275 32337 +62
- 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)
.../main/java/groovy/concurrent/AwaitableAdapter.java 100.0000% <100.0000%> (o)
...ain/java/org/codehaus/groovy/ast/ModifierNode.java 77.7778% <100.0000%> (+0.4193%)
...va/org/apache/groovy/parser/antlr4/AstBuilder.java 86.8652% <98.5294%> (+0.3579%)
src/main/java/groovy/concurrent/Awaitable.java 91.6667% <91.6667%> (o)
...org/apache/groovy/runtime/async/GroovyPromise.java 88.8889% <88.8889%> (o)
...odehaus/groovy/transform/AsyncTransformHelper.java 93.9394% <93.9394%> (o)
...che/groovy/runtime/async/AsyncStreamGenerator.java 81.4815% <81.4815%> (o)
...ehaus/groovy/transform/AsyncASTTransformation.java 80.2083% <80.2083%> (o)
... and 2 more

... and 6 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 18 times, most recently from 5b87db0 to ec35b7d Compare March 7, 2026 16:50
asf-gitbox-commits force-pushed the GROOVY-9381_3 branch 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.
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