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/06/29 20:24:46 UTC

[groovy] branch GROOVY_3_0_X updated: GROOVY-10180, GROOVY-10668: STC: check declared type before `instanceof`

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


The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
     new a867bbb108 GROOVY-10180, GROOVY-10668: STC: check declared type before `instanceof`
a867bbb108 is described below

commit a867bbb108ac507418d7dfc10b40e385be6d1bbe
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Jun 29 14:54:22 2022 -0500

    GROOVY-10180, GROOVY-10668: STC: check declared type before `instanceof`
    
    3_0_X rollback
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  26 +--
 .../stc/ClosureParamTypeInferenceSTCTest.groovy    |   3 +
 .../transform/stc/TypeInferenceSTCTest.groovy      | 184 ++++++++++++++-------
 3 files changed, 142 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 03db7b99a2..183b9e63fe 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -3776,19 +3776,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     Receiver.make(typeCheckingContext.getEnclosingClassNode()));
             addReceivers(owners, enclosingClass, typeCheckingContext.delegationMetadata.getParent(), "owner.");
         } else {
-            if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) { // GROOVY-10180, et al.
-                List<ClassNode> instanceofTypes = getTemporaryTypesForExpression(objectExpression);
-                if (instanceofTypes != null && !instanceofTypes.isEmpty()) {
-                    ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0)
-                            : new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY));
-                    owners.add(Receiver.make(instanceofType));
-                }
-            }
-            if (typeCheckingContext.lastImplicitItType != null
-                    && objectExpression instanceof VariableExpression
-                    && ((Variable) 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>
@@ -3802,6 +3789,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     owners.add(Receiver.make(OBJECT_TYPE));
                 }
             }
+            if (typeCheckingContext.lastImplicitItType != null
+                    && objectExpression instanceof VariableExpression
+                    && ((Variable) objectExpression).getName().equals("it")) {
+                owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
+            }
+            if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) {
+                List<ClassNode> instanceofTypes = getTemporaryTypesForExpression(objectExpression);
+                if (instanceofTypes != null && !instanceofTypes.isEmpty()) {
+                    ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0)
+                            : new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY));
+                    owners.add(Receiver.make(instanceofType));
+                }
+            }
         }
         return owners;
     }
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index d2d86a9cd4..9bd1c17085 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -18,6 +18,8 @@
  */
 package groovy.transform.stc
 
+import groovy.test.NotYetImplemented
+
 /**
  * Unit tests for static type checking : closure parameter type inference.
  */
