Skip to content

Commit 6ac3591

Browse files
committed
GROOVY-8965, GROOVY-10668, GROOVY-10673
1 parent e352da5 commit 6ac3591

File tree

4 files changed

+147
-79
lines changed

4 files changed

+147
-79
lines changed

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

+72
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,29 @@ public void testTypeChecked8917a() {
18611861
runConformTest(sources, "[null]");
18621862
}
18631863

1864+
@Test
1865+
public void testTypeChecked8965() {
1866+
//@formatter:off
1867+
String[] sources = {
1868+
"Main.groovy",
1869+
"@groovy.transform.TypeChecked\n" +
1870+
"def test(o) {\n" +
1871+
" if (o instanceof Integer || o instanceof Double)\n" +
1872+
" o.floatValue()\n" + // CCE: Double cannot be cast to Integer
1873+
"}\n" +
1874+
"print test(1.2d)\n",
1875+
};
1876+
//@formatter:on
1877+
1878+
runNegativeTest(sources,
1879+
"----------\n" +
1880+
"1. ERROR in Main.groovy (at line 4)\n" +
1881+
"\to.floatValue()\n" +
1882+
"\t^^^^^^^^^^^^^^\n" +
1883+
"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" +
1884+
"----------\n");
1885+
}
1886+
18641887
@Test
18651888
public void testTypeChecked8974() {
18661889
//@formatter:off
@@ -5930,4 +5953,53 @@ public void testTypeChecked10667() {
59305953

59315954
runConformTest(sources, "foo");
59325955
}
5956+
5957+
@Test
5958+
public void testTypeChecked10668() {
5959+
//@formatter:off
5960+
String[] sources = {
5961+
"Main.groovy",
5962+
"@groovy.transform.TypeChecked\n" +
5963+
"def toArray(value) {\n" +
5964+
" def result\n" +
5965+
" if (value instanceof List)\n" +
5966+
" result = value.toArray()\n" +
5967+
" else if (value instanceof String || value instanceof GString)\n" +
5968+
" result = value.toString().split(',')\n" +
5969+
" else\n" +
5970+
" throw new Exception('not supported')\n" +
5971+
" return result\n" +
5972+
"}\n" +
5973+
"print(toArray([1,2,3]))\n" +
5974+
"print(toArray('1,2,3'))\n",
5975+
};
5976+
//@formatter:on
5977+
5978+
runConformTest(sources, "[1, 2, 3][1, 2, 3]");
5979+
}
5980+
5981+
@Test
5982+
public void testTypeChecked10673() {
5983+
//@formatter:off
5984+
String[] sources = {
5985+
"Main.groovy",
5986+
"import java.util.function.Consumer\n" +
5987+
"void proc(Consumer<Number> action) {\n" +
5988+
" action.accept(1.234)\n" +
5989+
"}\n" +
5990+
"@groovy.transform.TypeChecked\n" +
5991+
"void test() {\n" +
5992+
" proc { n ->\n" +
5993+
" def c = {\n" +
5994+
" print n.intValue()\n" +
5995+
" }\n" +
5996+
" c()\n" +
5997+
" }\n" +
5998+
"}\n" +
5999+
"test()\n",
6000+
};
6001+
//@formatter:on
6002+
6003+
runConformTest(sources, "1");
6004+
}
59336005
}

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

