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

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

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'
         '''
     }