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 2020/10/21 22:00:54 UTC

[groovy] branch GROOVY-9786 created (now 14a0bac)

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

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


      at 14a0bac  GROOVY-9786: STC: keep explicit declared type for uninitialized variable

This branch includes the following new commits:

     new 14a0bac  GROOVY-9786: STC: keep explicit declared type for uninitialized variable

The 1 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.



[groovy] 01/01: GROOVY-9786: STC: keep explicit declared type for uninitialized variable

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 14a0bacfd4b30b72c0f1fbe326680e18624d775e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Oct 21 16:50:28 2020 -0500

    GROOVY-9786: STC: keep explicit declared type for uninitialized variable
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 26 +++++++-------
 .../groovy/transform/stc/STCAssignmentTest.groovy  | 42 +++++++++++++++++++---
 2 files changed, 51 insertions(+), 17 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 62c37bd..ed9f198 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -855,28 +855,30 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     resultType = originType;
                 }
 
-                // if we are in an if/else branch, keep track of assignment
-                if (typeCheckingContext.ifElseForWhileAssignmentTracker != null && leftExpression instanceof VariableExpression
-                        && !isNullConstant(rightExpression)) {
+                // track conditional assignment
+                if (!isNullConstant(rightExpression)
+                        && leftExpression instanceof VariableExpression
+                        && typeCheckingContext.ifElseForWhileAssignmentTracker != null) {
                     Variable accessedVariable = ((VariableExpression) leftExpression).getAccessedVariable();
                     if (accessedVariable instanceof Parameter) {
                         accessedVariable = new ParameterVariableExpression((Parameter) accessedVariable);
                     }
                     if (accessedVariable instanceof VariableExpression) {
-                        VariableExpression var = (VariableExpression) accessedVariable;
-                        List<ClassNode> types = typeCheckingContext.ifElseForWhileAssignmentTracker.get(var);
-                        if (types == null) {
-                            types = new LinkedList<>();
-                            ClassNode type = var.getNodeMetaData(INFERRED_TYPE);
+                        typeCheckingContext.ifElseForWhileAssignmentTracker.computeIfAbsent((VariableExpression) accessedVariable, ve -> {
+                            ClassNode type = ve.getNodeMetaData(INFERRED_TYPE);
+                            if (type == null && !ve.isDynamicTyped()) {
+                                type = originType; // GROOVY-9786
+                            }
+                            List<ClassNode> types = new ArrayList<>(2);
                             types.add(type);
-                            typeCheckingContext.ifElseForWhileAssignmentTracker.put(var, types);
-                        }
-                        types.add(resultType);
+                            return types;
+                        }).add(resultType);
                     }
                 }
+
                 storeType(leftExpression, resultType);
 
-                // if right expression is a ClosureExpression, store parameter type information
+                // propagate closure parameter type information
                 if (leftExpression instanceof VariableExpression) {
                     if (rightExpression instanceof ClosureExpression) {
                         leftExpression.putNodeMetaData(CLOSURE_ARGUMENTS, ((ClosureExpression) rightExpression).getParameters());
diff --git a/src/test/groovy/transform/stc/STCAssignmentTest.groovy b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
index ace7882..6c3d990 100644
--- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy
+++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
@@ -549,15 +549,47 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
 
     void testIfWithCommonInterface() {
         assertScript '''
-            interface Foo { void foo() }
-            class A implements Foo { void foo() { println 'A' } }
-            class B implements Foo { void foo() { println 'B' } }
+            interface I {
+                def foo()
+            }
+            class A implements I {
+                def foo() { 'A' }
+            }
+            class B implements I {
+                def foo() { 'B' }
+            }
+
             def x = new A()
-            def y = 'foo'
+            def y = true
+            if (y) {
+                x = new B()
+            }
+            assert x.foo() == 'B'
+        '''
+    }
+
+    // GROOVY-9786
+    void testIfElseIfWithCommonInterface() {
+        assertScript '''
+            interface I {
+                def foo()
+            }
+            class A implements I {
+                def foo() { 'A' }
+            }
+            class B implements I {
+                def foo() { 'B' }
+            }
+
+            I x
+            def y = false
+            def z = true
             if (y) {
+                x = new A()
+            } else if (z) {
                 x = new B()
             }
-            x.foo()
+            assert x.foo() == 'B'
         '''
     }