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:31 UTC

[groovy] branch GROOVY_3_0_X updated (f9dc615 -> a38ccfc)

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

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


    from f9dc615  GROOVY-10280: STC: do not mix type param contexts when resolving
     new d4eee10  GROOVY-10180: STC: method lookup: try instanceof type(s) before declared
     new a38ccfc  GROOVY-6919: STC: check bound types for fields, methods, properties, ...

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../transform/stc/StaticTypeCheckingVisitor.java   | 135 ++++++++-------------
 .../stc/ClosureParamTypeInferenceSTCTest.groovy    |  79 ++++++------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 132 ++++++++++++++++----
 .../console/ui/AstNodeToScriptAdapter.groovy       |  12 +-
 4 files changed, 207 insertions(+), 151 deletions(-)

[groovy] 02/02: GROOVY-6919: STC: check bound types for fields, methods, properties, ...

Posted by em...@apache.org.
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 a38ccfc546db231843680e29751783562f7efccd
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Oct 6 14:26:25 2021 -0500

    GROOVY-6919: STC: check bound types for fields, methods, properties, ...
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  85 ++++---------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 132 +++++++++++++++++----
 .../console/ui/AstNodeToScriptAdapter.groovy       |  12 +-
 3 files changed, 138 insertions(+), 91 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 4e294c6..aeef6ca 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -3806,10 +3806,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 addTraitType(staticType, owners); // T in Class<T$Trait$Helper>
                 owners.add(Receiver.make(receiver)); // Class<Type>
             } else {
-                owners.add(Receiver.make(receiver));
+                addBoundType(receiver, owners);
                 addSelfTypes(receiver, owners);
                 addTraitType(receiver, owners);
-                if (receiver.isInterface()) {
+                if (receiver.redirect().isInterface()) {
                     owners.add(Receiver.make(OBJECT_TYPE));
                 }
             }
@@ -3817,6 +3817,23 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return owners;
     }
 
