Skip to content

Commit e090327

Browse files
committed
GROOVY-10308: STC: variable flow type: do not use INFERRED_RETURN_TYPE
3_0_X backport
1 parent 82a4089 commit e090327

File tree

5 files changed

+40
-74
lines changed

5 files changed

+40
-74
lines changed

src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+25-70
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
337337
protected static final ClassNode ITERABLE_TYPE = ClassHelper.make(Iterable.class);
338338
private static final ClassNode SET_TYPE = ClassHelper.make(Set.class);
339339

340-
private static final List<ClassNode> TUPLE_TYPES = Arrays.stream(ClassHelper.TUPLE_CLASSES).map(ClassHelper::makeWithoutCaching).collect(Collectors.toList());
340+
private static final List<ClassNode> TUPLE_TYPES = Arrays.stream(TUPLE_CLASSES).map(ClassHelper::makeWithoutCaching).collect(Collectors.toList());
341341

342342
public static final Statement GENERATED_EMPTY_STATEMENT = EmptyStatement.INSTANCE;
343343

@@ -655,7 +655,7 @@ public void visitVariableExpression(final VariableExpression vexp) {
655655
inferredType = getInferredTypeFromTempInfo(localVariable, inferredType);
656656
if (inferredType != null && !inferredType.equals(OBJECT_TYPE)
657657
&& !inferredType.equals(accessedVariable.getOriginType())) {
658-
vexp.putNodeMetaData(INFERRED_RETURN_TYPE, inferredType);
658+
vexp.putNodeMetaData(INFERRED_TYPE, inferredType);
659659
}
660660
}
661661
}
@@ -764,11 +764,7 @@ public void visitBinaryExpression(final BinaryExpression expression) {
764764
lType = getType(leftExpression);
765765
} else {
766766
if (op != EQUAL && op != ELVIS_EQUAL) {
767-
if (leftExpression instanceof VariableExpression && hasInferredReturnType(leftExpression)) {
768-
lType = getInferredReturnType(leftExpression); // GROOVY-10217
769-
} else {
770-
lType = getType(leftExpression);
771-
}
767+
lType = getType(leftExpression);
772768
} else {
773769
lType = getOriginalDeclarationType(leftExpression);
774770

@@ -1335,23 +1331,17 @@ protected void typeCheckAssignment(final BinaryExpression assignmentExpression,
13351331
// TODO: need errors for write-only too!
13361332
if (addedReadOnlyPropertyError(leftExpression)) return;
13371333

1338-
ClassNode rTypeInferred; // see if any instanceof exists
1339-
if (rightExpression instanceof VariableExpression && hasInferredReturnType(rightExpression) && assignmentExpression.getOperation().getType() == EQUAL) {
1340-
rTypeInferred = getInferredReturnType(rightExpression);
1341-
} else {
1342-
rTypeInferred = rightExpressionType;
1343-
}
1344-
ClassNode rTypeAdjusted = adjustTypeForSpreading(rTypeInferred, leftExpression);
1334+
ClassNode rTypeAdjusted = adjustTypeForSpreading(rightExpressionType, leftExpression);
13451335

13461336
if (!checkCompatibleAssignmentTypes(leftExpressionType, rTypeAdjusted, rightExpression)) {
13471337
if (!extension.handleIncompatibleAssignment(leftExpressionType, rTypeAdjusted, assignmentExpression)) {
1348-
addAssignmentError(leftExpressionType, rTypeInferred, rightExpression);
1338+
addAssignmentError(leftExpressionType, rightExpressionType, rightExpression);
13491339
}
13501340
} else {
13511341
ClassNode lTypeRedirect = leftExpressionType.redirect();
13521342
addPrecisionErrors(lTypeRedirect, leftExpressionType, rTypeAdjusted, rightExpression);
13531343
if (rightExpression instanceof ListExpression) {
1354-
addListAssignmentConstructorErrors(lTypeRedirect, leftExpressionType, rTypeInferred, rightExpression, assignmentExpression);
1344+
addListAssignmentConstructorErrors(lTypeRedirect, leftExpressionType, rightExpressionType, rightExpression, assignmentExpression);
13551345
} else if (rightExpression instanceof MapExpression) {
13561346
addMapAssignmentConstructorErrors(lTypeRedirect, leftExpression, (MapExpression)rightExpression);
13571347
}
@@ -1999,12 +1989,7 @@ public void visitForLoop(final ForStatement forLoop) {
19991989
} else {
20001990
visitStatement(forLoop);
20011991
collectionExpression.visit(this);
2002-
ClassNode collectionType;
2003-
if (collectionExpression instanceof VariableExpression && hasInferredReturnType(collectionExpression)) {
2004-
collectionType = getInferredReturnType(collectionExpression);
2005-
} else {
2006-
collectionType = getType(collectionExpression);
2007-
}
1992+
ClassNode collectionType = getType(collectionExpression);
20081993
ClassNode forLoopVariableType = forLoop.getVariableType();
20091994
ClassNode componentType;
20101995
if (Character_TYPE.equals(getWrapper(forLoopVariableType)) && STRING_TYPE.equals(collectionType)) {
@@ -2271,18 +2256,12 @@ private ClassNode infer(final ClassNode target, final ClassNode source) {
22712256

22722257
protected ClassNode checkReturnType(final ReturnStatement statement) {
22732258
Expression expression = statement.getExpression();
2274-
ClassNode type;
2275-
if (expression instanceof VariableExpression && hasInferredReturnType(expression)) {
2276-
type = getInferredReturnType(expression);
2277-
} else {
2278-
type = getType(expression);
2279-
}
2259+
ClassNode type = getType(expression);
22802260
if (typeCheckingContext.getEnclosingClosure() != null) {
22812261
ClassNode inferredReturnType = getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
22822262
// GROOVY-9995: return ctor call with diamond operator
22832263
if (expression instanceof ConstructorCallExpression) {
2284-
ClassNode inferredClosureReturnType = getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
2285-
if (inferredClosureReturnType != null) inferDiamondType((ConstructorCallExpression) expression, inferredClosureReturnType);
2264+
inferDiamondType((ConstructorCallExpression) expression, inferredReturnType != null ? inferredReturnType : DYNAMIC_TYPE); // GROOVY-10080
22862265
}
22872266
if (inferredReturnType != null && inferredReturnType.equals(STRING_TYPE) && isGStringOrGStringStringLUB(type)) {
22882267
type = STRING_TYPE; // GROOVY-9971: convert GString to String at point of return
@@ -2419,7 +2398,7 @@ protected MethodNode typeCheckMapConstructor(final ConstructorCallExpression cal
24192398

24202399
protected ClassNode[] getArgumentTypes(final ArgumentListExpression args) {
24212400
return args.getExpressions().stream().map(exp ->
2422-
isNullConstant(exp) ? UNKNOWN_PARAMETER_TYPE : getInferredTypeFromTempInfo(exp, getType(exp))
2401+
isNullConstant(exp) ? UNKNOWN_PARAMETER_TYPE : getType(exp)
24232402
).toArray(ClassNode[]::new);
24242403
}
24252404

@@ -3848,11 +3827,7 @@ protected ClassNode getInferredReturnTypeFromWithClosureArgument(final Expressio
38483827

38493828
visitClosureExpression(closure);
38503829

3851-
if (getInferredReturnType(closure) != null) {
3852-
return getInferredReturnType(closure);
3853-
}
3854-
3855-
return null;
3830+
return getInferredReturnType(closure);
38563831
}
38573832

38583833
/**
@@ -4328,7 +4303,6 @@ && isOrImplements(typeOfFalse, typeOfTrue))) { // List/Collection/Iterable : []
43284303
* @param type the inferred type of {@code expr}
43294304
*/
43304305
private ClassNode checkForTargetType(final Expression expr, final ClassNode type) {
4331-
ClassNode sourceType = type;
43324306
ClassNode targetType = null;
43334307
MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod();
43344308
MethodCall enclosingMethodCall = (MethodCall)typeCheckingContext.getEnclosingMethodCall();
@@ -4348,27 +4322,15 @@ && isTypeSource(expr, enclosingMethod)) {
43484322
targetType = enclosingMethod.getReturnType();
43494323
}
43504324

4351-
if (expr instanceof VariableExpression && hasInferredReturnType(expr)) {
4352-
sourceType = getInferredReturnType(expr);
4353-
}
4325+
if (targetType == null)
4326+
targetType = type.getPlainNodeReference();
4327+
if (type == UNKNOWN_PARAMETER_TYPE) return targetType;
43544328

4355-
if (expr instanceof ConstructorCallExpression) { // GROOVY-9972, GROOVY-9983
4356-
// GROOVY-10114: type parameter(s) could be inferred from call arguments
4357-
if (targetType == null) targetType = sourceType.getPlainNodeReference();
4329+
if (expr instanceof ConstructorCallExpression) { // GROOVY-9972, GROOVY-9983, GROOVY-10114
43584330
inferDiamondType((ConstructorCallExpression) expr, targetType);
4359-
return sourceType;
4360-
}
4361-
4362-
if (targetType == null) return sourceType;
4363-
4364-
if (!isPrimitiveType(getUnwrapper(targetType)) && !OBJECT_TYPE.equals(targetType)
4365-
&& !sourceType.isGenericsPlaceHolder() && missesGenericsTypes(sourceType)) {
4366-
// unchecked assignment with ternary/elvis, like "List<T> list = listOfT ?: []"
4367-
// the inferred type is the RHS type "completed" with generics information from LHS
4368-
return GenericsUtils.parameterizeType(targetType, sourceType.getPlainNodeReference());
43694331
}
43704332

4371-
return sourceType != UNKNOWN_PARAMETER_TYPE ? sourceType : targetType;
4333+
return adjustForTargetType(type, targetType); // GROOVY-10688
43724334
}
43734335

43744336
private static ClassNode adjustForTargetType(final ClassNode resultType, final ClassNode targetType) {
@@ -4454,11 +4416,6 @@ private static boolean isEmptyCollection(final Expression expr) {
44544416
|| (expr instanceof MapExpression && ((MapExpression) expr).getMapEntryExpressions().isEmpty());
44554417
}
44564418

4457-
private static boolean hasInferredReturnType(final Expression expression) {
4458-
ClassNode type = expression.getNodeMetaData(INFERRED_RETURN_TYPE);
4459-
return type != null && !type.getName().equals(ClassHelper.OBJECT);
4460-
}
4461-
44624419
@Override
44634420
public void visitTryCatchFinally(final TryCatchStatement statement) {
44644421
List<CatchStatement> catchStatements = statement.getCatchStatements();
@@ -4778,8 +4735,7 @@ protected static ClassNode getGroupOperationResultType(final ClassNode a, final
47784735
protected ClassNode inferComponentType(final ClassNode containerType, final ClassNode indexType) {
47794736
ClassNode componentType = containerType.getComponentType();
47804737
if (componentType == null) {
4781-
// GROOVY-5521
4782-
// try to identify a getAt method
4738+
// GROOVY-5521: check for "getAt" method
47834739
typeCheckingContext.pushErrorCollector();
47844740
MethodCallExpression vcall = callX(localVarX("_hash_", containerType), "getAt", varX("_index_", indexType));
47854741
vcall.setImplicitThis(false); // GROOVY-8943
@@ -4788,10 +4744,9 @@ protected ClassNode inferComponentType(final ClassNode containerType, final Clas
47884744
} finally {
47894745
typeCheckingContext.popErrorCollector();
47904746
}
4791-
return getType(vcall);
4792-
} else {
4793-
return componentType;
4747+
componentType = getType(vcall);
47944748
}
4749+
return componentType;
47954750
}
47964751

47974752
protected MethodNode findMethodOrFail(final Expression expr, final ClassNode receiver, final String name, final ClassNode... args) {
@@ -5312,14 +5267,14 @@ protected ClassNode storeInferredReturnType(final ASTNode node, final ClassNode
53125267
}
53135268

53145269
/**
5315-
* Returns the inferred return type of a closure or a method, if stored on the AST node. This method
5316-
* doesn't perform any type inference by itself.
5270+
* Returns the inferred return type of a closure or method, if stored on the
5271+
* AST node. This method doesn't perform any type inference by itself.
53175272
*
5318-
* @param exp a {@link ClosureExpression} or {@link MethodNode}
5319-
* @return the inferred type, as stored on node metadata.
5273+
* @param node a {@link ClosureExpression} or {@link MethodNode}
5274+
* @return the expected return type
53205275
*/
5321-
protected ClassNode getInferredReturnType(final ASTNode exp) {
5322-
return exp.getNodeMetaData(INFERRED_RETURN_TYPE);
5276+
protected ClassNode getInferredReturnType(final ASTNode node) {
5277+
return node.getNodeMetaData(INFERRED_RETURN_TYPE);
53235278
}
53245279

53255280
protected ClassNode inferListExpressionType(final ListExpression list) {

src/test/groovy/transform/stc/GenericsSTCTest.groovy

-1
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
12291229
}
12301230

12311231
// GROOVY-10080
1232-
@NotYetImplemented
12331232
void testDiamondInferenceFromConstructor11() {
12341233
assertScript '''
12351234
@groovy.transform.TupleConstructor(defaults=false)

src/test/groovy/transform/stc/STCAssignmentTest.groovy

+13
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,19 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
10371037
'''
10381038
}
10391039

1040+
// GROOVY-10308
1041+
void testAssignToNullAfterCall() {
1042+
assertScript '''
1043+
class C<T> {
1044+
T p
1045+
}
1046+
def x = { -> new C<String>() }
1047+
def y = x()
1048+
def z = y.p // false positive: field access error
1049+
y = null
1050+
'''
1051+
}
1052+
10401053
// GROOVY-5798
10411054
void testShouldNotThrowConversionError() {
10421055
assertScript '''

src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy

-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,6 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase {
257257
'''
258258
}
259259

260-
@NotYetImplemented
261260
void testCommonInterface3() {
262261
assertScript '''import static java.util.concurrent.ConcurrentHashMap.*
263262
Set<Integer> integers = false ? new HashSet<>() : newKeySet()

src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333Bug.groovy src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333.groovy

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ package org.codehaus.groovy.classgen.asm.sc.bugs
2121
import groovy.transform.stc.StaticTypeCheckingTestCase
2222
import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
2323

24-
final class Groovy7333Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
24+
final class Groovy7333 extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
2525

2626
// GROOVY-7333
2727
void testIncorrectInstanceOfInference1() {
@@ -49,7 +49,7 @@ final class Groovy7333Bug extends StaticTypeCheckingTestCase implements StaticCo
4949
void test(A a) {
5050
if (a instanceof B) {
5151
@ASTTest(phase=INSTRUCTION_SELECTION, value={
52-
def type = node.rightExpression.getNodeMetaData(INFERRED_RETURN_TYPE)
52+
def type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
5353
assert type.text == 'B' // not '<UnionType:A+B>'
5454
})
5555
def x = a

0 commit comments

Comments
 (0)