[
https://issues.apache.org/jira/browse/GROOVY-12181?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Paul King resolved GROOVY-12181.
--------------------------------
Assignee: Daniel Sun
Resolution: Fixed
> Refactor async runtime and AST helpers introduced by GROOVY-9381
> ----------------------------------------------------------------
>
> Key: GROOVY-12181
> URL: https://issues.apache.org/jira/browse/GROOVY-12181
> Project: Groovy
> Issue Type: Improvement
> Reporter: Daniel Sun
> Assignee: Daniel Sun
> Priority: Major
>
> h2. Context
> GROOVY-9381 landed native {{async}}/{{await}}/{{defer}}: public API in
> {{groovy.concurrent}}, runtime in {{org.apache.groovy.runtime.async}}, and
> parser desugaring via {{AstBuilder}} + {{AsyncTransformHelper}}.
> The first implementation correctly prioritised a working feature, but two
> types accumulated too many responsibilities:
> * {{AsyncSupport}} — executor/scheduler setup, all {{await}} overloads, task
> launch, combinators ({{all}}/{{any}}/{{first}}/{{allSettled}}), defer scopes,
> and generator bridges
> * {{AstBuilder}} — multi-step rewrites for {{for await}} and {{async}}
> closures inlined next to general parse-tree walking
> This ticket covers a focused refactor of that code: clearer module
> boundaries, a thinner parser visitor, small API/docs polish, and unit tests
> for the extracted pieces. *No new language syntax.*
> h2. Goals
> # Single responsibility for runtime pieces (entry point vs pool config vs
> combinators).
> # Keep feature-specific AST rewrites out of {{AstBuilder}}; helpers own the
> desugaring.
> # Preserve the public {{groovy.concurrent}} surface and combinator *names*.
> # Make executor reset behaviour and generated {{await}} dispatch explicit and
> tested.
> h2. Changes
> h3. Runtime split (package-private)
> ||Concern||Before||After||
> |Entry point|{{AsyncSupport}} (monolith)|{{AsyncSupport}} — facade used by
> compiler-generated code and {{Awaitable}}|
> |Executors / scheduler|embedded in {{AsyncSupport}}|{{AsyncExecutors}}
> (package-private)|
> |Combinators|embedded in {{AsyncSupport}}|{{AwaitCombinators}} ({{all}},
> {{any}}, {{first}}, {{allSettled}}; package-private)|
> Public methods on {{AsyncSupport}} / {{Awaitable}} remain the stable surface;
> algorithms and pool wiring move behind package-private types. Package-info
> under {{groovy.concurrent}} and {{org.apache.groovy.runtime.async}} updated
> to match.
> h3. AST / parser
> Higher-level rewrites move from {{AstBuilder}} into {{AsyncTransformHelper}}:
> * {{transformAsyncClosure}} — defer-scope wrap, generator param injection,
> {{async}} / {{asyncGenerator}} call
> * {{wrapForAwaitLoop}} — {{toIterable}} + {{try}}/{{finally}}
> {{closeIterable}}
> {{AstBuilder}} only dispatches (one call site per construct).
> Related codegen polish in the same pass:
> * Single-arg {{await}} still targets {{AsyncSupport.await(Object)}} by
> inserting a cast to {{Object}} on the argument. That avoids overload
> ambiguity when a value implements several async interfaces (e.g.
> {{CompletableFuture}} as both {{CompletionStage}} and {{Future}}). No extra
> public entry point.
> * {{for await}} temps use {{$__forAwaitSource_N}} (monotonic counter) instead
> of a name derived from parse-context {{hashCode()}}, avoiding synthetic-name
> clashes across nested/repeated loops.
> h3. Small API / docs polish
> * {{AsyncSupport.setExecutor(null)}} / {{Awaitable.setExecutor(null)}} —
> restore the platform default (same as {{resetExecutor()}}). Previously
> {{null}} was rejected.
> * {{AwaitResult.success(T)}} — typed parameter (was {{Object}} + unchecked
> cast).
> * Javadoc for {{Awaitable.first}} all-fail path aligned with the existing
> aggregate {{CompletionException}} behaviour (cause = first failure; remaining
> as suppressed; {{await}} transparency rethrows the cause). *Exception shape
> unchanged.*
> * Spec doc ({{core-async-await.adoc}}) shows {{setExecutor(null)}} as the
> reset form alongside {{resetExecutor()}}.
> * Stale {{AsyncContext}} mentions removed from {{GroovyPromise}} continuation
> Javadoc.
> h3. Tests
> * {{AsyncSupportInternalsTest}} — runtime split, combinators, executor reset,
> defer scope, generators
> * {{AsyncTransformHelperTest}} — AST builders, {{Object}} cast on single-arg
> {{await}}, unique {{for await}} temps
> * {{AwaitResultTest}} — equality / success typing
> * Additional cases in {{AsyncAwaitTest}} ({{setExecutor(null)}},
> {{await(Object)}} fallback)
> h2. Compatibility
> * Follow-up to GROOVY-9381; intended for the 6.0 async feature line.
> * {{setExecutor(null)}} is no longer an error; it resets to the platform
> default.
> * Combinator *names* and the public package layout ({{groovy.concurrent}})
> are unchanged.
> * {{Awaitable.first}} all-fail path remains an aggregate
> {{CompletionException}} (no change to exception type).
> * Generated single-arg {{await}} remains a call to {{AsyncSupport.await}}
> with an {{Object}} cast (no new public API surface).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)