This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 5ddc1a0a0e GROOVY-11386: STC: closure method and property precedence
5ddc1a0a0e is described below

commit 5ddc1a0a0ea20ceb85aa834a8a1e6bf19cb76e80
Author: Eric Milles <[email protected]>
AuthorDate: Sun May 26 13:01:57 2024 -0500

    GROOVY-11386: STC: closure method and property precedence
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 88 ++++++++++++----------
 .../groovy/transform/stc/ClosuresSTCTest.groovy    | 74 ++++++++++--------
 2 files changed, 91 insertions(+), 71 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index efde5781cc..1aadaa5dae 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -161,6 +161,7 @@ import static 
org.codehaus.groovy.ast.ClassHelper.Iterator_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.LIST_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.Long_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.MAP_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.METACLASS_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.Number_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.PATTERN_TYPE;
@@ -650,26 +651,29 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                   case "delegate":
                     DelegationMetadata dm = 
getDelegationMetadata(enclosingClosure.getClosureExpression());
                     if (dm != null) {
-                        storeType(vexp, dm.getType());
+                        vexp.putNodeMetaData(INFERRED_TYPE, dm.getType());
                         return;
                     }
                     // falls through
                   case "owner":
                     if (typeCheckingContext.getEnclosingClosureStack().size() 
> 1) {
-                        storeType(vexp, CLOSURE_TYPE);
+                        vexp.putNodeMetaData(INFERRED_TYPE, 
CLOSURE_TYPE.getPlainNodeReference());
                         return;
                     }
                     // falls through
                   case "thisObject":
-                    storeType(vexp, 
typeCheckingContext.getEnclosingClassNode());
+                    vexp.putNodeMetaData(INFERRED_TYPE, makeThis());
                     return;
                   case "parameterTypes":
-                    storeType(vexp, CLASS_Type.makeArray());
+                    vexp.putNodeMetaData(INFERRED_TYPE, 
CLASS_Type.getPlainNodeReference().makeArray());
                     return;
                   case "maximumNumberOfParameters":
                   case "resolveStrategy":
                   case "directive":
-                    storeType(vexp, int_TYPE);
+                    vexp.putNodeMetaData(INFERRED_TYPE, int_TYPE);
+                    return;
+                  case "metaClass": // GROOVY-11386
+                    vexp.putNodeMetaData(INFERRED_TYPE, METACLASS_TYPE);
                     return;
                 }
             }
