[ 
https://issues.apache.org/jira/browse/GROOVY-12597?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18135563#comment-18135563
 ] 

ASF GitHub Bot commented on GROOVY-12597:
-----------------------------------------

codeconsole opened a new pull request, #3124:
URL: https://github.com/apache/groovy/pull/3124

   A public static trait method is promoted onto the trait interface, so 
`T.m()` works as well as `Impl.m()`. Called as `T.m()`, though, the method runs 
with the trait interface as its static self, and trait static state exists only 
in implementing classes. Any read or write of a static field then failed with 
an error naming the internal accessor:
   
   ```groovy
   trait T {
       private static boolean flag = true
       static boolean isReady() { flag }
   }
   class C implements T {}
   assert C.isReady()
   T.isReady() // MissingMethodException: No signature of static method: 
T__flag$get for class: T
   ```
   
   This happens the same way in dynamic, `@TypeChecked` and `@CompileStatic` 
code, and in 6.0.0.
   
   The trait documentation says each implementing class has its own copy of the 
static state and the trait itself has none, so there is no state to use here. A 
compile-time error is not possible in general: the access can be direct, 
through a private helper or in a closure, and a precompiled trait shows the 
caller only the method signature. The trait interface now declares synthetic 
static accessors for each static field. They throw a `MissingFieldException` 
that names the field and trait and says to call the method on an implementing 
class. Implementing classes keep their own accessors, so they are unaffected. 
In a static helper method the field accessor's receiver is cast to raw `Class`, 
so static compilation still dispatches it dynamically instead of binding to the 
throwing interface accessor. The trait guide documents the behaviour.
   
   ## Tests
   
   `TraitASTTransformationTest.testTraitStaticStateThroughTrait` (dynamic, 
`@TypeChecked`, `@CompileStatic`) fails without the change; its 
`@CompileStatic` case also fails without the `TraitReceiverTransformer` change 
alone. It covers getter, property and setter access, a closure, a private 
helper, a static property, a stateless `T.pure()`, a subclass of an 
implementing class, and the implementing class's state staying intact. 
`org.codehaus.groovy.transform.traitx.*`, `groovy.transform.stc.*`, 
`org.codehaus.groovy.classgen.asm.sc.*`, `gls.*`, `groovy.ThisAndSuperTest` and 
`TraitsSpecificationTest` pass. The Checkstyle and CodeNarc gates pass.
   




> Calling a stateful trait static method through the trait fails with 
> MissingMethodException for the internal field accessor
> --------------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12597
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12597
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> {code:groovy}
> trait T {
>     private static boolean flag = true
>     static boolean isReady() { flag }
> }
> class C implements T {}
> assert C.isReady()
> assert T.isReady()
> {code}
> Actual: {{T.isReady()}} (and {{T.ready}}) throws 
> {{groovy.lang.MissingMethodException: No signature of static method: 
> T__flag$get for class: T is applicable for argument types: () values: []}}. 
> The same happens in dynamic Groovy, with @TypeChecked and with 
> @CompileStatic, and for static properties, setters, closures and private 
> static helpers.
> Expected: trait static state belongs to each implementing class, so the trait 
> itself has none. The call should fail with an error that says so, not with a 
> missing internal accessor. Stateless static methods called through the trait 
> keep working.
> Cause: the promoted interface static forwarder passes the trait class as the 
> static self of the helper method. A static field access in the helper becomes 
> a call to the generated accessor (here T__flag$get) on that class, and only 
> implementing classes declare one.
> Seen in 6.0.0. 5.x does not promote trait statics onto the interface.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to