+    private static void addBoundType(final ClassNode receiver, final List<Receiver<String>> owners) {
+        if (!receiver.isGenericsPlaceHolder() || receiver.getGenericsTypes() == null) {
+            owners.add(Receiver.make(receiver));
+            return;
+        }
+
+        GenericsType gt = receiver.getGenericsTypes()[0];
+        if (gt.getLowerBound() == null && gt.getUpperBounds() != null) {
+            for (ClassNode cn : gt.getUpperBounds()) { // T extends C & I
+                addBoundType(cn, owners);
+                addSelfTypes(cn, owners);
+            }
+        } else {
+            owners.add(Receiver.make(OBJECT_TYPE)); // T or T super Type
+        }
+    }
+
     private static void addSelfTypes(final ClassNode receiver, final List<Receiver<String>> owners) {
         for (ClassNode selfType : Traits.collectSelfTypes(receiver, new LinkedHashSet<>())) {
             owners.add(Receiver.make(selfType));
@@ -5845,71 +5862,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         ParameterVariableExpression(final Parameter parameter) {
             super(parameter);
             this.parameter = parameter;
-            ClassNode inferred = parameter.getNodeMetaData(INFERRED_TYPE);
-            if (inferred == null) {
-                inferred = infer(parameter);
-
-                parameter.setNodeMetaData(INFERRED_TYPE, inferred);
-            }
-        }
-
-        private static ClassNode infer(final Variable variable) {
-            ClassNode originType = variable.getOriginType();
-
-            if (originType.isGenericsPlaceHolder()) {
-                GenericsType[] genericsTypes = originType.getGenericsTypes();
-
-                if (genericsTypes != null && genericsTypes.length > 0) {
-                    GenericsType gt = genericsTypes[0];
-                    ClassNode[] upperBounds = gt.getUpperBounds();
-
-                    if (upperBounds != null && upperBounds.length > 0) {
-                        return upperBounds[0];
-                    }
-                }
-            }
-
-            return originType;
-        }
-
-        @Override
-        public void copyNodeMetaData(final ASTNode other) {
-            parameter.copyNodeMetaData(other);
-        }
-
-        @Override
-        public Object putNodeMetaData(final Object key, final Object value) {
-            return parameter.putNodeMetaData(key, value);
-        }
-
-        @Override
-        public void removeNodeMetaData(final Object key) {
-            parameter.removeNodeMetaData(key);
-        }
-
-        @Override
-        public Map<?, ?> getNodeMetaData() {
-            return parameter.getNodeMetaData();
-        }
-
-        @Override
-        public <T> T getNodeMetaData(final Object key) {
-            return parameter.getNodeMetaData(key);
-        }
-
-        @Override
-        public void setNodeMetaData(final Object key, final Object value) {
-            parameter.setNodeMetaData(key, value);
+            this.parameter.getNodeMetaData(INFERRED_TYPE, x -> parameter.getOriginType());
         }
 
         @Override
-        public int hashCode() {
-            return parameter.hashCode();
+        public Map<?, ?> getMetaDataMap() {
+            return parameter.getMetaDataMap();
         }
 
         @Override
-        public boolean equals(final Object other) {
-            return parameter.equals(other);
+        public void setMetaDataMap(final Map<?, ?> metaDataMap) {
+            parameter.setMetaDataMap(metaDataMap);
         }
     }
 
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index ae365ab..c16b875 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1726,29 +1726,23 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     void testOutOfBoundsByExtendsPlaceholderParameterType() {
         shouldFailWithMessages '''
             class Foo {
-                static <T extends List<? extends CharSequence>> void bar(T a) {}
+                static <T extends List<? extends CharSequence>> void bar(T list) {}
             }
-            class Baz {
-                static <T extends List<Object>> void qux(T a) {
-                    Foo.bar(a)
-                }
+            def <U extends List<Object>> void baz(U list) {
+                Foo.bar(list)
             }
-            Baz.qux([new Object()])
-        ''', 'Cannot call <T extends java.util.List<? extends java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <Object>]'
+        ''', 'Cannot call <T extends java.util.List<? extends java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
     }
 
     void testOutOfBoundsBySuperPlaceholderParameterType() {
         shouldFailWithMessages '''
             class Foo {
-                static <T extends List<? super CharSequence>> void bar(T a) {}
+                static <T extends List<? super CharSequence>> void bar(T list) {}
             }
-            class Baz {
-                static <T extends List<String>> void qux(T a) {
-                    Foo.bar(a)
-                }
+            def <U extends List<String>> void baz(U list) {
+                Foo.bar(list)
             }
-            Baz.qux(['abc'])
-        ''', 'Cannot call <T extends java.util.List<? super java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <String>]'
+        ''', 'Cannot call <T extends java.util.List<? super java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
     }
 
     // GROOVY-5721
@@ -2172,8 +2166,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '#foo(java.util.List <? extends A>) with arguments [java.util.ArrayList <java.lang.Object>]'
     }
 
+    // GROOVY-5891
     void testMethodLevelGenericsForMethodCall() {
-        // Groovy-5891
         assertScript '''
             public <T extends List<Integer>> T foo(Class<T> type, def x) {
                 return type.cast(x)
@@ -2187,24 +2181,116 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             }
             def cl = {1}
             assert foo(cl.class, cl) == cl
-         '''
-         assertScript '''
+        '''
+        assertScript '''
             public <T extends Runnable> T foo(Class<T> type, def x) {
                 return type.cast(x) as T
             }
             def cl = {1}
             assert foo(cl.class, cl) == cl
-         '''
-         // GROOVY-5885
-         assertScript '''
+        '''
+    }
+
+    // GROOVY-5885
+    void testMethodLevelGenericsForMethodCall2() {
+        assertScript '''
             class Test {
-                public <X extends Test> X castToMe(Class<X> type, Object o) {
+                public <T extends Test> T castToMe(Class<T> type, Object o) {
                     return type.cast(o);
                 }
             }
             def t = new Test()
-            assert t.castToMe(Test, t)  == t
-         '''
+            assert t == t.castToMe(Test, t)
+        '''
+    }
+
+    // GROOVY-6919
+    void testMethodLevelGenericsForMethodCall3() {
+        assertScript '''
+            interface I1 {
+                String getFoo()
+            }
+            interface I2 {
+                String getBar()
+            }
+            def <T extends I1 & I2> void test(T obj) {
+                obj?.getFoo()
+                obj?.getBar()
+            }
+            test(null)
+        '''
+    }
+
+    // GROOVY-6919
+    void testMethodLevelGenericsForPropertyRead() {
+        assertScript '''
+            interface I1 {
+                String getFoo()
+            }
+            interface I2 {
+                String getBar()
+            }
+            def <T extends I1 & I2> void test(T obj) {
+                obj?.foo
+                obj?.bar
+            }
+            test(null)
+        '''
+    }
+
+    @NotYetImplemented
+    void testMethodLevelGenericsForPropertyRead2() {
+        assertScript '''
+            interface I1 {
+                static String getFoo() { 'foo' }
+            }
+            interface I2 {
+                String bar = 'bar'
+            }
+            def <T extends I1 & I2> void test(Class<T> cls) {
+                cls?.foo
+                cls?.bar
+            }
+            test(null)
+        '''
+    }
+
+    void testMethodLevelGenericsForPropertyRead3() {
+        assertScript '''
+            interface I1 {
+                String getFoo()
+            }
+            interface I2 {
+                String getBar()
+            }
+            class C<T extends I1 & I2> {
+                def <U extends T> void test(U obj) {
+                    obj?.foo
+                    obj?.bar
+                }
+            }
+            new C().test(null)
+        '''
+    }
+
+    void testMethodLevelGenericsForPropertyRead4() {
+        assertScript '''
+            interface I1 {
+                String getFoo()
+            }
+            interface I2 {
+                String getBar()
+            }
+            @groovy.transform.SelfType(I2) trait T2 {
+                abstract String getBaz()
+            }
+            def <T extends I1 & T2> void test(T obj) {
+                obj?.foo
+                obj?.bar
+                obj?.baz
+            }
+            test(null)
+        '''
     }
 
     // GROOVY-5839
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
index fa78b38..dcd2ccd 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
@@ -710,14 +710,12 @@ class AstNodeToScriptVisitor implements CompilationUnit.IPrimaryClassNodeOperati
 
     @Override
     void visitStaticMethodCallExpression(StaticMethodCallExpression expression) {
+        boolean parens = expression?.arguments instanceof MethodCallExpression
+                || expression?.arguments instanceof VariableExpression
         print expression?.ownerType?.name + '.' + expression?.method
-        if (expression?.arguments instanceof VariableExpression || expression?.arguments instanceof MethodCallExpression) {
-            print '('
-            expression?.arguments?.visit this
-            print ')'
-        } else {
-            expression?.arguments?.visit this
-        }
+        if (parens) print '('
+        expression?.arguments?.visit(this)
+        if (parens) print ')'
     }
 
     @Override

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

Posted by em...@apache.org.
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 ->
+                    }
+                }
+            }
+        '''
+    }
 }