Skip to content

Commit bd6db52

Browse files
committed
GROOVY-10308
1 parent 62910e5 commit bd6db52

File tree

4 files changed

+96
-144
lines changed

4 files changed

+96
-144
lines changed

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

+22
Original file line numberDiff line numberDiff line change
@@ -6421,6 +6421,28 @@ public void testCompileStatic10282() {
64216421
runConformTest(sources, "----------");
64226422
}
64236423

6424+
@Test
6425+
public void testCompileStatic10308() {
6426+
//@formatter:off
6427+
String[] sources = {
6428+
"Main.groovy",
6429+
"class C<T> {\n" +
6430+
" T p\n" +
6431+
"}\n" +
6432+
"@groovy.transform.CompileStatic\n" +
6433+
"void test() {\n" +
6434+
" def x = { -> new C<String>() }\n" +
6435+
" def y = x()\n" +
6436+
" def z = y.p\n" +
6437+
" y = null\n" +
6438+
"}\n" +
6439+
"test()\n",
6440+
};
6441+
//@formatter:on
6442+
6443+
runConformTest(sources);
6444+
}
6445+
64246446
@Test
64256447
public void testCompileStatic10319() {
64266448
//@formatter:off

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

+47-82
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ public void visitVariableExpression(VariableExpression vexp) {
676676

677677
ClassNode inferredType = getInferredTypeFromTempInfo(vexp, null);
678678
if (inferredType != null && !inferredType.equals(OBJECT_TYPE)) {
679-
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferredType);
679+
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferredType); // GROOVY-9454
680680
} else {
681681
storeType(vexp, getType(vexp));
682682
}
@@ -722,10 +722,15 @@ public void visitVariableExpression(VariableExpression vexp) {
722722

723723
if (variable != null) {
724724
ClassNode inferredType = getInferredTypeFromTempInfo(variable, (ClassNode) variable.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE));
725-
// instanceof applies, stash away the type, reusing key used elsewhere
725+
/* GRECLIPSE edit -- GROOVY-10102, GROOVY-10179, GROOVY-10217, GROOVY-10308, et al.
726726
if (inferredType != null && !inferredType.getName().equals("java.lang.Object")) {
727727
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferredType);
728728
}
729+
*/
730+
if (inferredType != null && !inferredType.equals(OBJECT_TYPE) && !inferredType.equals(accessedVariable.getType())) {
731+
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferredType);
732+
}
733+
// GRECLIPSE end
729734
}
730735
}
731736
return;
@@ -888,8 +893,6 @@ public void visitBinaryExpression(final BinaryExpression expression) {
888893
} else if (isClosureWithType(lType) && rightExpression instanceof ClosureExpression) {
889894
storeInferredReturnType(rightExpression, getCombinedBoundType(lType.getGenericsTypes()[0]));
890895
}
891-
} else if (leftExpression instanceof VariableExpression && hasInferredReturnType(leftExpression)) {
892-
lType = getInferredReturnType(leftExpression);
893896
} else {
894897
lType = getType(leftExpression);
895898
}
@@ -1033,7 +1036,6 @@ else if (GenericsUtils.hasUnresolvedGenerics(resultType)) {
10331036
resultType = originType;
10341037
}
10351038
*/
1036-
10371039
// track conditional assignment
10381040
if (!isNullConstant(rightExpression)
10391041
&& leftExpression instanceof VariableExpression
@@ -1446,7 +1448,7 @@ private void addListAssignmentConstructorErrors(
14461448
ClassNode[] args = getArgumentTypes(argList);
14471449
MethodNode methodNode = checkGroovyStyleConstructor(leftRedirect, args, assignmentExpression);
14481450
if (methodNode != null) {
1449-
rightExpression.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, methodNode);
1451+
rightExpression.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, methodNode);
14501452
}
14511453
} else if (!implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, leftRedirect)
14521454
&& implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
@@ -1574,23 +1576,17 @@ protected void typeCheckAssignment(
15741576

15751577
if (addedReadOnlyPropertyError(leftExpression)) return;
15761578

1577-
ClassNode rTypeInferred, rTypeWrapped; // check for instanceof and spreading
1578-
if (rightExpression instanceof VariableExpression && hasInferredReturnType(rightExpression) && assignmentExpression.getOperation().getType() == ASSIGN) {
1579-
rTypeInferred = getInferredReturnType(rightExpression);
1580-
} else {
1581-
rTypeInferred = rightExpressionType;
1582-
}
1583-
rTypeWrapped = adjustTypeForSpreading(rTypeInferred, leftExpression);
1579+
ClassNode rTypeWrapped = adjustTypeForSpreading(rightExpressionType, leftExpression);
15841580

15851581
if (!checkCompatibleAssignmentTypes(leftExpressionType, rTypeWrapped, rightExpression)) {
1586-
if (!extension.handleIncompatibleAssignment(leftExpressionType, rTypeInferred, assignmentExpression)) {
1587-
addAssignmentError(leftExpressionType, rTypeInferred, rightExpression);
1582+
if (!extension.handleIncompatibleAssignment(leftExpressionType, rightExpressionType, assignmentExpression)) {
1583+
addAssignmentError(leftExpressionType, rightExpressionType, rightExpression);
15881584
}
15891585
} else {
15901586
ClassNode lTypeRedirect = leftExpressionType.redirect();
1591-
addPrecisionErrors(lTypeRedirect, leftExpressionType, rTypeInferred, rightExpression);
1587+
addPrecisionErrors(lTypeRedirect, leftExpressionType, rightExpressionType, rightExpression);
15921588
if (rightExpression instanceof ListExpression) {
1593-
addListAssignmentConstructorErrors(lTypeRedirect, leftExpressionType, rTypeInferred, rightExpression, assignmentExpression);
1589+
addListAssignmentConstructorErrors(lTypeRedirect, leftExpressionType, rightExpressionType, rightExpression, assignmentExpression);
15941590
} else if (rightExpression instanceof MapExpression) {
15951591
addMapAssignmentConstructorErrors(lTypeRedirect, leftExpression, rightExpression);
15961592
}
@@ -1844,7 +1840,7 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
18441840
// skip property/accessor checks for "x.@field"
18451841
if (storeField(field, isAttributeExpression, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
18461842
/* GRECLIPSE edit -- GROOVY-5450
1847-
pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
1843+
pexp.removeNodeMetaData(READONLY_PROPERTY);
18481844
*/
18491845
return true;
18501846
} else if (isAttributeExpression) {
@@ -1854,7 +1850,7 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
18541850
// skip property/accessor checks for "field", "this.field", "this.with { field }", etc. in declaring class of field
18551851
if (storeField(field, enclosingTypes.contains(current), pexp, receiverType, visitor, receiver.getData(), !readMode)) {
18561852
/* GRECLIPSE edit -- GROOVY-5450
1857-
pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
1853+
pexp.removeNodeMetaData(READONLY_PROPERTY);
18581854
*/
18591855
return true;
18601856
}
@@ -1882,7 +1878,9 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
18821878
ClassNode cn = inferReturnTypeGenerics(current, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
18831879
storeInferredTypeForPropertyExpression(pexp, cn);
18841880
storeTargetMethod(pexp, getter);
1885-
pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
1881+
/* GRECLIPSE edit -- GROOVY-5450
1882+
pexp.removeNodeMetaData(READONLY_PROPERTY);
1883+
*/
18861884
String delegationData = receiver.getData();
18871885
if (delegationData != null)
18881886
pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
@@ -1914,10 +1912,10 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
19141912
return true;
19151913
/* GRECLIPSE edit -- GROOVY-9127
19161914
} else if (propertyNode == null) {
1917-
if (field != null && hasAccessToField(typeCheckingContext.getEnclosingClassNode(), field)) {
1918-
pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
1915+
if (field != null && hasAccessToField(field, typeCheckingContext.getEnclosingClassNode())) {
1916+
pexp.removeNodeMetaData(READONLY_PROPERTY);
19191917
} else if (getter != null) {
1920-
pexp.putNodeMetaData(StaticTypesMarker.READONLY_PROPERTY, Boolean.TRUE);
1918+
pexp.putNodeMetaData(READONLY_PROPERTY, Boolean.TRUE);
19211919
}
19221920
*/
19231921
} else if (getter != null && field == null) {
@@ -2367,16 +2365,7 @@ public void visitForLoop(final ForStatement forLoop) {
23672365
super.visitForLoop(forLoop);
23682366
} else {
23692367
collectionExpression.visit(this);
2370-
/* GRECLIPSE edit -- GROOVY-10179
23712368
final ClassNode collectionType = getType(collectionExpression);
2372-
*/
2373-
ClassNode collectionType;
2374-
if (collectionExpression instanceof VariableExpression && hasInferredReturnType(collectionExpression)) {
2375-
collectionType = getInferredReturnType(collectionExpression);
2376-
} else {
2377-
collectionType = getType(collectionExpression);
2378-
}
2379-
// GRECLIPSE end
23802369
ClassNode forLoopVariableType = forLoop.getVariableType();
23812370
ClassNode componentType;
23822371
if (Character_TYPE.equals(ClassHelper.getWrapper(forLoopVariableType)) && STRING_TYPE.equals(collectionType)) {
@@ -2729,7 +2718,7 @@ private ClassNode infer(ClassNode target, ClassNode source) {
27292718
varX("{source}", source)
27302719
);
27312720
virtualDecl.visit(this);
2732-
ClassNode newlyInferred = (ClassNode) virtualDecl.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
2721+
ClassNode newlyInferred = (ClassNode) virtualDecl.getNodeMetaData(INFERRED_TYPE);
27332722
27342723
return !missesGenericsTypes(newlyInferred) ? newlyInferred : null;
27352724
}
@@ -2748,12 +2737,7 @@ protected ClassNode checkReturnType(final ReturnStatement statement) {
27482737
type = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
27492738
}
27502739
*/
2751-
ClassNode type;
2752-
if (expression instanceof VariableExpression && hasInferredReturnType(expression)) {
2753-
type = getInferredReturnType(expression);
2754-
} else {
2755-
type = getType(expression);
2756-
}
2740+
ClassNode type = getType(expression);
27572741
if (typeCheckingContext.getEnclosingClosure() != null) {
27582742
ClassNode inferredReturnType = getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
27592743
if (expression instanceof ConstructorCallExpression) {
@@ -3236,6 +3220,7 @@ protected void startMethodInference(final MethodNode node, ErrorCollector collec
32363220
node.putNodeMetaData(ERROR_COLLECTOR, collector);
32373221
}
32383222

3223+
/* GRECLIPSE edit
32393224
protected void addTypeCheckingInfoAnnotation(final MethodNode node) {
32403225
// TypeChecked$TypeCheckingInfo can not be applied on constructors
32413226
if (node instanceof ConstructorNode) return;
@@ -3256,6 +3241,7 @@ protected void addTypeCheckingInfoAnnotation(final MethodNode node) {
32563241
}
32573242
}
32583243
}
3244+
*/
32593245

32603246
@Override
32613247
public void visitStaticMethodCallExpression(final StaticMethodCallExpression call) {
@@ -3496,6 +3482,12 @@ private void processNamedParam(AnnotationConstantExpression value, Map<Object, E
34963482
}
34973483
}
34983484

3485+
/* GRECLIPSE edit
3486+
private boolean isCompatibleType(ClassNode expectedType, boolean b, ClassNode type) {
3487+
return b && !isAssignableTo(type, expectedType);
3488+
}
3489+
*/
3490+
34993491
/**
35003492
* This method is responsible for performing type inference on closure argument types whenever code like this is
35013493
* found: <code>foo.collect { it.toUpperCase() }</code>.
@@ -3523,6 +3515,7 @@ protected void inferClosureParameterTypes(final ClassNode receiver, final Expres
35233515
}
35243516
/* GRECLIPSE edit -- GROOVY-8917, GROOVY-9347, GROOVY-10049
35253517
} else if (isSAMType(param.getOriginType())) {
3518+
// SAM coercion
35263519
inferSAMType(param, receiver, selectedMethod, InvocationWriter.makeArgumentList(arguments), expression);
35273520
}
35283521
*/
@@ -4112,16 +4105,7 @@ public void visitMethodCallExpression(MethodCallExpression call) {
41124105

41134106
// for arguments, we need to visit closures *after* the method has been chosen
41144107

4115-
/* GRECLIPSE edit
41164108
ClassNode receiver = getType(objectExpression);
4117-
*/
4118-
ClassNode receiver;
4119-
if (objectExpression instanceof VariableExpression && hasInferredReturnType(objectExpression)) {
4120-
receiver = getInferredReturnType(objectExpression);
4121-
} else {
4122-
receiver = getType(objectExpression);
4123-
}
4124-
// GRECLIPSE end
41254109
visitMethodCallArguments(receiver, argumentList, false, null);
41264110

41274111
ClassNode[] args = getArgumentTypes(argumentList);
@@ -4436,22 +4420,6 @@ private int getResolveStrategy(final Parameter parameter) {
44364420
}
44374421
// GRECLIPSE end
44384422

4439-
/**
4440-
* e.g. c(b(a())), a() and b() are nested method call, but c() is not
4441-
* new C(b(a())) a() and b() are nested method call
4442-
*
4443-
* a().b().c(), a() and b() are sandwiched method call, but c() is not
4444-
*
4445-
* a().b().c a() and b() are sandwiched method call
4446-
*
4447-
*/
4448-
@SuppressWarnings("unused")
4449-
private boolean isNestedOrSandwichedMethodCall() {
4450-
return typeCheckingContext.getEnclosingMethodCalls().size() > 1
4451-
|| typeCheckingContext.getEnclosingConstructorCalls().size() > 0
4452-
|| typeCheckingContext.getEnclosingPropertyExpressions().size() > 0;
4453-
}
4454-
44554423
/**
44564424
* A special method handling the "withTrait" call for which the type checker knows more than
44574425
* what the type signature is able to tell. If "withTrait" is detected, then a new class node
@@ -4519,11 +4487,7 @@ protected ClassNode getInferredReturnTypeFromWithClosureArgument(Expression call
45194487

45204488
visitClosureExpression(closure);
45214489

4522-
if (getInferredReturnType(closure) != null) {
4523-
return getInferredReturnType(closure);
4524-
}
4525-
4526-
return null;
4490+
return getInferredReturnType(closure);
45274491
}
45284492

45294493
/**
@@ -4542,6 +4506,7 @@ protected List<Receiver<String>> makeOwnerList(final Expression objectExpression
45424506
owners.add(0, Receiver.<String>make(clazzGT.getType()));
45434507
}
45444508
if (receiver.isInterface()) {
4509+
// GROOVY-xxxx
45454510
owners.add(Receiver.<String>make(OBJECT_TYPE));
45464511
}
45474512
addSelfTypes(receiver, owners);
@@ -4986,10 +4951,10 @@ public void visitTernaryExpression(final TernaryExpression expression) {
49864951
*/
49874952
// handle instanceof cases
49884953
if (hasInferredReturnType(falseExpression)) {
4989-
typeOfFalse = falseExpression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
4954+
typeOfFalse = getInferredReturnType(falseExpression);
49904955
}
49914956
if (hasInferredReturnType(trueExpression)) {
4992-
typeOfTrue = trueExpression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
4957+
typeOfTrue = getInferredReturnType(trueExpression);
49934958
}
49944959
/* GRECLIPSE edit -- GROOVY-9972
49954960
typeOfFalse = checkForTargetType(falseExpression, typeOfFalse);
@@ -5235,7 +5200,7 @@ protected ClassNode getResultType(ClassNode left, int op, ClassNode right, Binar
52355200
if (leftRedirect.isArray() && implementsInterfaceOrIsSubclassOf(rightRedirect, Collection_TYPE))
52365201
return leftRedirect;
52375202
if (leftRedirect.implementsInterface(Collection_TYPE) && rightRedirect.implementsInterface(Collection_TYPE)) {
5238-
// because of type inference, we must perform an additional check if the right expression
5203+
// because of type inferrence, we must perform an additional check if the right expression
52395204
// is an empty list expression ([]). In that case and only in that case, the inferred type
52405205
// will be wrong, so we will prefer the left type
52415206
if (rightExpression instanceof ListExpression) {
@@ -5770,11 +5735,10 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
57705735
collectAllInterfaceMethodsByName(receiver, name, methods);
57715736
}
57725737
*/
5773-
// lookup in DGM methods too
5774-
// GRECLIPSE add
5775-
if (!"<init>".equals(name) && !"<clinit>".equals(name))
5776-
// GRECLIPSE end
5777-
findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), receiver, name, args, methods);
5738+
if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
5739+
// lookup in DGM methods too
5740+
findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), receiver, name, args, methods);
5741+
}
57785742
methods = filterMethodsByVisibility(methods);
57795743
List<MethodNode> chosen = chooseBestMethod(receiver, methods, args);
57805744
if (!chosen.isEmpty()) return chosen;
@@ -6423,7 +6387,7 @@ private void resolvePlaceholdersFromImplicitTypeHints(final ClassNode[] actuals,
64236387
Expression a = argumentList.getExpression(i);
64246388
if (!(a instanceof MethodCallExpression)) continue;
64256389
if (((MethodCallExpression) a).isUsingGenerics()) continue;
6426-
MethodNode aNode = a.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
6390+
MethodNode aNode = a.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
64276391
if (aNode == null || aNode.getGenericsTypes() == null) continue;
64286392
64296393
// and unknown generics
@@ -6656,7 +6620,8 @@ private static ClassNode convertClosureTypeToSAMType(final Expression expression
66566620
}
66576621
ClassNode result = applyGenericsContext(placeholders, samType.redirect());
66586622
return result;
6659-
*/
6623+
}
6624+
*/
66606625
private static ClassNode convertClosureTypeToSAMType(final Expression expression, final ClassNode closureType, final MethodNode sam, final ClassNode samType) {
66616626
Map<GenericsTypeName, GenericsType> samTypeConnections = GenericsUtils.extractPlaceholders(samType);
66626627
samTypeConnections.replaceAll((xx, gt) -> // GROOVY-9762, GROOVY-9803: reduce "? super T" to "T"
@@ -6696,8 +6661,8 @@ private static ClassNode convertClosureTypeToSAMType(final Expression expression
66966661
}
66976662

66986663
return applyGenericsContext(samTypeConnections, samType.redirect());
6699-
// GRECLIPSE end
67006664
}
6665+
// GRECLIPSE end
67016666

67026667
private ClassNode resolveGenericsWithContext(Map<GenericsTypeName, GenericsType> resolvedPlaceholders, ClassNode currentType) {
67036668
/* GRECLIPSE edit -- GROOVY-9570
@@ -7120,11 +7085,11 @@ private static class ParameterVariableExpression extends VariableExpression {
71207085
super(parameter);
71217086
this.parameter = parameter;
71227087
/* GRECLIPSE edit -- GROOVY-6919
7123-
ClassNode inferred = parameter.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
7088+
ClassNode inferred = parameter.getNodeMetaData(INFERRED_TYPE);
71247089
if (inferred == null) {
71257090
inferred = infer(parameter);
71267091
7127-
parameter.setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferred);
7092+
parameter.setNodeMetaData(INFERRED_TYPE, inferred);
71287093
}
71297094
*/
71307095
parameter.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE, x -> parameter.getOriginType());

0 commit comments

Comments
 (0)