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]
