Skip to content

Commit af3c944

Browse files
committed
GROOVY-9786
1 parent ecabd6f commit af3c944

File tree

3 files changed

+98
-19
lines changed

3 files changed

+98
-19
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java

+33
Original file line numberDiff line numberDiff line change
@@ -5166,4 +5166,37 @@ public void testCompileStatic9771() {
51665166

51675167
runConformTest(sources, "[key:true]");
51685168
}
5169+
5170+
@Test
5171+
public void testCompileStatic9786() {
5172+
//@formatter:off
5173+
String[] sources = {
5174+
"Main.groovy",
5175+
"interface I {\n" +
5176+
" void m()\n" +
5177+
"}\n" +
5178+
"class A implements I {\n" +
5179+
" void m() { print 'A' }\n" +
5180+
"}\n" +
5181+
"class B implements I {\n" +
5182+
" void m() { print 'B' }\n" +
5183+
"}\n" +
5184+
"@groovy.transform.CompileStatic\n" +
5185+
"void test() {\n" +
5186+
" I x\n" +
5187+
" def y = false\n" +
5188+
" def z = true \n" +
5189+
" if (y) {\n" +
5190+
" x = new A()\n" +
5191+
" } else if (z) {\n" +
5192+
" x = new B()\n" +
5193+
" }\n" +
5194+
" x.m()\n" +
5195+
"}\n" +
5196+
"test()\n",
5197+
};
5198+
//@formatter:on
5199+
5200+
runConformTest(sources, "B");
5201+
}
51695202
}

