https://github.com/apache/grails-core/pull/15557#issuecomment-4845438797

All clear on the Grails side, as far as I can tell.

Thanks again for the heroic efforts to support some edge case, legacy code in 
Grails.

James

On 2026/06/29 20:12:12 Paul King wrote:
> 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)
> > > > > >>>
> > > > > >>>
> > > > >
> > >
> 

Reply via email to