@@ -1487,6 +1489,7 @@ method()
         '''
     }
 
+    @NotYetImplemented
     void testGroovy10180() {
         assertScript '''
             void test(args) {
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 27e2e50277..02113fe08f 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -18,6 +18,7 @@
  */
 package groovy.transform.stc
 
+import groovy.test.NotYetImplemented
 import org.codehaus.groovy.ast.ClassHelper
 import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.ast.MethodNode
@@ -91,25 +92,16 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testInstanceOf() {
+    void testInstanceOf1() {
         assertScript '''
             Object o
-            if (o instanceof String) o.toUpperCase()
-        '''
-    }
-
-    void testEmbeddedInstanceOf() {
-        assertScript '''
-            Object o
-            if (o instanceof Object) {
-                if (o instanceof String) {
-                    o.toUpperCase()
-                }
+            if (o instanceof String) {
+                o.toUpperCase()
             }
         '''
     }
 
-    void testEmbeddedInstanceOf2() {
+    void testInstanceOf2() {
         assertScript '''
             Object o
             if (o instanceof String) {
@@ -120,40 +112,55 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testEmbeddedInstanceOf3() {
+    void testInstanceOf3() {
         shouldFailWithMessages '''
             Object o
             if (o instanceof String) {
-                if (o instanceof Object) { // causes the inferred type of 'o' to be overwritten
-                    o.toUpperCase()
-                }
+               o.toUpperCase()
             }
-        ''', 'Cannot find matching method java.lang.Object#toUpperCase()'
+            o.toUpperCase() // ensure that type information is reset
+        ''',
+        'Cannot find matching method java.lang.Object#toUpperCase()'
     }
 
-    void testInstanceOfAfterEach() {
+    void testInstanceOf4() {
         shouldFailWithMessages '''
             Object o
             if (o instanceof String) {
                o.toUpperCase()
+            } else {
+                o.toUpperCase() // ensure that type information is reset
             }
-            o.toUpperCase() // ensure that type information is lost after if()
-        ''', 'Cannot find matching method java.lang.Object#toUpperCase()'
+        ''',
+        'Cannot find matching method java.lang.Object#toUpperCase()'
     }
 
-    void testInstanceOfInElseBranch() {
-        shouldFailWithMessages '''
-            Object o
-            if (o instanceof String) {
-               o.toUpperCase()
-            } else {
-                o.toUpperCase() // ensure that type information is lost in else
+    void testInstanceOf5() {
+        assertScript '''
+            class A {
+                void bar() {
+                }
             }
-        ''', 'Cannot find matching method java.lang.Object#toUpperCase()'
+            class B {
+                void bar() {
+                }
+            }
+
+            def foo(o) {
+                if (o instanceof A) {
+                    o.bar()
+                }
+                if (o instanceof B) {
+                    o.bar()
+                }
+            }
+            foo(new A())
+            foo(new B())
+        '''
     }
 
     // GROOVY-9454
-    void testInstanceOfOnGenericProperty() {
+    void testInstanceOf6() {
         assertScript '''
             interface Face {
             }
@@ -179,32 +186,73 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testMultipleInstanceOf() {
+    // GROOVY-10667
+    void testInstanceOf7() {
         assertScript '''
-            class A {
-                void bar() { }
+            trait Tagged {
+                String tag
             }
-            class B {
-                void bar() { }
+            class TaggedException extends Exception implements Tagged {
             }
 
-            def foo(o) {
-                if (o instanceof A) {
-                    o.bar()
+            static void doSomething1(Exception e) {
+                if (e instanceof Tagged) {
+                    //println e.tag
+                    doSomething2(e) // Cannot find matching method #doSomething2(Tagged)
                 }
-                if (o instanceof B) {
-                    o.bar()
+            }
+            static void doSomething2(Exception e) {
+            }
+
+            doSomething1(new TaggedException(tag:'Test'))
+        '''
+    }
+
+    void testNestedInstanceOf1() {
+        assertScript '''
+            Object o
+            if (o instanceof Object) {
+                if (o instanceof String) {
+                    o.toUpperCase()
                 }
             }
-            foo(new A())
-            foo(new B())
         '''
+    }
+
+    void testNestedInstanceOf2() {
         shouldFailWithMessages '''
+            Object o
+            if (o instanceof String) {
+                if (o instanceof Object) { // causes the inferred type of 'o' to be overwritten
+                    o.toUpperCase()
+                }
+            }
+        ''',
+        'Cannot find matching method java.lang.Object#toUpperCase()'
+    }
+
+    void testNestedInstanceOf3() {
+        assertScript '''
             class A {
-                void bar() { }
+               int foo() { 1 }
             }
             class B {
-                void bar() { }
+               int foo2() { 2 }
+            }
+            def o = new A()
+            int result = o instanceof A ? o.foo() : (o instanceof B ? o.foo2() : 3)
+        '''
+    }
+
+    void testMultipleInstanceOf1() {
+        shouldFailWithMessages '''
+            class A {
+                void bar() {
+                }
+            }
+            class B {
+                void bar() {
+                }
             }
 
             def foo(o) {
@@ -241,16 +289,22 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         'Reference to method is ambiguous. Cannot choose between [float java.lang.Integer#floatValue(), float java.lang.Double#floatValue()]'
     }
 
-    void testInstanceOfInTernaryOp() {
+    // GROOVY-10668
+    void testMultipleInstanceOf3() {
         assertScript '''
-            class A {
-               int foo() { 1 }
-            }
-            class B {
-               int foo2() { 2 }
-            }
-            def o = new A()
-            int result = o instanceof A?o.foo():(o instanceof B?o.foo2():3)
+            def toArray(Object value) {
+                def result
+                if (value instanceof List)
+                    result = value.toArray()
+                else if (value instanceof String || value instanceof GString)
+                    result = value.toString().split(',')
+                else
+                    throw new Exception('not supported')
+
+                return result
+            }
+            toArray([1,2,3])
+            toArray('1,2,3')
         '''
     }
 
@@ -387,11 +441,18 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         ''', 'Cannot find matching method java.lang.Object#toUpperCase()'
     }
 
-    void testShouldNotAllowDynamicVariable() {
-        shouldFailWithMessages '''
-            String name = 'Guillaume'
-            println naamme
-        ''', 'The variable [naamme] is undeclared'
+    @NotYetImplemented // GROOVY-10217
+    void testInstanceOfThenSubscriptOperator() {
+        assertScript '''
+            void test(Object o) {
+                if (o instanceof List) {
+                    assert o[0] == 1
+                    def x = (List) o
+                    assert x[0] == 1
+                }
+            }
+            test([1])
+        '''
     }
 
     void testInstanceOfInferenceWithImplicitIt() {
@@ -522,6 +583,13 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    void testShouldNotAllowDynamicVariable() {
+        shouldFailWithMessages '''
+            String name = 'Guillaume'
+            println naamme
+        ''', 'The variable [naamme] is undeclared'
+    }
+
     void testShouldNotFailWithWith() {
         assertScript '''
             class A {