jamesfredley commented on PR #15557:
URL: https://github.com/apache/grails-core/pull/15557#issuecomment-4327379625

   @paulk-asert here is a faithful standalone reproducer that does fail under 
Groovy 5: https://github.com/jamesfredley/groovy5-compiledynamic-trait-bug
   
   You were right - the bug is **not** what either of my commit messages 
described. It is not about `@Delegate` fields on traits silently returning 
null, and it is not about `@CompileDynamic` bodies dispatching through 
`@Delegate` chains under invokedynamic. The reproducer has no `@CompileDynamic` 
anywhere and it still fails, and the same failure happens whether `BaseCommand` 
is a `trait` or an `abstract class`.
   
   What it actually is, on Groovy 5.0.5 and 5.0.6-SNAPSHOT, with Java 21 / 
Gradle 9.4.1: under `@CompileStatic`, calling an overloaded 
`render(Map<String,Object>)` on an interface-typed reference silently no-ops. 
No exception, no warning, no log - the method is just not entered. The same 
code passes on Groovy 4.0.31.
   
   The reproducer runs four call shapes back-to-back against the same non-null 
`TemplateRendererImpl` instance:
   
   | # | Call site (from a `@CompileStatic` class) | Groovy 4.0.31 | Groovy 
5.0.6-SNAPSHOT |
   
|---|------------------------------------------|---------------|------------------------|
   | A | `render(template: ..., destination: ..., model: ..., overwrite: ...)` 
via `@Delegate` forwarder | PASS | **silent no-op** |
   | B | `templateRenderer.render(template: ..., destination: ..., model: ..., 
overwrite: ...)` directly on the interface-typed field, no `@Delegate` involved 
| PASS | **silent no-op** |
   | C | `render([template: ..., destination: ..., ...] as Map<String, 
Object>)` explicit `Map` literal via `@Delegate` forwarder | PASS | **silent 
no-op** |
   | D | `render(File, File, Map, boolean)` typed positional overload via 
`@Delegate` forwarder | PASS | PASS |
   
   Case B is the one that rules out `@Delegate` and the trait-helper-method 
theory entirely - it is calling `render(Map)` directly on the interface field, 
not through any `@Delegate`-generated forwarder, and it still silently no-ops 
on Groovy 5.
   
   That also explains why two independent workarounds in this PR each happen to 
make grails-scaffolding pass: `a0ee062e89` (trait -> abstract class) is 
actually a red herring on its own (the reproducer shows abstract class still 
fails), but `0270152be9` does fix it because it rewrites the one in-Grails call 
that landed on `render(Map)` into a Case-D positional call that survives.
   
   Versions and setup match this PR (Java 21, Gradle 9.4.1, Apache snapshots 
repo for Groovy `5.0.6-SNAPSHOT`). README walks through the layout and the call 
shapes; `./gradlew run` defaults to the Groovy 5 snapshot, 
`-PgroovyVersion=4.0.31` to compare against 4.x.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to