Skip to content

Commit

Permalink
GROOVY-10308
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Oct 24, 2021
1 parent 62910e5 commit bd6db52
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6421,6 +6421,28 @@ public void testCompileStatic10282() {
runConformTest(sources, "----------");
}

@Test
public void testCompileStatic10308() {
//@formatter:off
String[] sources = {
"Main.groovy",
"class C<T> {\n" +
" T p\n" +
"}\n" +
"@groovy.transform.CompileStatic\n" +
"void test() {\n" +
" def x = { -> new C<String>() }\n" +
" def y = x()\n" +
" def z = y.p\n" +
" y = null\n" +
"}\n" +
"test()\n",
};
//@formatter:on

runConformTest(sources);
}

@Test
public void testCompileStatic10319() {
//@formatter:off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ public void visitVariableExpression(VariableExpression vexp) {

ClassNode inferredType = getInferredTypeFromTempInfo(vexp, null);
if (inferredType != null && !inferredType.equals(OBJECT_TYPE)) {
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferredType);
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferredType); // GROOVY-9454
} else {
storeType(vexp, getType(vexp));
}
Expand Down Expand Up @@ -722,10 +722,15 @@ public void visitVariableExpression(VariableExpression vexp) {

if (variable != null) {
ClassNode inferredType = getInferredTypeFromTempInfo(variable, (ClassNode) variable.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE));
// instanceof applies, stash away the type, reusing key used elsewhere
/* GRECLIPSE edit -- GROOVY-10102, GROOVY-10179, GROOVY-10217, GROOVY-10308, et al.
if (inferredType != null && !inferredType.getName().equals("java.lang.Object")) {
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferredType);
}
*/
if (inferredType != null && !inferredType.equals(OBJECT_TYPE) && !inferredType.equals(accessedVariable.getType())) {
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferredType);
}
// GRECLIPSE end
}
}
return;
Expand Down Expand Up @@ -888,8 +893,6 @@ public void visitBinaryExpression(final BinaryExpression expression) {
} else if (isClosureWithType(lType) && rightExpression instanceof ClosureExpression) {
storeInferredReturnType(rightExpression, getCombinedBoundType(lType.getGenericsTypes()[0]));
}
} else if (leftExpression instanceof VariableExpression && hasInferredReturnType(leftExpression)) {
lType = getInferredReturnType(leftExpression);
} else {
lType = getType(leftExpression);
}
Expand Down Expand Up @@ -1033,7 +1036,6 @@ else if (GenericsUtils.hasUnresolvedGenerics(resultType)) {
resultType = originType;
}
*/

