I haven't tried to track down the cause but I created this:
https://issues.apache.org/jira/browse/GROOVY-12117
https://github.com/apache/groovy/pull/2644
AI's read of your comments Eric below:
Yes — Eric is correct about what that block *does*, but it's
describing the **consumer**, not the site of the order-dependence. Two
clarifications worth making, and he's right about
`@DelegatesTo.Target`.
## Where Eric is right
That block in `TraitTypeCheckingExtension.handleMissingMethod` is
exactly the STC resolver for an inherited super-trait static, and his
read of the `(Object)` cast is the correct historical explanation: the
version he pasted uses exact-match `getDeclaredMethod(name,
signature)`, so an argument whose static type was a *subtype* of the
declared `Object delegate` (e.g. `Field`) didn't match — you cast to
`Object` to hit the declared signature.
## Two clarifications
**1. He's quoting the pre-12106 snippet.** On the `groovy12117` branch
(post-`b7796c3f9b`) that block no longer does exact-match — it builds
the helper's static candidates and runs `chooseBestMethod` for
subtype-aware resolution (`TraitTypeCheckingExtension.java:127-146`).
So the `(Object)` cast is no longer needed *for resolution*; a raw
`Field` arg resolves directly — my regression test passes one with no
cast.
**2. This block is not where 12117 lives — it's downstream of it.**
The guard at line 123 is `argumentTypes.length > 0 &&
ClassHelper.isClassType(argumentTypes[0])`. It only fires once the
call already carries the synthetic `$static$self` Class as arg 0 —
i.e. *after* `TraitReceiverTransformer.findConcreteMethod` (transform
phase) has rewritten `withDelegate(closure, f)` into
`this.withDelegate($static$self, closure, f)`. In the sub-trait-first
ordering that rewrite never happens (the super-trait's helper is still
an empty stub when the sub-trait is lowered, so `findConcreteMethod`
returns null), so the call reaches `handleMissingMethod` as
`withDelegate(Closure, Field)` — arg 0 is `Closure`, the
`isClassType(argumentTypes[0])` guard is **false**, the whole block is
skipped, and you get the plain `Cannot find matching method
Arguable#withDelegate(Closure, Field)`. That's exactly the observed
error.
So this block can't be the fix point — it's already order-independent
(it runs after every trait is lowered). The order-dependence is one
phase earlier, which is why the fix is the fallback in
`findConcreteMethod` (resolve the static off the not-yet-lowered
super-trait node so the rewrite happens regardless of declaration
order). His block then resolves it identically as it always did.
## On `@DelegatesTo.Target`
Correct — for a *faithful* `withDelegate(Closure, delegate)` the
`delegate` parameter wants `@DelegatesTo.Target` (the existing
`testGrailsHelperShapeWithDelegatesTo` instead uses
`genericTypeIndex=0`, which points `@DelegatesTo` at the closure's
generic type — a different valid form). It doesn't affect the repro
because the test closures (`{ -> }`, `{ -> sb.append('seen') }`) never
reference delegate members, so delegate resolution is never exercised.
But if you want the regression test to mirror the real Grails shape
exactly, I can switch it to `@DelegatesTo.Target Object delegate`.
Want me to make that change?
On Tue, Jun 30, 2026 at 5:44 AM Milles, Eric (TR Technology) via dev
<[email protected]> wrote:
>
> I think this block of the trait type-checking extension is responsible for
> finding withDelegate in the super trait. That explains the need for the
> Object typecast (see argumentTypes parameter).
>
>
> public class TraitTypeCheckingExtension extends AbstractTypeCheckingExtension
> {
> public List<MethodNode> handleMissingMethod(final ClassNode receiver,
> final String name, final ArgumentListExpression argumentList, final
> ClassNode[] argumentTypes, final MethodCall call) {
> // ...
> if (call instanceof MethodCallExpression mce) {
> ClassNode returnType =
> mce.getNodeMetaData(TraitASTTransformation.DO_DYNAMIC);
> if (returnType != null) return
> Collections.singletonList(makeDynamic(call, returnType));
>
> // GROOVY-7322, GROOVY-8272, GROOVY-8587, GROOVY-8854,
> GROOVY-10312: trait: this.m($static$self)
> ClassNode targetClass =
> isClassClassNodeWrappingConcreteType(receiver)?
> receiver.getGenericsTypes()[0].getType(): receiver;
> if (Traits.isTrait(targetClass.getOuterClass()) &&
> argumentTypes.length > 0 && ClassHelper.isClassType(argumentTypes[0])) {
> Parameter[] signature =
> java.util.Arrays.stream(argumentTypes).map(t -> new
> Parameter(t,"")).toArray(Parameter[]::new);
> List<ClassNode> traits =
> Traits.findTraits(targetClass.getOuterClass());
> traits.remove(targetClass.getOuterClass());
>
> for (ClassNode trait : traits) { // check super trait for
> static method
> MethodNode method =
> Traits.findHelper(trait).getDeclaredMethod(name, signature);
> if (method != null && method.isStatic()) {
> return Collections.singletonList(makeDynamic(call,
> method.getReturnType()));
> }
> }
> }
> }
>
> return Collections.emptyList();
> }
>
>
> Also note that the second parameter in withDelegate needs @DelegatesTo.Target
> in order for the example to fully compile.
>
> ________________________________
> From: Milles, Eric (TR Technology) <[email protected]>
> Sent: Monday, June 29, 2026 2:09 PM
> To: [email protected] <[email protected]>
> Subject: Re: [VOTE] Release Apache Groovy 5.0.7
>
> James,
>
> The issue mentioned in
> https://github.com/apache/grails-core/pull/15557#issuecomment-4833554145
> (code below), is that GROOVY-12106 in a simpler form or is it a new issue?
> The example does indeed work with Groovy 4. But it fails under Groovy 5.0.3,
> so it is possibly related to GROOVY-8854 and GROOVY-11985 but is not caused
> by the changes that went into 5.0.7.
>
> final class A {
> }
> trait Arguable<T> extends ExecutesClosures { // sub-trait declared FIRST
> @groovy.transform.CompileStatic String describe(A a) { withDelegate({ -> },
> (Object) a); 'ok' } // can the cast be removed?
> }
> trait ExecutesClosures {
> static void withDelegate(@DelegatesTo(strategy = Closure.DELEGATE_ONLY)
> Closure c, Object d) { if (c != null) c.call() }
> }
> class C implements Arguable<String> {
> }
>
> print new C().describe(new A())
>
>
> ________________________________
> From: James Fredley <[email protected]>
> Sent: Monday, June 29, 2026 9:21 AM
> To: [email protected] <[email protected]>
> Subject: Re: [VOTE] Release Apache Groovy 5.0.7
>
> Latest run on Grails 8 with latest Groovy 5 snapshot: https: //urldefense.
> com/v3/__https: //github.
> com/apache/grails-core/pull/15557*issuecomment-4833554145__;Iw!!GFN0sa3rsbfR8OLyAw!aTGIzjECSrwp2O9InZ26flgLuK7b6JB0d3eGoY8mmTbXlgeIn2UDLVlg1GdRYxI-qQi7om_CBMmWFVelntIlxHPH6tI3MA$
>
> Latest run on Grails 8 with latest Groovy 5 snapshot:
> https://urldefense.com/v3/__https://github.com/apache/grails-core/pull/15557*issuecomment-4833554145__;Iw!!GFN0sa3rsbfR8OLyAw!aTGIzjECSrwp2O9InZ26flgLuK7b6JB0d3eGoY8mmTbXlgeIn2UDLVlg1GdRYxI-qQi7om_CBMmWFVelntIlxHPH6tI3MA$
>
> On 2026/06/28 10:09:13 Paul King wrote:
> > Both GROOVY_5_0_X and master are now updated with what I believe is a
> > path forward, but I am awaiting to hear from the Grails team on
> > whether the latest version allows them to move forward.
> >
> > GROOVY-11985 which reverted GROOVY-8854 was rolled back. Instead,
> > GROOVY_5_0_X adds @Virtual so we can support the traditional template
> > method style from Groovy 2-4 and fixes the resolution breakages from
> > GROOVY-8854 (as per GROOVY-12106). It leaves the Java-like style
> > (GROOVY-8854) as the default. master also reinforces the Java-like
> > style by adding (non-@Virtual) static methods to the trait interface -
> > fixing some naming previous issues too. As far as I know, the "fuzzy"
> > areas in GEP-22 now all have well-defined semantics.
> >
> > Let me know if you have any feedback. I plan to re-roll the release(s)
> > in a day or two.
> >
> > Cheers, Paul.
> >
> > On Fri, Jun 26, 2026 at 10:50 PM Paul King <[email protected]> wrote:
> > >
> > > Okay, I did another PR here:
> > >
> > > https://urldefense.com/v3/__https://github.com/apache/groovy/pull/2631__;!!GFN0sa3rsbfR8OLyAw!aTGIzjECSrwp2O9InZ26flgLuK7b6JB0d3eGoY8mmTbXlgeIn2UDLVlg1GdRYxI-qQi7om_CBMmWFVelntIlxHMiAqIUWQ$
> > >
> > > This adds @Virtual as the pair of @Anchored and, as the PR is
> > > currently positioned, flips back to GROOVY-8854 behavior.
> > >
> > > My previous thinking was that given we hadn't advertised the breaking
> > > change, was to remove the break and have a more well-defined migration
> > > path from 6.0.X which is only a month or 2 away I would guess.
> > >
> > > But if the consensus is to keep the breaking change, the implications
> > > for Grails are that they would need to add @Virtual to keep the old
> > > behavior. I don't think the reflection path that is their current
> > > workaround is something we want to suggest frameworks built on Groovy
> > > use. And the other workarounds are quite invasive and would need a
> > > long time for them to percolate through the Grails plugin community.
> > > We don't know anyone using the new behavior, so we don't know if
> > > further folks would be impacted but the static method feature is still
> > > marked as incubating.
> > >
> > > The additional implication for Grails is that plugins using the same
> > > pattern that Grails itself uses will continue to work if compiled
> > > under 4.0.32 but will break as soon as they are compiled under Groovy
> > > 5 unless they also add @Virtual. At least the breakage is limited to
> > > the traits themselves and not Grails applications which weave in the
> > > traits.
> > >
> > > If folks are happy with that path, I can cancel the vote and re-roll
> > > the release, and discuss with Grails about getting @Virtual added.
> > >
> > > Cheers, Paul.
> > >
> > > On Fri, Jun 26, 2026 at 5:48 AM Jochen Theodorou <[email protected]>
> > > wrote:
> > > >
> > > > Hi,
> > > >
> > > >
> > > > I think I have to agree with Eric. -1
> > > >
> > > > Normally I would suggest to undo the trait changes in 5.0.7 and go with
> > > > that, but that would not help Grails either.
> > > >
> > > > Is it a 5.1.0? Well the question is what comes after? If we "fix" the
> > > > reamining bug, does that lead to a reevaluation of who traits work and
> > > > then we get a 5.2 next? Also Anchored is a best effort to solve a
> > > > problem onlly 5.0.x introduced. Do we intend to keep that around? Is
> > > > Grails using that?
> > > >
> > > > I really do not want to block things, but I the situation does currently
> > > > not feel exactly right.
> > > >
> > > > I have a wish to Grails here. Could you write a test suite that covers
> > > > the Grails cases in "all" aspects? And I mean the way you expect the
> > > > things to work - in pure Groovy, without Grails of course. I think that
> > > > is better than this case-by-case and late discoveries process we
> > > > currently have.
> > > >
> > > > bye Jochen
> > > >
> > > >
> > > > On 6/25/26 20:06, James Daugherty via dev wrote:
> > > > > Hi Eric,
> > > > >
> > > > > Would you be agreeable to a release of 5.1.0 or a milestone of 5.1.0
> > > > > with these changes? Is your concern for any 5.x version or just the
> > > > > 5.0.x version?
> > > > >
> > > > > Regards,
> > > > > James
> > > > >
> > > > > On Thu, Jun 25, 2026 at 2:02 PM James Fredley
> > > > > <[email protected]> wrote:
> > > > >>
> > > > >> Hi Eric,
> > > > >>
> > > > >> I wanted to share some context on our current work to bring Groovy 5
> > > > >> support into Apache Grails 8.
> > > > >>
> > > > >> After the Groovy 5 release last year, Grails encountered several
> > > > >> compatibility challenges. The team has invested substantial effort,
> > > > >> more than 75 iterations, on this pull request to resolve the issues
> > > > >> and enable Grails 8 to ship on the stable Groovy 5.0.7 release
> > > > >> alongside Spring Boot 4:
> > > > >> https://urldefense.com/v3/__https://github.com/apache/grails-core/pull/15557__;!!GFN0sa3rsbfR8OLyAw!aTGIzjECSrwp2O9InZ26flgLuK7b6JB0d3eGoY8mmTbXlgeIn2UDLVlg1GdRYxI-qQi7om_CBMmWFVelntIlxHPZVQBq9Q$
> > > > >>
> > > > >> Without completing this work, we would likely need to release Apache
> > > > >> Grails 8 on Apache Groovy 4 and then target Apache Groovy 6 for
> > > > >> Apache Grails 9. However, Grails 7 is built on Spring Boot 3.5.x,
> > > > >> which reaches end of life on June 30, 2026. This creates real
> > > > >> pressure to deliver Grails 8 in a timely manner.
> > > > >>
> > > > >> For clarity, Apache Grails 9 will almost certainly target Apache
> > > > >> Groovy 6 regardless.
> > > > >>
> > > > >> On a more positive note, we have also improved our release
> > > > >> validation process with Canary builds. The previous joint validation
> > > > >> approach primarily caught issues in patch releases. The new process
> > > > >> lets us test Grails against upcoming Groovy versions much earlier
> > > > >> and more comprehensively:
> > > > >> https://urldefense.com/v3/__https://github.com/apache/grails-core/pull/15558__;!!GFN0sa3rsbfR8OLyAw!aTGIzjECSrwp2O9InZ26flgLuK7b6JB0d3eGoY8mmTbXlgeIn2UDLVlg1GdRYxI-qQi7om_CBMmWFVelntIlxHN-NLC9WQ$
> > > > >>
> > > > >> Thank you for your ongoing collaboration. I am happy to discuss
> > > > >> timelines, the remaining workarounds in the PR, or anything else
> > > > >> that would help us coordinate effectively.
> > > > >>
> > > > >> Best regards,
> > > > >> James Fredley
> > > > >> VP, Apache Grails PMC
> > > > >>
> > > > >> This version stays professional, collaborative, and timeline focused
> > > > >> while remaining fully compliant with your no em dashes preference.
> > > > >> Ready to copy and send or post to the list.
> > > > >>
> > > > >> On 2026/06/25 15:44:42 "Milles, Eric (TR Technology) via dev" wrote:
> > > > >>> -1 (binding)
> > > > >>>
> > > > >>> I do not think the trait static method change (GROOVY-11985) or the
> > > > >>> new Anchored transform (GROOVY-12093) should have been done in a
> > > > >>> point-fix release. GROOVY-12106 is evidence that one problem has
> > > > >>> been traded for another. There was quite a bit of discussion, but
> > > > >>> IMO the behavior should have remained as-is and Grails could
> > > > >>> investigate a workaround. Groovy 5 was in pre-release state for an
> > > > >>> extended time. So, there was plenty of time to try it out and
> > > > >>> discuss the trait changes.
> > > > >>>
> > > > >>> Having Groovy 5.0.0 to 5.0.6 have one set of behaviors and then
> > > > >>> 5.0.7 onwards do something else plus have GROOVY-12106 and possibly
> > > > >>> other issues is not a good look.
> > > > >>>
> > > > >>> If 11985 and 12093 were removed, I'm okay with the rest of 5.0.7.
> > > > >>> We could then further weigh the possibilities for Groovy 5 and 6
> > > > >>> WRT trait static member references.
> > > > >>>
> > > > >>>
> > > > >>> ________________________________
> > > > >>> From: Paul King <[email protected]>
> > > > >>> Sent: Thursday, June 25, 2026 2:46 AM
> > > > >>> To: Groovy_Developers <[email protected]>
> > > > >>> Subject: [VOTE] Release Apache Groovy 5.0.7
> > > > >>>
> > > > >>> Dear development community, I am happy to start the VOTE thread for
> > > > >>> a Groovy 5. 0. 7 release! This release includes 14 bug
> > > > >>> fixes/improvements as outlined in the changelog: https:
> > > > >>> //urldefense. com/v3/__https: //issues. apache.
> > > > >>> org/jira/secure/ReleaseNote.
> > > > >>> jspa?projectId=12318123&version=12356953__;!!GFN0sa3rsbfR8OLyAw!aTE-LsRa0qOkuOe9PDf8SxURjg4lPNkURZZDxdnHHE1SarHQqnSUqpw4F1byG6kxErokFTjgNp2kjyRDpx1WUg$
> > > > >>>
> > > > >>>
> > > > >>> Dear development community,
> > > > >>>
> > > > >>> I am happy to start the VOTE thread for a Groovy 5.0.7 release!
> > > > >>>
> > > > >>> This release includes 14 bug fixes/improvements as outlined in the
> > > > >>> changelog:
> > > > >>> https://urldefense.com/v3/__https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&version=12356953__;!!GFN0sa3rsbfR8OLyAw!aTE-LsRa0qOkuOe9PDf8SxURjg4lPNkURZZDxdnHHE1SarHQqnSUqpw4F1byG6kxErokFTjgNp2kjyRDpx1WUg$
> >> > >>>
> > > > >>> Tag:
> > > > >>> https://urldefense.com/v3/__https://gitbox.apache.org/repos/asf?p=groovy.git;a=tag;h=refs*tags*GROOVY_5_0_7__;Ly8!!GFN0sa3rsbfR8OLyAw!aTE-LsRa0qOkuOe9PDf8SxURjg4lPNkURZZDxdnHHE1SarHQqnSUqpw4F1byG6kxErokFTjgNp2kjyRmvXQoww$
> >> > >>> Tag commit id: 061e5462ecd50521e881005a82f2733e31ca976a
> > > > >>>
> > > > >>> The artifacts to be voted on are located as follows (r85451).
> > > > >>> Source release:
> > > > >>> https://urldefense.com/v3/__https://dist.apache.org/repos/dist/dev/groovy/5.0.7/sources__;!!GFN0sa3rsbfR8OLyAw!aTE-LsRa0qOkuOe9PDf8SxURjg4lPNkURZZDxdnHHE1SarHQqnSUqpw4F1byG6kxErokFTjgNp2kjyQSz2JVOg$
> >> > >>> Convenience binaries:
> > > > >>> https://urldefense.com/v3/__https://dist.apache.org/repos/dist/dev/groovy/5.0.7/distribution__;!!GFN0sa3rsbfR8OLyAw!aTE-LsRa0qOkuOe9PDf8SxURjg4lPNkURZZDxdnHHE1SarHQqnSUqpw4F1byG6kxErokFTjgNp2kjyQpsp9rgw$
> >> > >>>
> > > > >>> Release artifacts are signed with a key from the following file:
> > > > >>> https://urldefense.com/v3/__https://dist.apache.org/repos/dist/release/groovy/KEYS__;!!GFN0sa3rsbfR8OLyAw!aTE-LsRa0qOkuOe9PDf8SxURjg4lPNkURZZDxdnHHE1SarHQqnSUqpw4F1byG6kxErokFTjgNp2kjySCMw7zpA$
> >> > >>>
> > > > >>> Please vote on releasing this package as Apache Groovy 5.0.7.
> > > > >>>
> > > > >>> Reminder on ASF release approval requirements for PMC members:
> > > > >>> https://urldefense.com/v3/__http://www.apache.org/legal/release-policy.html*release-approval__;Iw!!GFN0sa3rsbfR8OLyAw!aTE-LsRa0qOkuOe9PDf8SxURjg4lPNkURZZDxdnHHE1SarHQqnSUqpw4F1byG6kxErokFTjgNp2kjyRvf488sA$
> >> > >>> Hints on validating checksums/signatures (but replace md5sum with
> >> > >>> sha256sum):
> > > > >>> https://urldefense.com/v3/__https://www.apache.org/info/verification.html__;!!GFN0sa3rsbfR8OLyAw!aTE-LsRa0qOkuOe9PDf8SxURjg4lPNkURZZDxdnHHE1SarHQqnSUqpw4F1byG6kxErokFTjgNp2kjyS1WVRpgA$
> >> > >>>
> > > > >>> The vote is open for the next 72 hours and passes if a majority of
> > > > >>> at
> > > > >>> least three +1 PMC votes are cast.
> > > > >>>
> > > > >>> [ ] +1 Release Apache Groovy 5.0.7
> > > > >>> [ ] 0 I don't have a strong opinion about this, but I assume it's
> > > > >>> ok
> > > > >>> [ ] -1 Do not release Apache Groovy 5.0.7 because...
> > > > >>>
> > > > >>> Here is my vote:
> > > > >>>
> > > > >>> +1 (binding)
> > > > >>>
> > > > >>>
> > > >
> >