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