You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2017/09/29 12:37:12 UTC
groovy git commit: GROOVY-8260: Static compilation requires casting
inside instanceof check (handle additional cases)
Repository: groovy
Updated Branches:
refs/heads/GROOVY_2_5_X 3d927668c -> caa1e5f6a
GROOVY-8260: Static compilation requires casting inside instanceof check (handle additional cases)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/caa1e5f6
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/caa1e5f6
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/caa1e5f6
Branch: refs/heads/GROOVY_2_5_X
Commit: caa1e5f6ad55c9456833bb787f69d7d718a2e915
Parents: 3d92766
Author: paulk <pa...@asert.com.au>
Authored: Fri Sep 29 22:35:54 2017 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Fri Sep 29 22:36:57 2017 +1000
----------------------------------------------------------------------
.../stc/StaticTypeCheckingVisitor.java | 51 ++++++++++++++--
.../groovy/transform/stc/MiscSTCTest.groovy | 63 +++++++++++++++++++-
2 files changed, 105 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/caa1e5f6/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 20f5d97..cca4167 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -479,7 +479,30 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
- if (! (vexp.getAccessedVariable() instanceof DynamicVariable)) return;
+ if (!(vexp.getAccessedVariable() instanceof DynamicVariable)) {
+ VariableExpression variable = null;
+ if (vexp.getAccessedVariable() instanceof Parameter) {
+ variable = new ParameterVariableExpression((Parameter) vexp.getAccessedVariable());
+ } else if (vexp.getAccessedVariable() instanceof VariableExpression) {
+ variable = (VariableExpression) vexp.getAccessedVariable();
+ }
+ if (variable != null) {
+ ClassNode inferredType = getInferredTypeFromTempInfo(variable, variable.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE));
+ if (inferredType != null && !inferredType.getName().equals("java.lang.Object")) {
+ if (typeCheckingContext.getEnclosingBinaryExpression() != null) {
+ // TODO narrow this down to assignment
+ if (typeCheckingContext.getEnclosingBinaryExpression().getRightExpression() == vexp) {
+ vexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferredType);
+ }
+ } else {
+ // stash away type info that will be lost later to handle case
+ // where this expression has return added later - piggy back on existing key
+ vexp.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferredType);
+ }
+ }
+ }
+ return;
+ }
// a dynamic variable is either an undeclared variable
// or a member of a class used in a 'with'
@@ -1835,6 +1858,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (typeCheckingContext.getEnclosingClosure()!=null) {
return type;
}
+ if ((expression instanceof VariableExpression) && hasInferredReturnType(expression)) {
+ type = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
+ }
MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod();
if (enclosingMethod != null && typeCheckingContext.getEnclosingClosure()==null) {
if (!enclosingMethod.isVoidMethod()
@@ -3204,7 +3230,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
int depth = typeCheckingContext.temporaryIfBranchTypeInformation.size();
while (classNodes == null && depth > 0) {
final Map<Object, List<ClassNode>> tempo = typeCheckingContext.temporaryIfBranchTypeInformation.get(--depth);
- Object key = extractTemporaryTypeInfoKey(objectExpression);
+ Object key = objectExpression instanceof ParameterVariableExpression
+ ? ((ParameterVariableExpression) objectExpression).parameter
+ : extractTemporaryTypeInfoKey(objectExpression);
classNodes = tempo.get(key);
}
return classNodes;
@@ -3392,6 +3420,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
typeCheckingContext.popTemporaryTypeInfo();
falseExpression.visit(this);
ClassNode resultType;
+ ClassNode typeOfFalse = getType(falseExpression);
+ ClassNode typeOfTrue = getType(trueExpression);
+ if (hasInferredReturnType(falseExpression)) {
+ typeOfFalse = falseExpression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
+ }
+ if (hasInferredReturnType(trueExpression)) {
+ typeOfTrue = trueExpression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
+ }
if (isNullConstant(trueExpression) || isNullConstant(falseExpression)) {
BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
if (enclosingBinaryExpression != null && enclosingBinaryExpression.getRightExpression()==expression) {
@@ -3399,20 +3435,23 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
} else if (isNullConstant(trueExpression) && isNullConstant(falseExpression)) {
resultType = OBJECT_TYPE;
} else if (isNullConstant(trueExpression)) {
- resultType = wrapTypeIfNecessary(getType(falseExpression));
+ resultType = wrapTypeIfNecessary(typeOfFalse);
} else {
- resultType = wrapTypeIfNecessary(getType(trueExpression));
+ resultType = wrapTypeIfNecessary(typeOfTrue);
}
} else {
// store type information
- final ClassNode typeOfTrue = getType(trueExpression);
- final ClassNode typeOfFalse = getType(falseExpression);
resultType = lowestUpperBound(typeOfTrue, typeOfFalse);
}
storeType(expression, resultType);
popAssignmentTracking(oldTracker);
}
+ private boolean hasInferredReturnType(Expression expression) {
+ ClassNode type = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
+ return type != null && !type.getName().equals("java.lang.Object");
+ }
+
@Override
public void visitTryCatchFinally(final TryCatchStatement statement) {
final List<CatchStatement> catchStatements = statement.getCatchStatements();
http://git-wip-us.apache.org/repos/asf/groovy/blob/caa1e5f6/src/test/groovy/transform/stc/MiscSTCTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/transform/stc/MiscSTCTest.groovy b/src/test/groovy/transform/stc/MiscSTCTest.groovy
index 13bdb40..fadac0a 100644
--- a/src/test/groovy/transform/stc/MiscSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MiscSTCTest.groovy
@@ -22,8 +22,6 @@ import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor
/**
* Unit tests for static type checking : miscellaneous tests.
- *
- * @author Cedric Champeau
*/
class MiscSTCTest extends StaticTypeCheckingTestCase {
@@ -272,8 +270,67 @@ class MiscSTCTest extends StaticTypeCheckingTestCase {
}
}
- public static class MiscSTCTestSupport {
+ static class MiscSTCTestSupport {
static def foo() { '123' }
}
+
+ void testTernaryParam() {
+ assertScript '''
+ Date ternaryParam(Object input) {
+ input instanceof Date ? input : null
+ }
+ def d = new Date()
+ assert ternaryParam(42) == null
+ assert ternaryParam('foo') == null
+ assert ternaryParam(d) == d
+ '''
+ }
+
+ void testTernaryLocalVar() {
+ assertScript '''
+ Date ternaryLocalVar(Object input) {
+ Object copy = input
+ copy instanceof Date ? copy : null
+ }
+ def d = new Date()
+ assert ternaryLocalVar(42) == null
+ assert ternaryLocalVar('foo') == null
+ assert ternaryLocalVar(d) == d
+ '''
+ }
+
+ void testIfThenElseParam() {
+ assertScript '''
+ Date ifThenElseParam(Object input) {
+ if (input instanceof Date) {
+ input
+ } else {
+ null
+ }
+ }
+ def d = new Date()
+ assert ifThenElseParam(42) == null
+ assert ifThenElseParam('foo') == null
+ assert ifThenElseParam(d) == d
+ '''
+ }
+
+ void testIfThenElseLocalVar() {
+ assertScript '''
+ Date ifThenElseLocalVar(Object input) {
+ Date result
+ if (input instanceof Date) {
+ result = input
+ } else {
+ result = null
+ }
+ result
+ }
+ def d = new Date()
+ assert ifThenElseLocalVar(42) == null
+ assert ifThenElseLocalVar('foo') == null
+ assert ifThenElseLocalVar(d) == d
+ '''
+ }
}