Skip to content

Commit

Permalink
GROOVY-10088
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed May 13, 2021
1 parent 74e24d8 commit a05d059
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2655,4 +2655,32 @@ public void testTypeChecked10067() {

runConformTest(sources);
}

@Test
public void testTypeChecked10088() {
//@formatter:off
String[] sources = {
"Main.groovy",
"@groovy.transform.TypeChecked\n" +
"void test() {\n" +
" new D<Number>().p = 'x'\n" +
"}\n",

"Types.groovy",
"class C<T> {\n" +
" void setP(T t) { }\n" +
"}\n" +
"class D<X> extends C<X> {\n" +
"}\n",
};
//@formatter:on

runNegativeTest(sources,
"----------\n" +
"1. ERROR in Main.groovy (at line 3)\n" +
"\tnew D<Number>().p = 'x'\n" +
"\t^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Groovy:[Static type checking] - Cannot assign value of type java.lang.String to variable of type java.lang.Number\n" +
"----------\n");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1120,8 +1120,16 @@ private boolean ensureValidSetter(final Expression expression, final Expression
// but we must check if the binary expression is an assignment
// because we need to check if a setter uses @DelegatesTo
VariableExpression ve = varX("%", setterInfo.receiverType);
// GRECLIPSE add -- GROOVY-8409, et al.
// GRECLIPSE add -- GROOVY-8409, GROOVY-10088, et al.
ve.setType(setterInfo.receiverType);
Function<MethodNode, ClassNode> firstParamType = (method) -> {
ClassNode type = method.getParameters()[0].getOriginType();
if (!method.isStatic() && !(method instanceof ExtensionMethodNode) && GenericsUtils.hasUnresolvedGenerics(type)) {
Map<GenericsTypeName, GenericsType> spec = extractPlaceHolders(null, setterInfo.receiverType, method.getDeclaringClass());
type = applyGenericsContext(spec, type);
}
return type;
};
// GRECLIPSE end
// for compound assignment "x op= y" find type as if it was "x = (x op y)"
final Expression newRightExpression = isCompoundAssignment(expression)
Expand All @@ -1135,7 +1143,7 @@ private boolean ensureValidSetter(final Expression expression, final Expression
// this may happen if there's a setter of type boolean/String/Class, and that we are using the property
// notation AND that the RHS is not a boolean/String/Class
for (MethodNode setter : setterInfo.setters) {
ClassNode type = getWrapper(setter.getParameters()[0].getOriginType());
ClassNode type = getWrapper(firstParamType.apply(setter));
if (Boolean_TYPE.equals(type) || STRING_TYPE.equals(type) || CLASS_Type.equals(type)) {
call = callX(ve, setterInfo.name, castX(type, newRightExpression));
call.setImplicitThis(false);
Expand All @@ -1150,13 +1158,14 @@ private boolean ensureValidSetter(final Expression expression, final Expression
if (directSetterCandidate != null) {
for (MethodNode setter : setterInfo.setters) {
if (setter == directSetterCandidate) {
leftExpression.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, directSetterCandidate);
storeType(leftExpression, getType(newRightExpression));
leftExpression.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, setter);
leftExpression.removeNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
storeType(leftExpression, firstParamType.apply(setter));
break;
}
}
} else {
ClassNode firstSetterType = setterInfo.setters.iterator().next().getParameters()[0].getOriginType();
ClassNode firstSetterType = firstParamType.apply(setterInfo.setters.get(0));
addAssignmentError(firstSetterType, getType(newRightExpression), expression);
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1000,8 +1000,16 @@ private boolean ensureValidSetter(final Expression expression, final Expression
// but we must check if the binary expression is an assignment
// because we need to check if a setter uses @DelegatesTo
VariableExpression ve = varX("%", setterInfo.receiverType);
// GRECLIPSE add -- GROOVY-8409, et al.
// GRECLIPSE add -- GROOVY-8409, GROOVY-10088, et al.
ve.setType(setterInfo.receiverType);
Function<MethodNode, ClassNode> firstParamType = (method) -> {
ClassNode type = method.getParameters()[0].getOriginType();
if (!method.isStatic() && !(method instanceof ExtensionMethodNode) && GenericsUtils.hasUnresolvedGenerics(type)) {
Map<GenericsTypeName, GenericsType> spec = extractPlaceHolders(null, setterInfo.receiverType, method.getDeclaringClass());
type = applyGenericsContext(spec, type);
}
return type;
};
// GRECLIPSE end
// for compound assignment "x op= y" find type as if it was "x = (x op y)"
Expression newRightExpression = isCompoundAssignment(expression)
Expand All @@ -1015,7 +1023,7 @@ private boolean ensureValidSetter(final Expression expression, final Expression
// this may happen if there's a setter of type boolean/String/Class, and that we are using the property
// notation AND that the RHS is not a boolean/String/Class
for (MethodNode setter : setterInfo.setters) {
ClassNode type = getWrapper(setter.getParameters()[0].getOriginType());
ClassNode type = getWrapper(firstParamType.apply(setter));
if (Boolean_TYPE.equals(type) || STRING_TYPE.equals(type) || CLASS_Type.equals(type)) {
call = callX(ve, setterInfo.name, castX(type, newRightExpression));
call.setImplicitThis(false);
Expand All @@ -1032,13 +1040,13 @@ private boolean ensureValidSetter(final Expression expression, final Expression
if (setter == directSetterCandidate) {
leftExpression.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, directSetterCandidate);
leftExpression.removeNodeMetaData(INFERRED_TYPE); // clear assumption
storeType(leftExpression, getType(newRightExpression));
storeType(leftExpression, firstParamType.apply(setter));
break;
}
}
return false;
} else {
ClassNode firstSetterType = setterInfo.setters.get(0).getParameters()[0].getOriginType();
ClassNode firstSetterType = firstParamType.apply(setterInfo.setters.get(0));
addAssignmentError(firstSetterType, getType(newRightExpression), expression);
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1003,12 +1003,22 @@ private boolean ensureValidSetter(final Expression expression, final Expression
visitMethodCallExpression(call);
return call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
};
// GRECLIPSE add -- GROOVY-10088
Function<MethodNode, ClassNode> setterType = setter -> {
ClassNode type = setter.getParameters()[0].getOriginType();
if (!setter.isStatic() && !(setter instanceof ExtensionMethodNode) && GenericsUtils.hasUnresolvedGenerics(type)) {
Map<GenericsTypeName, GenericsType> spec = extractPlaceHolders(null, setterInfo.receiverType, setter.getDeclaringClass());
type = applyGenericsContext(spec, type);
}
return type;
};
// GRECLIPSE end

MethodNode methodTarget = setterCall.apply(newRightExpression);
if (methodTarget == null && !isCompoundAssignment(expression)) {
// if no direct match, try implicit conversion
for (MethodNode setter : setterInfo.setters) {
ClassNode lType = setter.getParameters()[0].getOriginType();
ClassNode lType = setterType.apply(setter);
ClassNode rType = getDeclaredOrInferredType(newRightExpression);
if (checkCompatibleAssignmentTypes(lType, rType, newRightExpression, false)) {
methodTarget = setterCall.apply(castX(lType, newRightExpression));
Expand All @@ -1023,14 +1033,14 @@ private boolean ensureValidSetter(final Expression expression, final Expression
for (MethodNode setter : setterInfo.setters) {
if (setter == methodTarget) {
leftExpression.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, methodTarget);
leftExpression.removeNodeMetaData(INFERRED_TYPE); // clear the assumption
storeType(leftExpression, methodTarget.getParameters()[0].getOriginType());
leftExpression.removeNodeMetaData(INFERRED_TYPE); // clear assumption
storeType(leftExpression, setterType.apply(methodTarget));
break;
}
}
return false;
} else {
ClassNode firstSetterType = setterInfo.setters.get(0).getParameters()[0].getOriginType();
ClassNode firstSetterType = setterType.apply(setterInfo.setters.get(0));
addAssignmentError(firstSetterType, getType(newRightExpression), expression);
return true;
}
Expand Down

0 comments on commit a05d059

Please sign in to comment.