You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/03/11 18:19:32 UTC

[groovy] 01/02: GROOVY-10180: STC: method lookup: try instanceof type(s) before declared

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

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

commit d4eee1057af17d5f8d007859f1eecb3ffce219d2
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Jul 23 17:40:13 2021 -0500

    GROOVY-10180: STC: method lookup: try instanceof type(s) before declared
    
    - better match for "each" using Map vs. Object:
        void test(obj) { if (obj instanceof Map) obj.each { e -> } }
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 54 +++++++--------
 .../stc/ClosureParamTypeInferenceSTCTest.groovy    | 79 ++++++++++++----------
 2 files changed, 71 insertions(+), 62 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 2c67eca..4e294c6 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -3779,40 +3779,40 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     protected List<Receiver<String>> makeOwnerList(final Expression objectExpression) {
         ClassNode receiver = getType(objectExpression);
         List<Receiver<String>> owners = new ArrayList<>();
-        if (isClassClassNodeWrappingConcreteType(receiver)) {
-            ClassNode staticType = receiver.getGenericsTypes()[0].getType();
-            owners.add(Receiver.make(staticType)); // Type from Class<Type>
-            addTraitType(staticType, owners); // T in Class<T$Trait$Helper>
-            owners.add(Receiver.make(receiver)); // Class<Type>
-        } else {
-            owners.add(Receiver.make(receiver));
-            if (receiver.isInterface()) {
-                owners.add(Receiver.make(OBJECT_TYPE));
-            }
-            addSelfTypes(receiver, owners);
-            addTraitType(receiver, owners);
-        }
-        if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) {
-            List<ClassNode> potentialReceiverType = getTemporaryTypesForExpression(objectExpression);
-            if (potentialReceiverType != null && !potentialReceiverType.isEmpty()) {
-                for (ClassNode node : potentialReceiverType) {
-                    owners.add(Receiver.make(node));
-                }
-            }
-        }
-        if (typeCheckingContext.lastImplicitItType != null
-                && objectExpression instanceof VariableExpression
-                && ((VariableExpression) objectExpression).getName().equals("it")) {
-            owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
-        }
         if (typeCheckingContext.delegationMetadata != null
                 && objectExpression instanceof VariableExpression
                 && ((VariableExpression) objectExpression).getName().equals("owner")
                 && /*isNested:*/typeCheckingContext.delegationMetadata.getParent() != null) {
-            owners.clear();
             List<Receiver<String>> enclosingClass = Collections.singletonList(
                     Receiver.make(typeCheckingContext.getEnclosingClassNode()));
             addReceivers(owners, enclosingClass, typeCheckingContext.delegationMetadata.getParent(), "owner.");
+        } else {
+            if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) {
+                List<ClassNode> potentialReceiverType = getTemporaryTypesForExpression(objectExpression);
+                if (potentialReceiverType != null && !potentialReceiverType.isEmpty()) {
+                    for (ClassNode node : potentialReceiverType) {
+                        owners.add(Receiver.make(node));
+                    }
+                }
+            }
+            if (typeCheckingContext.lastImplicitItType != null
+                    && objectExpression instanceof VariableExpression
+                    && ((VariableExpression) objectExpression).getName().equals("it")) {
+                owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
+            }
+            if (isClassClassNodeWrappingConcreteType(receiver)) {
+                ClassNode staticType = receiver.getGenericsTypes()[0].getType();
+                owners.add(Receiver.make(staticType)); // Type from Class<Type>
+                addTraitType(staticType, owners); // T in Class<T$Trait$Helper>
+                owners.add(Receiver.make(receiver)); // Class<Type>
+            } else {
+                owners.add(Receiver.make(receiver));
+                addSelfTypes(receiver, owners);
+                addTraitType(receiver, owners);
+                if (receiver.isInterface()) {
+                    owners.add(Receiver.make(OBJECT_TYPE));
+                }
+            }
         }
         return owners;
     }
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index bc0ac8a..d2d86a9 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -22,22 +22,41 @@ package groovy.transform.stc
  * Unit tests for static type checking : closure parameter type inference.
  */
 class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
