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

Eric Milles commented on GROOVY-12106:
--------------------------------------

For reference, here is my fullĀ {{TraitReceiverTransformer 
transformMethodCallOnThis}} that I tested with:
{code:java}
    private Expression transformMethodCallOnThis(final MethodCallExpression 
call) {
        Expression method    = call.getMethod();
        Expression arguments = call.getArguments();
        Expression thisExpr  = call.getObjectExpression();

        MethodCallExpression newCall = null;

        if (method instanceof ConstantExpression) {
            // GROOVY-7213, GROOVY-7214, GROOVY-8282, GROOVY-8859, 
GROOVY-10106, GROOVY-10312
            MethodNode methodNode = findConcreteMethod(traitClass, 
call.getMethodAsString());
            if (methodNode != null) {
                // GROOVY-11985: static method of weaved
                if (methodNode.isStatic() && !methodNode.isPrivate() && 
!inClosure) {
                    // this.m(x) --> ($static$self or $self.getClass()).m(x)
                    Expression selfClass;
                    if (ClassHelper.isClassType(weaved.getOriginType())) {
                        selfClass = varX(weaved); // $static$self
                    } else {
                        newCall = callX(varX(weaved), "getClass"); // 
$self.getClass()
                        newCall.setImplicitThis(false);
                        
newCall.setMethodTarget(ClassHelper.OBJECT_TYPE.getGetterMethod("getClass",false));
                        selfClass = newCall;
                    }
                    newCall = callX(selfClass, method, transform(arguments));
                    newCall.setImplicitThis(false);
                    // weaved static method is available via the implementing 
class, which is not checkable
                    newCall.putNodeMetaData(TraitASTTransformation.DO_DYNAMIC, 
methodNode.getReturnType());
                } else {
                    // this.m(x) --> (this or T$Trait$Helper).m($self or 
$static$self or (Class)$self.getClass(), x)
                    Expression selfClassOrObject = methodNode.isStatic() && 
!ClassHelper.isClassType(weaved.getOriginType()) ? 
castX(ClassHelper.CLASS_Type.getPlainNodeReference(), callX(weaved, 
"getClass")) : weaved;
                    newCall = callX(!inClosure ? thisExpr : 
classX(traitHelper), method, createArgumentList(selfClassOrObject, arguments));
                    newCall.setImplicitThis(!inClosure ? call.isImplicitThis() 
: false);
                }
            }
        }

        if (newCall == null) { // this.m(x) --> (this or $self or 
$static$self).m(x)
            newCall = callX(inClosure ? thisExpr : weaved, method, 
transform(arguments));
            newCall.setImplicitThis(inClosure ? call.isImplicitThis() : false);
        }

        newCall.setGenericsTypes(call.getGenericsTypes()); // GROOVY-11302: 
this.<T>m(x)
        newCall.setSpreadSafe(call.isSpreadSafe());
        newCall.setSourcePosition(call);
        return newCall;
    }
{code}

The current method just adds a not-anchored check to "methodNode.isStatic() && 
!methodNode.isPrivate() && !inClosure".

> STC cannot resolve inherited static trait method from sub-trait body
> --------------------------------------------------------------------
>
>                 Key: GROOVY-12106
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12106
>             Project: Groovy
>          Issue Type: Bug
>          Components: Static Type Checker
>    Affects Versions: 5.0.7
>            Reporter: James Fredley
>            Priority: Major
>              Labels: static-method, sts, traits
>
> h2. Summary
> Groovy 5 static type checking does not resolve a static method declared by a 
> parent trait when the method is called from a sub-trait body.
> This is independent of Grails and can be reproduced with plain Groovy traits 
> under @CompileStatic.
> This was re-tested on Groovy 5.0.7-SNAPSHOT. Both an unqualified call and a 
> qualified call fail static type checking:
> {code:groovy}
> inheritedStaticMethod(value)
> {code}
> {code:groovy}
> ParentTrait.inheritedStaticMethod(value)
> {code}
> The failure is distinct from GROOVY-11985, which fixed 
> static-override-via-this. This issue is about resolving a parent trait's 
> static method from a sub-trait body.
> h2. Standalone reproducer
> {code:groovy}
> import groovy.transform.CompileStatic
> @CompileStatic
> trait ParentTrait {
>     static void configure(Closure closure, Object target) {
>         if (closure != null) {
>             closure.delegate = target
>             closure.resolveStrategy = Closure.DELEGATE_ONLY
>             closure.call()
>         }
>     }
> }
> @CompileStatic
> trait ChildTrait extends ParentTrait {
>     void applyConfig(Closure closure, Object target) {
>         configure(closure, target)
>     }
> }
> @CompileStatic
> class Example implements ChildTrait {
> }
> {code}
> h2. Expected result
> The code should pass static type checking. A sub-trait should be able to 
> resolve a static method declared by a parent trait.
> h2. Actual result
> Static type checking fails on the call from the sub-trait body:
> {code}
> Cannot find matching method ChildTrait#configure(groovy.lang.Closure, 
> java.lang.Object)
> {code}
> Using a qualified call also fails:
> {code:groovy}
> ParentTrait.configure(closure, target)
> {code}
> h2. Real-world use case
> Apache Grails has the same pattern in the GraphQL DSL helper traits.
> Parent trait method:
> {code}
> grails-data-graphql/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ExecutesClosures.groovy
> line 34
> {code}
> {code:groovy}
> @CompileStatic
> trait ExecutesClosures {
>     static void withDelegate(@DelegatesTo(strategy = Closure.DELEGATE_ONLY) 
> Closure closure, Object delegate) {
>         ...
>     }
> }
> {code}
> Sub-traits that should be able to call the inherited helper:
> {code}
> grails-data-graphql/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy
> grails-data-graphql/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy
> {code}
> Grails currently works around this by inlining the parent trait helper body 
> into each sub-trait. Once this Groovy STC issue is fixed, that inline 
> workaround can be removed.
> h2. Workaround
> Inline the static helper body in each sub-trait, or avoid calling the 
> inherited static trait method from the sub-trait.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to