Skip to content

Commit

Permalink
GROOVY-8965, GROOVY-10668, GROOVY-10673
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Jun 29, 2022
1 parent e352da5 commit 6ac3591
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1861,6 +1861,29 @@ public void testTypeChecked8917a() {
runConformTest(sources, "[null]");
}

@Test
public void testTypeChecked8965() {
//@formatter:off
String[] sources = {
"Main.groovy",
"@groovy.transform.TypeChecked\n" +
"def test(o) {\n" +
" if (o instanceof Integer || o instanceof Double)\n" +
" o.floatValue()\n" + // CCE: Double cannot be cast to Integer
"}\n" +
"print test(1.2d)\n",
};
//@formatter:on

runNegativeTest(sources,
"----------\n" +
"1. ERROR in Main.groovy (at line 4)\n" +
"\to.floatValue()\n" +
"\t^^^^^^^^^^^^^^\n" +
"Groovy:[Static type checking] - Cannot find matching method java.lang.Object#floatValue(). Please check if the declared type is correct and if the method exists.\n" +
"----------\n");
}

@Test
public void testTypeChecked8974() {
//@formatter:off
Expand Down Expand Up @@ -5930,4 +5953,53 @@ public void testTypeChecked10667() {

runConformTest(sources, "foo");
}

@Test
public void testTypeChecked10668() {
//@formatter:off
String[] sources = {
"Main.groovy",
"@groovy.transform.TypeChecked\n" +
"def toArray(value) {\n" +
" def result\n" +
" if (value instanceof List)\n" +
" result = value.toArray()\n" +
" else if (value instanceof String || value instanceof GString)\n" +
" result = value.toString().split(',')\n" +
" else\n" +
" throw new Exception('not supported')\n" +
" return result\n" +
"}\n" +
"print(toArray([1,2,3]))\n" +
"print(toArray('1,2,3'))\n",
};
//@formatter:on

runConformTest(sources, "[1, 2, 3][1, 2, 3]");
}

@Test
public void testTypeChecked10673() {
//@formatter:off
String[] sources = {
"Main.groovy",
"import java.util.function.Consumer\n" +
"void proc(Consumer<Number> action) {\n" +
" action.accept(1.234)\n" +
"}\n" +
"@groovy.transform.TypeChecked\n" +
"void test() {\n" +
" proc { n ->\n" +
" def c = {\n" +
" print n.intValue()\n" +
" }\n" +
" c()\n" +
" }\n" +
"}\n" +
"test()\n",
};
//@formatter:on

runConformTest(sources, "1");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5879,9 +5879,8 @@ protected ClassNode getType(final ASTNode exp) {
type = typeCheckingContext.controlStructureVariables.get(parameter);
}
// now check for closure override
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) {
type = getTypeFromClosureArguments(parameter, enclosingClosure);
if (type == null && temporaryTypesForExpression == null) {
type = getTypeFromClosureArguments(parameter);
}
if (type != null) {
storeType(vexp, type);
Expand Down Expand Up @@ -5970,25 +5969,26 @@ protected ClassNode getType(final ASTNode exp) {
return ((Expression) exp).getType();
}

private ClassNode getTypeFromClosureArguments(Parameter parameter, TypeCheckingContext.EnclosingClosure enclosingClosure) {
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
ClassNode[] closureParamTypes = (ClassNode[]) closureExpression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
if (closureParamTypes == null) return null;
final Parameter[] parameters = closureExpression.getParameters();
String name = parameter.getName();

if (parameters != null) {
if (parameters.length == 0) {
return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null;
}

for (int index = 0; index < parameters.length; index++) {
if (name.equals(parameters[index].getName())) {
return closureParamTypes.length > index ? closureParamTypes[index] : null;
private ClassNode getTypeFromClosureArguments(final Parameter parameter) {
for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) {
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
if (closureParamTypes != null) {
Parameter[] parameters = closureExpression.getParameters();
if (parameters != null) {
final int n = parameters.length;
String parameterName = parameter.getName();
if (n == 0 && parameterName.equals("it")) {
return closureParamTypes.length > 0 ? closureParamTypes[0] : null;
}
for (int i = 0; i < n; i += 1) {
if (parameterName.equals(parameters[i].getName())) {
return closureParamTypes.length > i ? closureParamTypes[i] : null;
}
}
}
}
}

return null;
}

Expand Down Expand Up @@ -7021,8 +7021,7 @@ private class ParameterVariableExpression extends VariableExpression {
if (inferredType == null) {
inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure
if (inferredType == null) {
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
if (enclosingClosure != null) inferredType = getTypeFromClosureArguments(parameter, enclosingClosure);
inferredType = getTypeFromClosureArguments(parameter); // @ClosureParams or SAM-type coercion
}
setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferredType != null ? inferredType : parameter.getType());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -757,10 +757,9 @@ public void visitBinaryExpression(final BinaryExpression expression) {
typeCheckingContext.pushEnclosingBinaryExpression(expression);
try {
int op = expression.getOperation().getType();
// GRECLIPSE add
if (op == LOGICAL_OR) {
// GRECLIPSE add -- GROOVY-7971, GROOVY-8965
if (op == LOGICAL_OR)
typeCheckingContext.pushTemporaryTypeInfo();
}
// GRECLIPSE end
Expression leftExpression = expression.getLeftExpression();
Expression rightExpression = expression.getRightExpression();
Expand Down Expand Up @@ -4192,19 +4191,6 @@ protected List<Receiver<String>> makeOwnerList(final Expression objectExpression
Receiver.make(typeCheckingContext.getEnclosingClassNode()));
addReceivers(owners, enclosingClass, typeCheckingContext.delegationMetadata.getParent(), "owner.");
} else {
if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) { // GROOVY-10180, et al.
List<ClassNode> instanceofTypes = getTemporaryTypesForExpression(objectExpression);
if (instanceofTypes != null && !instanceofTypes.isEmpty()) {
ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0)
: new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY));
owners.add(Receiver.make(instanceofType));
}
}
if (typeCheckingContext.lastImplicitItType != null
&& objectExpression instanceof VariableExpression
&& ((Variable) objectExpression).getName().equals("it")) {
owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
}
if (isClassClassNodeWrappingConcreteType(receiver)) {
ClassNode staticType = receiver.getGenericsTypes()[0].getType();
owners.add(Receiver.make(staticType)); // Type from Class<Type>
Expand All @@ -4218,6 +4204,19 @@ protected List<Receiver<String>> makeOwnerList(final Expression objectExpression
owners.add(Receiver.make(OBJECT_TYPE));
}
}
if (typeCheckingContext.lastImplicitItType != null
&& objectExpression instanceof VariableExpression
&& ((Variable) objectExpression).getName().equals("it")) {
owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
}
if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) {
List<ClassNode> instanceofTypes = getTemporaryTypesForExpression(objectExpression);
if (instanceofTypes != null && !instanceofTypes.isEmpty()) {
ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0)
: new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY));
owners.add(Receiver.make(instanceofType));
}
}
}
return owners;
}
Expand Down Expand Up @@ -5509,9 +5508,8 @@ protected ClassNode getType(final ASTNode exp) {
type = typeCheckingContext.controlStructureVariables.get(parameter);
}
// now check for closure override
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) {
type = getTypeFromClosureArguments(parameter, enclosingClosure);
if (type == null && temporaryTypesForExpression == null) {
type = getTypeFromClosureArguments(parameter);
}
if (type != null) {
storeType(vexp, type);
Expand Down Expand Up @@ -5601,25 +5599,26 @@ protected ClassNode getType(final ASTNode exp) {
return ((Expression) exp).getType();
}

private ClassNode getTypeFromClosureArguments(final Parameter parameter, final TypeCheckingContext.EnclosingClosure enclosingClosure) {
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
if (closureParamTypes == null) return null;
Parameter[] parameters = closureExpression.getParameters();
String name = parameter.getName();

if (parameters != null) {
if (parameters.length == 0) {
return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null;
}

for (int index = 0; index < parameters.length; index++) {
if (name.equals(parameters[index].getName())) {
return closureParamTypes.length > index ? closureParamTypes[index] : null;
private ClassNode getTypeFromClosureArguments(final Parameter parameter) {
for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) {
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
if (closureParamTypes != null) {
Parameter[] parameters = closureExpression.getParameters();
if (parameters != null) {
final int n = parameters.length;
String parameterName = parameter.getName();
if (n == 0 && parameterName.equals("it")) {
return closureParamTypes.length > 0 ? closureParamTypes[0] : null;
}
for (int i = 0; i < n; i += 1) {
if (parameterName.equals(parameters[i].getName())) {
return closureParamTypes.length > i ? closureParamTypes[i] : null;
}
}
}
}
}

return null;
}

Expand Down Expand Up @@ -6664,8 +6663,7 @@ private class ParameterVariableExpression extends VariableExpression {
if (inferredType == null) {
inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure
if (inferredType == null) {
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
if (enclosingClosure != null) inferredType = getTypeFromClosureArguments(parameter, enclosingClosure);
inferredType = getTypeFromClosureArguments(parameter); // @ClosureParams or SAM-type coercion
}
setNodeMetaData(INFERRED_TYPE, inferredType != null ? inferredType : parameter.getType()); // to parameter
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5078,9 +5078,8 @@ protected ClassNode getType(final ASTNode node) {
type = typeCheckingContext.controlStructureVariables.get(parameter);
}
// now check for closure override
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) {
type = getTypeFromClosureArguments(parameter, enclosingClosure);
if (type == null && temporaryTypesForExpression == null) {
type = getTypeFromClosureArguments(parameter);
}
if (type != null) {
storeType(vexp, type);
Expand Down Expand Up @@ -5159,25 +5158,26 @@ protected ClassNode getType(final ASTNode node) {
return ((Expression) node).getType();
}

private ClassNode getTypeFromClosureArguments(final Parameter parameter, final TypeCheckingContext.EnclosingClosure enclosingClosure) {
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
if (closureParamTypes == null) return null;
Parameter[] parameters = closureExpression.getParameters();
String name = parameter.getName();

if (parameters != null) {
if (parameters.length == 0) {
return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null;
}

for (int index = 0; index < parameters.length; index++) {
if (name.equals(parameters[index].getName())) {
return closureParamTypes.length > index ? closureParamTypes[index] : null;
private ClassNode getTypeFromClosureArguments(final Parameter parameter) {
for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) {
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
if (closureParamTypes != null) {
Parameter[] parameters = closureExpression.getParameters();
if (parameters != null) {
final int n = parameters.length;
String parameterName = parameter.getName();
if (n == 0 && parameterName.equals("it")) {
return closureParamTypes.length > 0 ? closureParamTypes[0] : null;
}
for (int i = 0; i < n; i += 1) {
if (parameterName.equals(parameters[i].getName())) {
return closureParamTypes.length > i ? closureParamTypes[i] : null;
}
}
}
}
}

return null;
}

Expand Down Expand Up @@ -6009,8 +6009,7 @@ private class ParameterVariableExpression extends VariableExpression {
if (inferredType == null) {
inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure
if (inferredType == null) {
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
if (enclosingClosure != null) inferredType = getTypeFromClosureArguments(parameter, enclosingClosure);
inferredType = getTypeFromClosureArguments(parameter); // @ClosureParams or SAM-type coercion
}
setNodeMetaData(INFERRED_TYPE, inferredType != null ? inferredType : parameter.getType()); // GROOVY-10651
}
Expand Down

0 comments on commit 6ac3591

Please sign in to comment.