@@ -1271,7 +1275,7 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
             TupleExpression tuple = (TupleExpression) leftExpression;
             for (int i = 0; i < tuple.getExpressions().size(); i++) {
                 Expression expression = indexX(rightExpression, constX(i, 
true));
-                expression.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, 
type);
+                expression.putNodeMetaData(INFERRED_TYPE, type);
                 listExpression.addExpression(expression);
             }
             if (!listExpression.getExpressions().isEmpty()) {
@@ -3694,46 +3698,52 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
                 int nArgs = list.stream().noneMatch(e -> e instanceof 
SpreadExpression) ? list.size() : Integer.MAX_VALUE;
                 storeTargetMethod(call, nArgs == 0 ? CLOSURE_CALL_NO_ARG : 
nArgs == 1 ? CLOSURE_CALL_ONE_ARG : CLOSURE_CALL_VARGS);
             } else {
-                // method call receivers are :
-                //   - possible "with" receivers
-                //   - the actual receiver as found in the method call 
expression
-                //   - any of the potential receivers found in the instanceof 
temporary table
-                // in that order
-                List<Receiver<String>> receivers = new ArrayList<>();
-                addReceivers(receivers, makeOwnerList(objectExpression), 
call.isImplicitThis());
-
-                MethodNode first = null;
                 List<MethodNode> mn = null;
                 Receiver<String> chosenReceiver = null;
-                for (Receiver<String> currentReceiver : receivers) {
-                    mn = 
findMethod(currentReceiver.getType().getPlainNodeReference(), name, args);
-                    if (!mn.isEmpty()) {
-                        first = mn.get(0); // capture for error string
-                        // for "this" in a static context, only static methods 
are compatible
-                        if (currentReceiver.getData() == null && 
!isClassType(currentReceiver.getType())) {
-                            boolean staticThis = (isThisObjectExpression || 
call.isImplicitThis()) && typeCheckingContext.isInStaticContext;
-                            boolean staticThat = 
isClassClassNodeWrappingConcreteType(receiver); // GROOVY-10819, GROOVY-10820
-                            mn = allowStaticAccessToMember(mn, staticThis || 
staticThat);
-                        }
-                    }
-                    if (!mn.isEmpty()) {
-                        chosenReceiver = currentReceiver;
-                        break;
-                    }
-                }
-                if (mn.isEmpty() && isThisObjectExpression && 
call.isImplicitThis() && typeCheckingContext.getEnclosingClosure() != null) {
-                    mn = CLOSURE_TYPE.getDeclaredMethods(name);
+                // GROOVY-11386:
+                if (isThisObjectExpression && call.isImplicitThis()
+                    && typeCheckingContext.getEnclosingClosure() != null
+                    && !name.equals("call") && !name.equals("doCall")) { // 
GROOVY-9662
+                    mn = CLOSURE_TYPE.getMethods(name);
                     if (!mn.isEmpty()) {
                         objectExpression.removeNodeMetaData(INFERRED_TYPE);
                     }
                 }
-                if (mn.isEmpty()) {
-                    mn = extension.handleMissingMethod(receiver, name, 
argumentList, args, call);
-                    if (mn.isEmpty() && first != null) mn.add(first); // 
non-static method error?
+                if (mn == null || mn.isEmpty()) {
+                    // method call receivers are:
+                    //   - closure delegate(s) or owner(s) and trait self 
type(s)
+                    //   - the actual receiver as found in the method call 
expression
+                    //   - any of the potential receivers found in the 
instanceof temporary table
+                    // in that order
+                    List<Receiver<String>> receivers = new ArrayList<>();
+                    addReceivers(receivers, makeOwnerList(objectExpression), 
call.isImplicitThis());
+
+                    MethodNode first = null;
+                    for (Receiver<String> currentReceiver : receivers) {
+                        mn = 
findMethod(currentReceiver.getType().getPlainNodeReference(), name, args);
+                        if (!mn.isEmpty()) {
+                            first = mn.get(0); // capture for error string
+                            // for "this" in a static context, only static 
methods are compatible
+                            if (currentReceiver.getData() == null && 
!isClassType(currentReceiver.getType())) {
+                                boolean staticThis = (isThisObjectExpression 
|| call.isImplicitThis()) && typeCheckingContext.isInStaticContext;
+                                boolean staticThat = 
isClassClassNodeWrappingConcreteType(receiver); // GROOVY-10819, GROOVY-10820
+                                mn = allowStaticAccessToMember(mn, staticThis 
|| staticThat);
+                            }
+                        }
+                        if (!mn.isEmpty()) {
+                            chosenReceiver = currentReceiver;
+                            break;
+                        }
+                    }
+                    if (mn.isEmpty()) {
+                        mn = extension.handleMissingMethod(receiver, name, 
argumentList, args, call);
+                        if (mn.isEmpty()) {
+                            if (first != null) mn.add(first); // non-static 
method error?
+                            else addNoMatchingMethodError(receiver, name, 
args, call);
+                        }
+                    }
                 }
-                if (mn.isEmpty()) {
-                    addNoMatchingMethodError(receiver, name, args, call);
-                } else {
+                if (!mn.isEmpty()) {
                     if (areCategoryMethodCalls(mn, name, args)) 
addCategoryMethodCallError(call);
 
                     {
diff --git a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy 
b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
index ef84f0d1c3..80968d78c0 100644
--- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -150,8 +150,6 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    //
-
     void testClosureReturnTypeInference1() {
         assertScript '''
             def c = { int a, int b -> return a + b }
@@ -328,36 +326,6 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    // GROOVY-7701
-    void testWithDelegateVsOwnerField() {
-        assertScript '''
-            class Foo {
-                List type
-            }
-
-            class Bar {
-                int type = 10
-
-                @Lazy
-                List<Foo> something = { ->
-                    List<Foo> tmp = []
-                    def foo = new Foo()
-                    foo.with {
-                        type = ['String']
-                    //  ^^^^ should be Foo.type, not Bar.type
-                    }
-                    tmp.add(foo)
-                    tmp
-                }()
-            }
-
-            def bar = new Bar()
-            assert bar.type == 10
-            assert bar.something*.type == [['String']]
-            assert bar.type == 10
-        '''
-    }
-
     void testClosureSharedVariable1() {
         assertScript '''
             def x = '123';
@@ -784,6 +752,36 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         }
     }
 
+    // GROOVY-7701
+    void testOwnerVersusDelegate() {
+        assertScript '''
+            class Foo {
+                List type
+            }
+
+            class Bar {
+                int type = 10
+
+                @Lazy
+                List<Foo> something = { ->
+                    List<Foo> tmp = []
+                    def foo = new Foo()
+                    foo.with {
+                        type = ['String']
+                    //  ^^^^ should be Foo.type, not Bar.type
+                    }
+                    tmp.add(foo)
+                    tmp
+                }()
+            }
+
+            def bar = new Bar()
+            assert bar.type == 10
+            assert bar.something*.type == [['String']]
+            assert bar.type == 10
+        '''
+    }
+
     // GROOVY-9089
     void testOwnerVersusDelegateFromNestedClosure() {
         String declarations = '''
@@ -912,4 +910,16 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
             assert result == 'foo'
         '''
     }
+
+    // GROOVY-11386
+    void testClosurePropertyPrecedence() {
+        assertScript '''
+            String x = { -> metaClass }()
+            assert x.contains('$_run_closure')
+            String y = { -> getMetaClass() }()
+            assert y.contains('$_run_closure')
+            String z = { -> owner.metaClass }()
+            assert !z.contains('$_run_closure')
+        '''
+    }
 }

Reply via email to