base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+29-9
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,7 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
985985
accessedVariable = new ParameterVariableExpression((Parameter) accessedVariable);
986986
}
987987
if (accessedVariable instanceof VariableExpression) {
988+
/* GRECLIPSE edit -- GROOVY-9786
988989
VariableExpression var = (VariableExpression) accessedVariable;
989990
List<ClassNode> types = typeCheckingContext.ifElseForWhileAssignmentTracker.get(var);
990991
if (types == null) {
@@ -994,6 +995,9 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
994995
typeCheckingContext.ifElseForWhileAssignmentTracker.put(var, types);
995996
}
996997
types.add(resultType);
998+
*/
999+
recordAssignment((VariableExpression) accessedVariable, resultType);
1000+
// GRECLIPSE end
9971001
}
9981002
}
9991003
storeType(leftExpression, resultType);
@@ -4105,7 +4109,6 @@ protected void typeCheckClosureCall(final Expression callArguments, final ClassN
41054109
@Override
41064110
public void visitIfElse(final IfStatement ifElse) {
41074111
Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();
4108-
41094112
try {
41104113
// create a new temporary element in the if-then-else type info
41114114
typeCheckingContext.pushTemporaryTypeInfo();
@@ -4126,20 +4129,26 @@ public void visitIfElse(final IfStatement ifElse) {
41264129
visitEmptyStatement((EmptyStatement) elseBlock);
41274130
} else {
41284131
elseBlock.visit(this);
4132+
// GRECLIPSE add -- GROOVY-9786
4133+
Map<VariableExpression, ClassNode> updates =
4134+
elseBlock.getNodeMetaData("assignments");
4135+
if (updates != null) {
4136+
updates.forEach(this::recordAssignment);
4137+
}
4138+
// GRECLIPSE end
41294139
}
41304140
} finally {
4131-
popAssignmentTracking(oldTracker);
4141+
// GRECLIPSE add -- GROOVY-9786
4142+
ifElse.putNodeMetaData("assignments",
4143+
// GRECLIPSE end
4144+
popAssignmentTracking(oldTracker));
41324145
}
4133-
BinaryExpression instanceOfExpression = findInstanceOfNotReturnExpression(ifElse);
4134-
if (instanceOfExpression == null) {
4135-
} else {
4136-
if (typeCheckingContext.enclosingBlocks.size() > 0) {
4137-
visitInstanceofNot(instanceOfExpression);
4138-
}
4146+
4147+
if (!typeCheckingContext.enclosingBlocks.isEmpty()) {
4148+
Optional.ofNullable(findInstanceOfNotReturnExpression(ifElse)).ifPresent(this::visitInstanceofNot);
41394149
}
41404150
}
41414151

4142-
41434152
public void visitInstanceofNot(BinaryExpression be) {
41444153
final BlockStatement currentBlock = typeCheckingContext.enclosingBlocks.getFirst();
41454154
assert currentBlock != null;
@@ -4237,6 +4246,17 @@ public void visitCaseStatement(final CaseStatement statement) {
42374246
restoreTypeBeforeConditional();
42384247
}
42394248

4249+
// GRECLIPSE add -- GROOVY-9786
4250+
private void recordAssignment(final VariableExpression lhsExpr, final ClassNode rhsType) {
4251+
typeCheckingContext.ifElseForWhileAssignmentTracker.computeIfAbsent(lhsExpr, lhs -> {
4252+
ClassNode lhsType = lhs.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
4253+
List<ClassNode> types = new ArrayList<>(2);
4254+
types.add(lhsType);
4255+
return types;
4256+
}).add(rhsType);
4257+
}
4258+
// GRECLIPSE end
4259+
42404260
private void restoreTypeBeforeConditional() {
42414261
Set<Map.Entry<VariableExpression, List<ClassNode>>> entries = typeCheckingContext.ifElseForWhileAssignmentTracker.entrySet();
42424262
for (Map.Entry<VariableExpression, List<ClassNode>> entry : entries) {

base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+36-10
Original file line numberDiff line numberDiff line change
@@ -869,13 +869,15 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
869869
}
870870

871871
// if we are in an if/else branch, keep track of assignment
872-
if (typeCheckingContext.ifElseForWhileAssignmentTracker != null && leftExpression instanceof VariableExpression
873-
&& !isNullConstant(rightExpression)) {
872+
if (!isNullConstant(rightExpression)
873+
&& leftExpression instanceof VariableExpression
874+
&& typeCheckingContext.ifElseForWhileAssignmentTracker != null) {
874875
Variable accessedVariable = ((VariableExpression) leftExpression).getAccessedVariable();
875876
if (accessedVariable instanceof Parameter) {
876877
accessedVariable = new ParameterVariableExpression((Parameter) accessedVariable);
877878
}
878879
if (accessedVariable instanceof VariableExpression) {
880+
/* GRECLIPSE edit -- GROOVY-9786
879881
VariableExpression var = (VariableExpression) accessedVariable;
880882
List<ClassNode> types = typeCheckingContext.ifElseForWhileAssignmentTracker.get(var);
881883
if (types == null) {
@@ -885,6 +887,9 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
885887
typeCheckingContext.ifElseForWhileAssignmentTracker.put(var, types);
886888
}
887889
types.add(resultType);
890+
*/
891+
recordAssignment((VariableExpression) accessedVariable, resultType);
892+
// GRECLIPSE end
888893
}
889894
}
890895
storeType(leftExpression, resultType);
@@ -3889,7 +3894,6 @@ protected void typeCheckClosureCall(final Expression callArguments, final ClassN
38893894
@Override
38903895
public void visitIfElse(final IfStatement ifElse) {
38913896
Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();
3892-
38933897
try {
38943898
// create a new temporary element in the if-then-else type info
38953899
typeCheckingContext.pushTemporaryTypeInfo();
@@ -3904,15 +3908,26 @@ public void visitIfElse(final IfStatement ifElse) {
39043908
restoreTypeBeforeConditional();
39053909

39063910
ifElse.getElseBlock().visit(this);
3911+
// GRECLIPSE add -- GROOVY-9786
3912+
Map<VariableExpression, ClassNode> updates =
3913+
ifElse.getElseBlock().getNodeMetaData("assignments");
3914+
if (updates != null) {
3915+
updates.forEach(this::recordAssignment);
3916+
}
3917+
// GRECLIPSE end
39073918
} finally {
3908-
popAssignmentTracking(oldTracker);
3909-
}
3910-
BinaryExpression instanceOfExpression = findInstanceOfNotReturnExpression(ifElse);
3911-
if (instanceOfExpression == null) {
3912-
instanceOfExpression = findNotInstanceOfReturnExpression(ifElse);
3919+
// GRECLIPSE add
3920+
ifElse.putNodeMetaData("assignments",
3921+
// GRECLIPSE end
3922+
popAssignmentTracking(oldTracker));
39133923
}
3914-
if (instanceOfExpression != null) {
3915-
if (!typeCheckingContext.enclosingBlocks.isEmpty()) {
3924+
3925+
if (!typeCheckingContext.enclosingBlocks.isEmpty()) {
3926+
BinaryExpression instanceOfExpression = findInstanceOfNotReturnExpression(ifElse);
3927+
if (instanceOfExpression == null) {
3928+
instanceOfExpression = findNotInstanceOfReturnExpression(ifElse);
3929+
}
3930+
if (instanceOfExpression != null) {
39163931
visitInstanceofNot(instanceOfExpression);
39173932
}
39183933
}
@@ -4062,6 +4077,17 @@ public void visitCaseStatement(final CaseStatement statement) {
40624077
restoreTypeBeforeConditional();
40634078
}
40644079

4080+
// GRECLIPSE add -- GROOVY-9786
4081+
private void recordAssignment(final VariableExpression lhsExpr, final ClassNode rhsType) {
4082+
typeCheckingContext.ifElseForWhileAssignmentTracker.computeIfAbsent(lhsExpr, lhs -> {
4083+
ClassNode lhsType = lhs.getNodeMetaData(INFERRED_TYPE);
4084+
List<ClassNode> types = new ArrayList<>(2);
4085+
types.add(lhsType);
4086+
return types;
4087+
}).add(rhsType);
4088+
}
4089+
// GRECLIPSE end
4090+
40654091
private void restoreTypeBeforeConditional() {
40664092
Set<Map.Entry<VariableExpression, List<ClassNode>>> entries = typeCheckingContext.ifElseForWhileAssignmentTracker.entrySet();
40674093
for (Map.Entry<VariableExpression, List<ClassNode>> entry : entries) {

0 commit comments

Comments
 (0)