This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 72c7914 GROOVY-10308: STC: variable flow type: do not use
`INFERRED_RETURN_TYPE`
72c7914 is described below
commit 72c791402fef8181b218aad74b379dc3272829c7
Author: Eric Milles <[email protected]>
AuthorDate: Sat Oct 23 18:57:43 2021 -0500
GROOVY-10308: STC: variable flow type: do not use `INFERRED_RETURN_TYPE`
---
.../transform/stc/StaticTypeCheckingVisitor.java | 64 +++++-----------------
.../transform/stc/TypeInferenceSTCTest.groovy | 41 ++++++++++++--
.../{Groovy7333Bug.groovy => Groovy7333.groovy} | 4 +-
3 files changed, 51 insertions(+), 58 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 ef4eee2..b0e15ba 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -641,7 +641,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
// GROOVY-9454
ClassNode inferredType = getInferredTypeFromTempInfo(vexp,
null);
if (inferredType != null && !isObjectType(inferredType)) {
- vexp.putNodeMetaData(INFERRED_RETURN_TYPE, inferredType);
+ vexp.putNodeMetaData(INFERRED_TYPE, inferredType);
} else {
storeType(vexp, getType(vexp));
}
@@ -673,7 +673,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
ClassNode inferredType =
localVariable.getNodeMetaData(INFERRED_TYPE);
inferredType = getInferredTypeFromTempInfo(localVariable,
inferredType);
if (inferredType != null && !isObjectType(inferredType) &&
!inferredType.equals(accessedVariable.getType())) {
- vexp.putNodeMetaData(INFERRED_RETURN_TYPE, inferredType);
+ vexp.putNodeMetaData(INFERRED_TYPE, inferredType);
}
}
}
@@ -780,11 +780,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
lType = getType(leftExpression);
} else {
if (op != ASSIGN && op != ELVIS_EQUAL) {
- if (leftExpression instanceof VariableExpression &&
hasInferredReturnType(leftExpression)) {
- lType = getInferredReturnType(leftExpression);
- } else {
- lType = getType(leftExpression);
- }
+ lType = getType(leftExpression);
} else {
lType = getOriginalDeclarationType(leftExpression);
@@ -1321,23 +1317,17 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
// TODO: need errors for write-only too!
if (addedReadOnlyPropertyError(leftExpression)) return;
- ClassNode rTypeInferred, rTypeWrapped; // check for instanceof and
spreading
- if (rightExpression instanceof VariableExpression &&
hasInferredReturnType(rightExpression) &&
assignmentExpression.getOperation().getType() == ASSIGN) {
- rTypeInferred = getInferredReturnType(rightExpression);
- } else {
- rTypeInferred = rightExpressionType;
- }
- rTypeWrapped = adjustTypeForSpreading(rTypeInferred, leftExpression);
+ ClassNode rTypeWrapped = adjustTypeForSpreading(rightExpressionType,
leftExpression);
if (!checkCompatibleAssignmentTypes(leftExpressionType, rTypeWrapped,
rightExpression)) {
- if (!extension.handleIncompatibleAssignment(leftExpressionType,
rTypeInferred, assignmentExpression)) {
- addAssignmentError(leftExpressionType, rTypeInferred,
rightExpression);
+ if (!extension.handleIncompatibleAssignment(leftExpressionType,
rightExpressionType, assignmentExpression)) {
+ addAssignmentError(leftExpressionType, rightExpressionType,
rightExpression);
}
} else {
ClassNode lTypeRedirect = leftExpressionType.redirect();
- addPrecisionErrors(lTypeRedirect, leftExpressionType,
rTypeInferred, rightExpression);
+ addPrecisionErrors(lTypeRedirect, leftExpressionType,
rightExpressionType, rightExpression);
if (rightExpression instanceof ListExpression) {
- addListAssignmentConstructorErrors(lTypeRedirect,
leftExpressionType, rTypeInferred, rightExpression, assignmentExpression);
+ addListAssignmentConstructorErrors(lTypeRedirect,
leftExpressionType, rightExpressionType, rightExpression, assignmentExpression);
} else if (rightExpression instanceof MapExpression) {
addMapAssignmentConstructorErrors(lTypeRedirect,
leftExpression, rightExpression);
}
@@ -1954,12 +1944,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
super.visitForLoop(forLoop);
} else {
collectionExpression.visit(this);
- ClassNode collectionType;
- if (collectionExpression instanceof VariableExpression &&
hasInferredReturnType(collectionExpression)) {
- collectionType = getInferredReturnType(collectionExpression);
- } else {
- collectionType = getType(collectionExpression);
- }
+ ClassNode collectionType = getType(collectionExpression);
ClassNode forLoopVariableType = forLoop.getVariableType();
ClassNode componentType;
if (isWrapperCharacter(getWrapper(forLoopVariableType)) &&
isStringType(collectionType)) {
@@ -2203,12 +2188,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
protected ClassNode checkReturnType(final ReturnStatement statement) {
Expression expression = statement.getExpression();
- ClassNode type;
- if (expression instanceof VariableExpression &&
hasInferredReturnType(expression)) {
- type = getInferredReturnType(expression);
- } else {
- type = getType(expression);
- }
+ ClassNode type = getType(expression);
if (typeCheckingContext.getEnclosingClosure() != null) {
ClassNode inferredReturnType =
getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
// GROOVY-9995: return ctor call with diamond operator
@@ -3316,18 +3296,11 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
objectExpression.visit(this);
call.getMethod().visit(this);
- ClassNode receiver;
- if (objectExpression instanceof VariableExpression &&
hasInferredReturnType(objectExpression)) {
- receiver = getInferredReturnType(objectExpression);
- } else {
- receiver = getType(objectExpression);
- }
- // if it's a spread operator call, then make sure receiver is array or
collection
- if (call.isSpreadSafe()) {
+ ClassNode receiver = getType(objectExpression);
+ if (call.isSpreadSafe()) { // make sure receiver is array or
collection then check element type
if (!receiver.isArray() &&
!implementsInterfaceOrIsSubclassOf(receiver, Collection_TYPE)) {
addStaticTypeError("Spread operator can only be used on
collection types", objectExpression);
} else {
- // type check call as if it was made on component type
ClassNode componentType = inferComponentType(receiver,
int_TYPE);
MethodCallExpression subcall = callX(castX(componentType,
EmptyExpression.INSTANCE), name, call.getArguments());
subcall.setLineNumber(call.getLineNumber());
subcall.setColumnNumber(call.getColumnNumber());
@@ -3751,11 +3724,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
visitClosureExpression(closure);
- if (getInferredReturnType(closure) != null) {
- return getInferredReturnType(closure);
- }
-
- return null;
+ return getInferredReturnType(closure);
}
/**
@@ -4206,7 +4175,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
* @param type the inferred type of {@code expr}
*/
private ClassNode checkForTargetType(final Expression expr, final
ClassNode type) {
- ClassNode sourceType = (hasInferredReturnType(expr) ?
getInferredReturnType(expr) : type);
+ ClassNode sourceType =
Optional.ofNullable(getInferredReturnType(expr)).orElse(type);
ClassNode targetType = null;
MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod();
@@ -4281,11 +4250,6 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
return expr instanceof MapExpression && ((MapExpression)
expr).getMapEntryExpressions().isEmpty();
}
- private static boolean hasInferredReturnType(final Expression expression) {
- ClassNode type = expression.getNodeMetaData(INFERRED_RETURN_TYPE);
- return type != null && !type.getName().equals(ClassHelper.OBJECT);
- }
-
@Override
public void visitTryCatchFinally(final TryCatchStatement statement) {
List<CatchStatement> catchStatements = statement.getCatchStatements();
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 3e7cff4..0c596f6 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
@@ -614,7 +615,7 @@ class TypeInferenceSTCTest extends
StaticTypeCheckingTestCase {
'''
}
- void testCallMethodInWithContextAndShadowing() {
+ void testCallMethodInWithContextAndShadowing() {
// make sure that the method which is found in 'with' is actually the
one from class A
// which returns a String
assertScript '''
@@ -774,11 +775,38 @@ class TypeInferenceSTCTest extends
StaticTypeCheckingTestCase {
}
void testFlowTypingWithStringVariable() {
- // as anything can be assigned to a string, flow typing engine
- // could "erase" the type of the original variable although is must not
assertScript '''
- String str = new Object() // type checker will not complain,
anything assignable to a String
- str.toUpperCase() // should not complain
+ String s = new Object() // anything assignable to String
+ s.toUpperCase()
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10294
+ void testFlowTypingWithNullAssignment() {
+ assertScript '''
+ class C {
+ }
+ C test() {
+ def x = new C()
+ if (false) {
+ x = null
+ }
+ x
+ }
+ assert test() != null
+ '''
+ }
+
+ // GROOVY-10308
+ void testFlowTypingWithNullAssignment2() {
+ assertScript '''
+ class C<T> {
+ T p
+ }
+ def x = { -> new C<String>() }
+ def y = x()
+ def z = y.p // false positive: field access error
+ y = null
'''
}
@@ -870,7 +898,8 @@ class TypeInferenceSTCTest extends
StaticTypeCheckingTestCase {
'''
}
- void testGroovy6215() {
+ // GROOVY-6215
+ void testSwitchCaseAnalysis2() {
assertScript '''
def processNumber(int x) {
def value = getValueForNumber(x)
diff --git
a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333Bug.groovy
b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333.groovy
similarity index 94%
rename from
src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333Bug.groovy
rename to src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333.groovy
index 0916e27..2a7a962 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333Bug.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333.groovy
@@ -21,7 +21,7 @@ package org.codehaus.groovy.classgen.asm.sc.bugs
import groovy.transform.stc.StaticTypeCheckingTestCase
import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
-final class Groovy7333Bug extends StaticTypeCheckingTestCase implements
StaticCompilationTestSupport {
+final class Groovy7333 extends StaticTypeCheckingTestCase implements
StaticCompilationTestSupport {
// GROOVY-7333
void testIncorrectInstanceOfInference1() {
@@ -49,7 +49,7 @@ final class Groovy7333Bug extends StaticTypeCheckingTestCase
implements StaticCo
void test(A a) {
if (a instanceof B) {
@ASTTest(phase=INSTRUCTION_SELECTION, value={
- def type =
node.rightExpression.getNodeMetaData(INFERRED_RETURN_TYPE)
+ def type =
node.rightExpression.getNodeMetaData(INFERRED_TYPE)
assert type.text == 'B' // not '<UnionType:A+B>'
})
def x = a