// track conditional assignment
if (!isNullConstant(rightExpression)
&& leftExpression instanceof VariableExpression
Expand Down Expand Up @@ -1446,7 +1448,7 @@ private void addListAssignmentConstructorErrors(
ClassNode[] args = getArgumentTypes(argList);
MethodNode methodNode = checkGroovyStyleConstructor(leftRedirect, args, assignmentExpression);
if (methodNode != null) {
rightExpression.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, methodNode);
rightExpression.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, methodNode);
}
} else if (!implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, leftRedirect)
&& implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
Expand Down Expand Up @@ -1574,23 +1576,17 @@ protected void typeCheckAssignment(

if (addedReadOnlyPropertyError(leftExpression)) return;

ClassNode rTypeInferred, rTypeWrapped; // check for instanceof and spreading
if (rightExpression instanceof VariableExpression && hasInferredReturnType(rightExpression) && assignmentExpression.getOperation().getType() == ASSIGN) {
rTypeInferred = getInferredReturnType(rightExpression);
} else {
rTypeInferred = rightExpressionType;
}
rTypeWrapped = adjustTypeForSpreading(rTypeInferred, leftExpression);
ClassNode rTypeWrapped = adjustTypeForSpreading(rightExpressionType, leftExpression);

if (!checkCompatibleAssignmentTypes(leftExpressionType, rTypeWrapped, rightExpression)) {
if (!extension.handleIncompatibleAssignment(leftExpressionType, rTypeInferred, assignmentExpression)) {
addAssignmentError(leftExpressionType, rTypeInferred, rightExpression);
if (!extension.handleIncompatibleAssignment(leftExpressionType, rightExpressionType, assignmentExpression)) {
addAssignmentError(leftExpressionType, rightExpressionType, rightExpression);
}
} else {
ClassNode lTypeRedirect = leftExpressionType.redirect();
addPrecisionErrors(lTypeRedirect, leftExpressionType, rTypeInferred, rightExpression);
addPrecisionErrors(lTypeRedirect, leftExpressionType, rightExpressionType, rightExpression);
if (rightExpression instanceof ListExpression) {
addListAssignmentConstructorErrors(lTypeRedirect, leftExpressionType, rTypeInferred, rightExpression, assignmentExpression);
addListAssignmentConstructorErrors(lTypeRedirect, leftExpressionType, rightExpressionType, rightExpression, assignmentExpression);
} else if (rightExpression instanceof MapExpression) {
addMapAssignmentConstructorErrors(lTypeRedirect, leftExpression, rightExpression);
}
Expand Down Expand Up @@ -1844,7 +1840,7 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
// skip property/accessor checks for "x.@field"
if (storeField(field, isAttributeExpression, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
/* GRECLIPSE edit -- GROOVY-5450
pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
pexp.removeNodeMetaData(READONLY_PROPERTY);
*/
return true;
} else if (isAttributeExpression) {
Expand All @@ -1854,7 +1850,7 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
// skip property/accessor checks for "field", "this.field", "this.with { field }", etc. in declaring class of field
if (storeField(field, enclosingTypes.contains(current), pexp, receiverType, visitor, receiver.getData(), !readMode)) {
/* GRECLIPSE edit -- GROOVY-5450
pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
pexp.removeNodeMetaData(READONLY_PROPERTY);
*/
return true;
}
Expand Down Expand Up @@ -1882,7 +1878,9 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
ClassNode cn = inferReturnTypeGenerics(current, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
storeInferredTypeForPropertyExpression(pexp, cn);
storeTargetMethod(pexp, getter);
pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
/* GRECLIPSE edit -- GROOVY-5450
pexp.removeNodeMetaData(READONLY_PROPERTY);
*/
String delegationData = receiver.getData();
if (delegationData != null)
pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
Expand Down Expand Up @@ -1914,10 +1912,10 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
return true;
/* GRECLIPSE edit -- GROOVY-9127
} else if (propertyNode == null) {
if (field != null && hasAccessToField(typeCheckingContext.getEnclosingClassNode(), field)) {
pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
if (field != null && hasAccessToField(field, typeCheckingContext.getEnclosingClassNode())) {
pexp.removeNodeMetaData(READONLY_PROPERTY);
} else if (getter != null) {
pexp.putNodeMetaData(StaticTypesMarker.READONLY_PROPERTY, Boolean.TRUE);
pexp.putNodeMetaData(READONLY_PROPERTY, Boolean.TRUE);
}
*/
} else if (getter != null && field == null) {
Expand Down Expand Up @@ -2367,16 +2365,7 @@ public void visitForLoop(final ForStatement forLoop) {
super.visitForLoop(forLoop);
} else {
collectionExpression.visit(this);
/* GRECLIPSE edit -- GROOVY-10179
final ClassNode collectionType = getType(collectionExpression);
*/
ClassNode collectionType;
if (collectionExpression instanceof VariableExpression && hasInferredReturnType(collectionExpression)) {
collectionType = getInferredReturnType(collectionExpression);
} else {
collectionType = getType(collectionExpression);
}
// GRECLIPSE end
ClassNode forLoopVariableType = forLoop.getVariableType();
ClassNode componentType;
if (Character_TYPE.equals(ClassHelper.getWrapper(forLoopVariableType)) && STRING_TYPE.equals(collectionType)) {
Expand Down Expand Up @@ -2729,7 +2718,7 @@ private ClassNode infer(ClassNode target, ClassNode source) {
varX("{source}", source)
);
virtualDecl.visit(this);
ClassNode newlyInferred = (ClassNode) virtualDecl.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
ClassNode newlyInferred = (ClassNode) virtualDecl.getNodeMetaData(INFERRED_TYPE);
return !missesGenericsTypes(newlyInferred) ? newlyInferred : null;
}
Expand All @@ -2748,12 +2737,7 @@ protected ClassNode checkReturnType(final ReturnStatement statement) {
type = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
}
*/
ClassNode type;
if (expression instanceof VariableExpression && hasInferredReturnType(expression)) {
type = getInferredReturnType(expression);
} else {
type = getType(expression);
}
ClassNode type = getType(expression);
if (typeCheckingContext.getEnclosingClosure() != null) {
ClassNode inferredReturnType = getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
if (expression instanceof ConstructorCallExpression) {
Expand Down Expand Up @@ -3236,6 +3220,7 @@ protected void startMethodInference(final MethodNode node, ErrorCollector collec
node.putNodeMetaData(ERROR_COLLECTOR, collector);
}

/* GRECLIPSE edit
protected void addTypeCheckingInfoAnnotation(final MethodNode node) {
// TypeChecked$TypeCheckingInfo can not be applied on constructors
if (node instanceof ConstructorNode) return;
Expand All @@ -3256,6 +3241,7 @@ protected void addTypeCheckingInfoAnnotation(final MethodNode node) {
}
}
}
*/

@Override
public void visitStaticMethodCallExpression(final StaticMethodCallExpression call) {
Expand Down Expand Up @@ -3496,6 +3482,12 @@ private void processNamedParam(AnnotationConstantExpression value, Map<Object, E
}
}

/* GRECLIPSE edit
private boolean isCompatibleType(ClassNode expectedType, boolean b, ClassNode type) {
return b && !isAssignableTo(type, expectedType);
}
*/

/**
* This method is responsible for performing type inference on closure argument types whenever code like this is
* found: <code>foo.collect { it.toUpperCase() }</code>.
Expand Down Expand Up @@ -3523,6 +3515,7 @@ protected void inferClosureParameterTypes(final ClassNode receiver, final Expres
}
/* GRECLIPSE edit -- GROOVY-8917, GROOVY-9347, GROOVY-10049
} else if (isSAMType(param.getOriginType())) {
// SAM coercion
inferSAMType(param, receiver, selectedMethod, InvocationWriter.makeArgumentList(arguments), expression);
}
*/
Expand Down Expand Up @@ -4112,16 +4105,7 @@ public void visitMethodCallExpression(MethodCallExpression call) {

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

/* GRECLIPSE edit
ClassNode receiver = getType(objectExpression);
*/
ClassNode receiver;
if (objectExpression instanceof VariableExpression && hasInferredReturnType(objectExpression)) {
receiver = getInferredReturnType(objectExpression);
} else {
receiver = getType(objectExpression);
}
// GRECLIPSE end
visitMethodCallArguments(receiver, argumentList, false, null);

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

/**
* e.g. c(b(a())), a() and b() are nested method call, but c() is not
* new C(b(a())) a() and b() are nested method call
*
* a().b().c(), a() and b() are sandwiched method call, but c() is not
*
* a().b().c a() and b() are sandwiched method call
*
*/
@SuppressWarnings("unused")
private boolean isNestedOrSandwichedMethodCall() {
return typeCheckingContext.getEnclosingMethodCalls().size() > 1
|| typeCheckingContext.getEnclosingConstructorCalls().size() > 0
|| typeCheckingContext.getEnclosingPropertyExpressions().size() > 0;
}

/**
* A special method handling the "withTrait" call for which the type checker knows more than
* what the type signature is able to tell. If "withTrait" is detected, then a new class node
Expand Down Expand Up @@ -4519,11 +4487,7 @@ protected ClassNode getInferredReturnTypeFromWithClosureArgument(Expression call

visitClosureExpression(closure);

if (getInferredReturnType(closure) != null) {
return getInferredReturnType(closure);
}

return null;
return getInferredReturnType(closure);
}

/**
Expand All @@ -4542,6 +4506,7 @@ protected List<Receiver<String>> makeOwnerList(final Expression objectExpression
owners.add(0, Receiver.<String>make(clazzGT.getType()));
}
if (receiver.isInterface()) {
// GROOVY-xxxx
owners.add(Receiver.<String>make(OBJECT_TYPE));
}
addSelfTypes(receiver, owners);
Expand Down Expand Up @@ -4986,10 +4951,10 @@ public void visitTernaryExpression(final TernaryExpression expression) {
*/
// handle instanceof cases
if (hasInferredReturnType(falseExpression)) {
typeOfFalse = falseExpression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
typeOfFalse = getInferredReturnType(falseExpression);
}
if (hasInferredReturnType(trueExpression)) {
typeOfTrue = trueExpression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
typeOfTrue = getInferredReturnType(trueExpression);
}
/* GRECLIPSE edit -- GROOVY-9972
typeOfFalse = checkForTargetType(falseExpression, typeOfFalse);
Expand Down Expand Up @@ -5235,7 +5200,7 @@ protected ClassNode getResultType(ClassNode left, int op, ClassNode right, Binar
if (leftRedirect.isArray() && implementsInterfaceOrIsSubclassOf(rightRedirect, Collection_TYPE))
return leftRedirect;
if (leftRedirect.implementsInterface(Collection_TYPE) && rightRedirect.implementsInterface(Collection_TYPE)) {
// because of type inference, we must perform an additional check if the right expression
// because of type inferrence, we must perform an additional check if the right expression
// is an empty list expression ([]). In that case and only in that case, the inferred type
// will be wrong, so we will prefer the left type
if (rightExpression instanceof ListExpression) {
Expand Down Expand Up @@ -5770,11 +5735,10 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
collectAllInterfaceMethodsByName(receiver, name, methods);
}
*/
// lookup in DGM methods too
// GRECLIPSE add
if (!"<init>".equals(name) && !"<clinit>".equals(name))
// GRECLIPSE end
findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), receiver, name, args, methods);
if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
// lookup in DGM methods too
findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), receiver, name, args, methods);
}
methods = filterMethodsByVisibility(methods);
List<MethodNode> chosen = chooseBestMethod(receiver, methods, args);
if (!chosen.isEmpty()) return chosen;
Expand Down Expand Up @@ -6423,7 +6387,7 @@ private void resolvePlaceholdersFromImplicitTypeHints(final ClassNode[] actuals,
Expression a = argumentList.getExpression(i);
if (!(a instanceof MethodCallExpression)) continue;
if (((MethodCallExpression) a).isUsingGenerics()) continue;
MethodNode aNode = a.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
MethodNode aNode = a.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
if (aNode == null || aNode.getGenericsTypes() == null) continue;
// and unknown generics
Expand Down Expand Up @@ -6656,7 +6620,8 @@ private static ClassNode convertClosureTypeToSAMType(final Expression expression
}
ClassNode result = applyGenericsContext(placeholders, samType.redirect());
return result;
*/
}
*/
private static ClassNode convertClosureTypeToSAMType(final Expression expression, final ClassNode closureType, final MethodNode sam, final ClassNode samType) {
Map<GenericsTypeName, GenericsType> samTypeConnections = GenericsUtils.extractPlaceholders(samType);
samTypeConnections.replaceAll((xx, gt) -> // GROOVY-9762, GROOVY-9803: reduce "? super T" to "T"
Expand Down Expand Up @@ -6696,8 +6661,8 @@ private static ClassNode convertClosureTypeToSAMType(final Expression expression
}

return applyGenericsContext(samTypeConnections, samType.redirect());
// GRECLIPSE end
}
// GRECLIPSE end

private ClassNode resolveGenericsWithContext(Map<GenericsTypeName, GenericsType> resolvedPlaceholders, ClassNode currentType) {
/* GRECLIPSE edit -- GROOVY-9570
Expand Down Expand Up @@ -7120,11 +7085,11 @@ private static class ParameterVariableExpression extends VariableExpression {
super(parameter);
this.parameter = parameter;
/* GRECLIPSE edit -- GROOVY-6919
ClassNode inferred = parameter.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
ClassNode inferred = parameter.getNodeMetaData(INFERRED_TYPE);
if (inferred == null) {
inferred = infer(parameter);
parameter.setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferred);
parameter.setNodeMetaData(INFERRED_TYPE, inferred);
}
*/
parameter.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE, x -> parameter.getOriginType());
Expand Down
Loading

0 comments on commit bd6db52

Please sign in to comment.