Skip to content

Commit

Permalink
GROOVY-9786
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Oct 27, 2020
1 parent ecabd6f commit af3c944
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5166,4 +5166,37 @@ public void testCompileStatic9771() {

runConformTest(sources, "[key:true]");
}

@Test
public void testCompileStatic9786() {
//@formatter:off
String[] sources = {
"Main.groovy",
"interface I {\n" +
" void m()\n" +
"}\n" +
"class A implements I {\n" +
" void m() { print 'A' }\n" +
"}\n" +
"class B implements I {\n" +
" void m() { print 'B' }\n" +
"}\n" +
"@groovy.transform.CompileStatic\n" +
"void test() {\n" +
" I x\n" +
" def y = false\n" +
" def z = true \n" +
" if (y) {\n" +
" x = new A()\n" +
" } else if (z) {\n" +
" x = new B()\n" +
" }\n" +
" x.m()\n" +
"}\n" +
"test()\n",
};
//@formatter:on

runConformTest(sources, "B");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,7 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
accessedVariable = new ParameterVariableExpression((Parameter) accessedVariable);
}
if (accessedVariable instanceof VariableExpression) {
/* GRECLIPSE edit -- GROOVY-9786
VariableExpression var = (VariableExpression) accessedVariable;
List<ClassNode> types = typeCheckingContext.ifElseForWhileAssignmentTracker.get(var);
if (types == null) {
Expand All @@ -994,6 +995,9 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
typeCheckingContext.ifElseForWhileAssignmentTracker.put(var, types);
}
types.add(resultType);
*/
recordAssignment((VariableExpression) accessedVariable, resultType);
// GRECLIPSE end
}
}
storeType(leftExpression, resultType);
Expand Down Expand Up @@ -4105,7 +4109,6 @@ protected void typeCheckClosureCall(final Expression callArguments, final ClassN
@Override
public void visitIfElse(final IfStatement ifElse) {
Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();

try {
// create a new temporary element in the if-then-else type info
typeCheckingContext.pushTemporaryTypeInfo();
Expand All @@ -4126,20 +4129,26 @@ public void visitIfElse(final IfStatement ifElse) {
visitEmptyStatement((EmptyStatement) elseBlock);
} else {
elseBlock.visit(this);
// GRECLIPSE add -- GROOVY-9786
Map<VariableExpression, ClassNode> updates =
elseBlock.getNodeMetaData("assignments");
if (updates != null) {
updates.forEach(this::recordAssignment);
}
// GRECLIPSE end
}
} finally {
popAssignmentTracking(oldTracker);
// GRECLIPSE add -- GROOVY-9786
ifElse.putNodeMetaData("assignments",
// GRECLIPSE end
popAssignmentTracking(oldTracker));
}
BinaryExpression instanceOfExpression = findInstanceOfNotReturnExpression(ifElse);
if (instanceOfExpression == null) {
} else {
if (typeCheckingContext.enclosingBlocks.size() > 0) {
visitInstanceofNot(instanceOfExpression);
}

if (!typeCheckingContext.enclosingBlocks.isEmpty()) {
Optional.ofNullable(findInstanceOfNotReturnExpression(ifElse)).ifPresent(this::visitInstanceofNot);
}
}


public void visitInstanceofNot(BinaryExpression be) {
final BlockStatement currentBlock = typeCheckingContext.enclosingBlocks.getFirst();
assert currentBlock != null;
Expand Down Expand Up @@ -4237,6 +4246,17 @@ public void visitCaseStatement(final CaseStatement statement) {
restoreTypeBeforeConditional();
}

// GRECLIPSE add -- GROOVY-9786
private void recordAssignment(final VariableExpression lhsExpr, final ClassNode rhsType) {
typeCheckingContext.ifElseForWhileAssignmentTracker.computeIfAbsent(lhsExpr, lhs -> {
ClassNode lhsType = lhs.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
List<ClassNode> types = new ArrayList<>(2);
types.add(lhsType);
return types;
}).add(rhsType);
}
// GRECLIPSE end

private void restoreTypeBeforeConditional() {
Set<Map.Entry<VariableExpression, List<ClassNode>>> entries = typeCheckingContext.ifElseForWhileAssignmentTracker.entrySet();
for (Map.Entry<VariableExpression, List<ClassNode>> entry : entries) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -869,13 +869,15 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
}

// if we are in an if/else branch, keep track of assignment
if (typeCheckingContext.ifElseForWhileAssignmentTracker != null && leftExpression instanceof VariableExpression
&& !isNullConstant(rightExpression)) {
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) {
/* GRECLIPSE edit -- GROOVY-9786
VariableExpression var = (VariableExpression) accessedVariable;
List<ClassNode> types = typeCheckingContext.ifElseForWhileAssignmentTracker.get(var);
if (types == null) {
Expand All @@ -885,6 +887,9 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
typeCheckingContext.ifElseForWhileAssignmentTracker.put(var, types);
}
types.add(resultType);
*/
recordAssignment((VariableExpression) accessedVariable, resultType);
// GRECLIPSE end
}
}
storeType(leftExpression, resultType);
Expand Down Expand Up @@ -3889,7 +3894,6 @@ protected void typeCheckClosureCall(final Expression callArguments, final ClassN
@Override
public void visitIfElse(final IfStatement ifElse) {
Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();

try {
// create a new temporary element in the if-then-else type info
typeCheckingContext.pushTemporaryTypeInfo();
Expand All @@ -3904,15 +3908,26 @@ public void visitIfElse(final IfStatement ifElse) {
restoreTypeBeforeConditional();

ifElse.getElseBlock().visit(this);
// GRECLIPSE add -- GROOVY-9786
Map<VariableExpression, ClassNode> updates =
ifElse.getElseBlock().getNodeMetaData("assignments");
if (updates != null) {
updates.forEach(this::recordAssignment);
}
// GRECLIPSE end
} finally {
popAssignmentTracking(oldTracker);
}
BinaryExpression instanceOfExpression = findInstanceOfNotReturnExpression(ifElse);
if (instanceOfExpression == null) {
instanceOfExpression = findNotInstanceOfReturnExpression(ifElse);
// GRECLIPSE add
ifElse.putNodeMetaData("assignments",
// GRECLIPSE end
popAssignmentTracking(oldTracker));
}
if (instanceOfExpression != null) {
if (!typeCheckingContext.enclosingBlocks.isEmpty()) {

if (!typeCheckingContext.enclosingBlocks.isEmpty()) {
BinaryExpression instanceOfExpression = findInstanceOfNotReturnExpression(ifElse);
if (instanceOfExpression == null) {
instanceOfExpression = findNotInstanceOfReturnExpression(ifElse);
}
if (instanceOfExpression != null) {
visitInstanceofNot(instanceOfExpression);
}
}
Expand Down Expand Up @@ -4062,6 +4077,17 @@ public void visitCaseStatement(final CaseStatement statement) {
restoreTypeBeforeConditional();
}

// GRECLIPSE add -- GROOVY-9786
private void recordAssignment(final VariableExpression lhsExpr, final ClassNode rhsType) {
typeCheckingContext.ifElseForWhileAssignmentTracker.computeIfAbsent(lhsExpr, lhs -> {
ClassNode lhsType = lhs.getNodeMetaData(INFERRED_TYPE);
List<ClassNode> types = new ArrayList<>(2);
types.add(lhsType);
return types;
}).add(rhsType);
}
// GRECLIPSE end

private void restoreTypeBeforeConditional() {
Set<Map.Entry<VariableExpression, List<ClassNode>>> entries = typeCheckingContext.ifElseForWhileAssignmentTracker.entrySet();
for (Map.Entry<VariableExpression, List<ClassNode>> entry : entries) {
Expand Down

0 comments on commit af3c944

Please sign in to comment.