+20-21
Original file line numberDiff line numberDiff line change
@@ -5879,9 +5879,8 @@ protected ClassNode getType(final ASTNode exp) {
58795879
type = typeCheckingContext.controlStructureVariables.get(parameter);
58805880
}
58815881
// now check for closure override
5882-
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
5883-
if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) {
5884-
type = getTypeFromClosureArguments(parameter, enclosingClosure);
5882+
if (type == null && temporaryTypesForExpression == null) {
5883+
type = getTypeFromClosureArguments(parameter);
58855884
}
58865885
if (type != null) {
58875886
storeType(vexp, type);
@@ -5970,25 +5969,26 @@ protected ClassNode getType(final ASTNode exp) {
59705969
return ((Expression) exp).getType();
59715970
}
59725971

5973-
private ClassNode getTypeFromClosureArguments(Parameter parameter, TypeCheckingContext.EnclosingClosure enclosingClosure) {
5974-
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
5975-
ClassNode[] closureParamTypes = (ClassNode[]) closureExpression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
5976-
if (closureParamTypes == null) return null;
5977-
final Parameter[] parameters = closureExpression.getParameters();
5978-
String name = parameter.getName();
5979-
5980-
if (parameters != null) {
5981-
if (parameters.length == 0) {
5982-
return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null;
5983-
}
5984-
5985-
for (int index = 0; index < parameters.length; index++) {
5986-
if (name.equals(parameters[index].getName())) {
5987-
return closureParamTypes.length > index ? closureParamTypes[index] : null;
5972+
private ClassNode getTypeFromClosureArguments(final Parameter parameter) {
5973+
for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) {
5974+
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
5975+
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
5976+
if (closureParamTypes != null) {
5977+
Parameter[] parameters = closureExpression.getParameters();
5978+
if (parameters != null) {
5979+
final int n = parameters.length;
5980+
String parameterName = parameter.getName();
5981+
if (n == 0 && parameterName.equals("it")) {
5982+
return closureParamTypes.length > 0 ? closureParamTypes[0] : null;
5983+
}
5984+
for (int i = 0; i < n; i += 1) {
5985+
if (parameterName.equals(parameters[i].getName())) {
5986+
return closureParamTypes.length > i ? closureParamTypes[i] : null;
5987+
}
5988+
}
59885989
}
59895990
}
59905991
}
5991-
59925992
return null;
59935993
}
59945994

@@ -7021,8 +7021,7 @@ private class ParameterVariableExpression extends VariableExpression {
70217021
if (inferredType == null) {
70227022
inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure
70237023
if (inferredType == null) {
7024-
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
7025-
if (enclosingClosure != null) inferredType = getTypeFromClosureArguments(parameter, enclosingClosure);
7024+
inferredType = getTypeFromClosureArguments(parameter); // @ClosureParams or SAM-type coercion
70267025
}
70277026
setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferredType != null ? inferredType : parameter.getType());
70287027
}

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

+35-37
Original file line numberDiff line numberDiff line change
@@ -757,10 +757,9 @@ public void visitBinaryExpression(final BinaryExpression expression) {
757757
typeCheckingContext.pushEnclosingBinaryExpression(expression);
758758
try {
759759
int op = expression.getOperation().getType();
760-
// GRECLIPSE add
761-
if (op == LOGICAL_OR) {
760+
// GRECLIPSE add -- GROOVY-7971, GROOVY-8965
761+
if (op == LOGICAL_OR)
762762
typeCheckingContext.pushTemporaryTypeInfo();
763-
}
764763
// GRECLIPSE end
765764
Expression leftExpression = expression.getLeftExpression();
766765
Expression rightExpression = expression.getRightExpression();
@@ -4192,19 +4191,6 @@ protected List<Receiver<String>> makeOwnerList(final Expression objectExpression
41924191
Receiver.make(typeCheckingContext.getEnclosingClassNode()));
41934192
addReceivers(owners, enclosingClass, typeCheckingContext.delegationMetadata.getParent(), "owner.");
41944193
} else {
4195-
if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) { // GROOVY-10180, et al.
4196-
List<ClassNode> instanceofTypes = getTemporaryTypesForExpression(objectExpression);
4197-
if (instanceofTypes != null && !instanceofTypes.isEmpty()) {
4198-
ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0)
4199-
: new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY));
4200-
owners.add(Receiver.make(instanceofType));
4201-
}
4202-
}
4203-
if (typeCheckingContext.lastImplicitItType != null
4204-
&& objectExpression instanceof VariableExpression
4205-
&& ((Variable) objectExpression).getName().equals("it")) {
4206-
owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
4207-
}
42084194
if (isClassClassNodeWrappingConcreteType(receiver)) {
42094195
ClassNode staticType = receiver.getGenericsTypes()[0].getType();
42104196
owners.add(Receiver.make(staticType)); // Type from Class<Type>
@@ -4218,6 +4204,19 @@ protected List<Receiver<String>> makeOwnerList(final Expression objectExpression
42184204
owners.add(Receiver.make(OBJECT_TYPE));
42194205
}
42204206
}
4207+
if (typeCheckingContext.lastImplicitItType != null
4208+
&& objectExpression instanceof VariableExpression
4209+
&& ((Variable) objectExpression).getName().equals("it")) {
4210+
owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
4211+
}
4212+
if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) {
4213+
List<ClassNode> instanceofTypes = getTemporaryTypesForExpression(objectExpression);
4214+
if (instanceofTypes != null && !instanceofTypes.isEmpty()) {
4215+
ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0)
4216+
: new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY));
4217+
owners.add(Receiver.make(instanceofType));
4218+
}
4219+
}
42214220
}
42224221
return owners;
42234222
}
@@ -5509,9 +5508,8 @@ protected ClassNode getType(final ASTNode exp) {
55095508
type = typeCheckingContext.controlStructureVariables.get(parameter);
55105509
}
55115510
// now check for closure override
5512-
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
5513-
if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) {
5514-
type = getTypeFromClosureArguments(parameter, enclosingClosure);
5511+
if (type == null && temporaryTypesForExpression == null) {
5512+
type = getTypeFromClosureArguments(parameter);
55155513
}
55165514
if (type != null) {
55175515
storeType(vexp, type);
@@ -5601,25 +5599,26 @@ protected ClassNode getType(final ASTNode exp) {
56015599
return ((Expression) exp).getType();
56025600
}
56035601

5604-
private ClassNode getTypeFromClosureArguments(final Parameter parameter, final TypeCheckingContext.EnclosingClosure enclosingClosure) {
5605-
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
5606-
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
5607-
if (closureParamTypes == null) return null;
5608-
Parameter[] parameters = closureExpression.getParameters();
5609-
String name = parameter.getName();
5610-
5611-
if (parameters != null) {
5612-
if (parameters.length == 0) {
5613-
return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null;
5614-
}
5615-
5616-
for (int index = 0; index < parameters.length; index++) {
5617-
if (name.equals(parameters[index].getName())) {
5618-
return closureParamTypes.length > index ? closureParamTypes[index] : null;
5602+
private ClassNode getTypeFromClosureArguments(final Parameter parameter) {
5603+
for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) {
5604+
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
5605+
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
5606+
if (closureParamTypes != null) {
5607+
Parameter[] parameters = closureExpression.getParameters();
5608+
if (parameters != null) {
5609+
final int n = parameters.length;
5610+
String parameterName = parameter.getName();
5611+
if (n == 0 && parameterName.equals("it")) {
5612+
return closureParamTypes.length > 0 ? closureParamTypes[0] : null;
5613+
}
5614+
for (int i = 0; i < n; i += 1) {
5615+
if (parameterName.equals(parameters[i].getName())) {
5616+
return closureParamTypes.length > i ? closureParamTypes[i] : null;
5617+
}
5618+
}
56195619
}
56205620
}
56215621
}
5622-
56235622
return null;
56245623
}
56255624

@@ -6664,8 +6663,7 @@ private class ParameterVariableExpression extends VariableExpression {
66646663
if (inferredType == null) {
66656664
inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure
66666665
if (inferredType == null) {
6667-
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
6668-
if (enclosingClosure != null) inferredType = getTypeFromClosureArguments(parameter, enclosingClosure);
6666+
inferredType = getTypeFromClosureArguments(parameter); // @ClosureParams or SAM-type coercion
66696667
}
66706668
setNodeMetaData(INFERRED_TYPE, inferredType != null ? inferredType : parameter.getType()); // to parameter
66716669
}

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

+20-21
Original file line numberDiff line numberDiff line change
@@ -5078,9 +5078,8 @@ protected ClassNode getType(final ASTNode node) {
50785078
type = typeCheckingContext.controlStructureVariables.get(parameter);
50795079
}
50805080
// now check for closure override
5081-
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
5082-
if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) {
5083-
type = getTypeFromClosureArguments(parameter, enclosingClosure);
5081+
if (type == null && temporaryTypesForExpression == null) {
5082+
type = getTypeFromClosureArguments(parameter);
50845083
}
50855084
if (type != null) {
50865085
storeType(vexp, type);
@@ -5159,25 +5158,26 @@ protected ClassNode getType(final ASTNode node) {
51595158
return ((Expression) node).getType();
51605159
}
51615160

5162-
private ClassNode getTypeFromClosureArguments(final Parameter parameter, final TypeCheckingContext.EnclosingClosure enclosingClosure) {
5163-
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
5164-
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
5165-
if (closureParamTypes == null) return null;
5166-
Parameter[] parameters = closureExpression.getParameters();
5167-
String name = parameter.getName();
5168-
5169-
if (parameters != null) {
5170-
if (parameters.length == 0) {
5171-
return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null;
5172-
}
5173-
5174-
for (int index = 0; index < parameters.length; index++) {
5175-
if (name.equals(parameters[index].getName())) {
5176-
return closureParamTypes.length > index ? closureParamTypes[index] : null;
5161+
private ClassNode getTypeFromClosureArguments(final Parameter parameter) {
5162+
for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) {
5163+
ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
5164+
ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
5165+
if (closureParamTypes != null) {
5166+
Parameter[] parameters = closureExpression.getParameters();
5167+
if (parameters != null) {
5168+
final int n = parameters.length;
5169+
String parameterName = parameter.getName();
5170+
if (n == 0 && parameterName.equals("it")) {
5171+
return closureParamTypes.length > 0 ? closureParamTypes[0] : null;
5172+
}
5173+
for (int i = 0; i < n; i += 1) {
5174+
if (parameterName.equals(parameters[i].getName())) {
5175+
return closureParamTypes.length > i ? closureParamTypes[i] : null;
5176+
}
5177+
}
51775178
}
51785179
}
51795180
}
5180-
51815181
return null;
51825182
}
51835183

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

0 commit comments

Comments
 (0)