-    void testInferenceForDGM_CollectUsingExplicitIt() {
+
+    void testInferenceForDGM_collectUsingExplicitIt() {
         assertScript '''
             ['a','b'].collect { it -> it.toUpperCase() }
         '''
-    }
-
-    void testInferenceForDGM_CollectUsingExplicitItAndIncorrectType() {
         shouldFailWithMessages '''
             ['a','b'].collect { Date it -> it.toUpperCase() }
         ''', 'Expected parameter of type java.lang.String but got java.util.Date'
     }
 
-    void testInferenceForDGM_CollectUsingImplicitIt() {
+    void testInferenceForDGM_collectUsingImplicitIt() {
         assertScript '''
             ['a','b'].collect { it.toUpperCase() }
         '''
+        assertScript '''
+            def items = []
+            ['a','b','c'].collect(items) { it.toUpperCase() }
+        '''
+        assertScript '''
+            String[] array = ['foo', 'bar', 'baz']
+            assert array.collect { it.startsWith('ba') } == [false, true, true]
+        '''
+        assertScript '''
+            List<Boolean> answer = [true]
+            String[] array = ['foo', 'bar', 'baz']
+            array.collect(answer){it.startsWith('ba')}
+            assert answer == [true, false, true, true]
+        '''
+        assertScript '''
+            Iterator<String> iter = ['foo', 'bar', 'baz'].iterator()
+            assert iter.collect { it.startsWith('ba') } == [false, true, true]
+        '''
+        assertScript '''
+            assert [1234, 3.14].collect { it.intValue() } == [1234,3]
+        '''
     }
 
     void testInferenceForDGM_eachUsingExplicitIt() {
@@ -52,12 +71,6 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testInferenceForDGM_CollectUsingImplicitItAndLUB() {
-        assertScript '''
-            assert [1234, 3.14].collect { it.intValue() } == [1234,3]
-        '''
-    }
-
     void testInferenceForDGM_countUsingFirstSignature() {
         assertScript '''
             def src = [a: 1, b:2, c:3]
@@ -103,13 +116,6 @@ assert result == ['b', 'r', 'e', 'a', 'd', 'b', 'u', 't', 't', 'e', 'r']
 '''
     }
 
-    void testInferenceForDGM_Collect2() {
-        assertScript '''
-def items = []
-['a','b','c'].collect(items) { it.toUpperCase() }
-'''
-    }
-
     void testInferenceForDGM_CollectMap() {
         assertScript '''
         assert [a: 'foo',b:'bar'].collect { k,v -> k+v } == ['afoo','bbar']
@@ -221,23 +227,6 @@ def items = []
 '''
     }
 
-    void testDGM_collectOnArray() {
-        assertScript '''
-            String[] arr = ['foo', 'bar', 'baz']
-            assert arr.collect { it.startsWith('ba') } == [false, true, true]
-            List<Boolean> answer = [true]
-            arr.collect(answer) { it.startsWith('ba') }
-            assert answer == [true, false, true, true]
-        '''
-    }
-
-    void testDGM_collectOnIterator() {
-        assertScript '''
-            Iterator<String> itr = ['foo', 'bar', 'baz'].iterator()
-            assert itr.collect { it.startsWith('ba') } == [false, true, true]
-        '''
-    }
-
     void testInferenceOnNonExtensionMethod() {
         assertScript '''import groovy.transform.stc.ClosureParams
             import groovy.transform.stc.FirstParam
@@ -1497,4 +1486,24 @@ method()
             assert iterable.collect { it.prop } == ['x', 'y', 'z']
         '''
     }
+
+    void testGroovy10180() {
+        assertScript '''
+            void test(args) {
+                if (args instanceof Map) {
+                    args.each { e ->
+                        def k = e.key, v = e.value
+                    }
+                }
+            }
+        '''
+        assertScript '''
+            void test(args) {
+                if (args instanceof Map) {
+                    args.each { k, v ->
+                    }
+                }
+            }
+        '''
+    }
 }