Skip to content

Commit 59193b3

Browse files
committed
GROOVY-10228, GROOVY-10310
1 parent 8ca4d13 commit 59193b3

File tree

4 files changed

+140
-36
lines changed

4 files changed

+140
-36
lines changed

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

+51-1
Original file line numberDiff line numberDiff line change
@@ -3912,6 +3912,30 @@ public void testTypeChecked10225() {
39123912
runConformTest(sources, "null");
39133913
}
39143914

3915+
@Test
3916+
public void testTypeChecked10228() {
3917+
//@formatter:off
3918+
String[] sources = {
3919+
"Main.groovy",
3920+
"@groovy.transform.TupleConstructor(defaults=false)\n" +
3921+
"class C<T> {\n" +
3922+
" T p\n" +
3923+
"}\n" +
3924+
"void m(Number n) {\n" +
3925+
" print 'works'\n" +
3926+
"}\n" +
3927+
"@groovy.transform.TypeChecked\n" +
3928+
"void test() {\n" +
3929+
" def x = 12345\n" +
3930+
" m(new C<>(x).getP())\n" + // Cannot find matching method m(T)
3931+
"}\n" +
3932+
"test()\n",
3933+
};
3934+
//@formatter:on
3935+
3936+
runConformTest(sources, "works");
3937+
}
3938+
39153939
@Test
39163940
public void testTypeChecked10234() {
39173941
//@formatter:off
@@ -4257,7 +4281,33 @@ public void testTypeChecked10309() {
42574281
" new A<X,T>((X)null, (T)null)\n" + // Cannot call A#<init>(X, T) with arguments [X, T]
42584282
" }\n" +
42594283
"}\n" +
4260-
"new C().test()",
4284+
"new C().test()\n",
4285+
};
4286+
//@formatter:on
4287+
4288+
runConformTest(sources);
4289+
}
4290+
4291+
@Test
4292+
public void testTypeChecked10310() {
4293+
//@formatter:off
4294+
String[] sources = {
4295+
"Main.groovy",
4296+
"@groovy.transform.TupleConstructor\n" +
4297+
"class A<T> {\n" +
4298+
" T t\n" +
4299+
"}\n" +
4300+
"class B<T> {\n" +
4301+
"}\n" +
4302+
"def <T> A<T> m(T t, B<? extends T> b_of_t) {\n" +
4303+
" new A<>(t)\n" +
4304+
"}\n" +
4305+
"@groovy.transform.TypeChecked\n" +
4306+
"void test() {\n" +
4307+
" def x = 'x'\n" +
4308+
" m(x, new B<>())\n" + // Cannot call m(T,B<? extends T>) with arguments...
4309+
"}\n" +
4310+
"test()\n",
42614311
};
42624312
//@formatter:on
42634313

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

+34-7
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,8 @@ protected void inferDiamondType(final ConstructorCallExpression cce, final Class
12571257
}
12581258
}
12591259

1260-
private void adjustGenerics(ClassNode from, ClassNode to) {
1260+
private void adjustGenerics(final ClassNode source, final ClassNode target) {
1261+
/* GRECLIPSE edit -- GROOVY-10055, GROOVY-10228, GROOVY-10310
12611262
GenericsType[] genericsTypes = from.getGenericsTypes();
12621263
if (genericsTypes == null) {
12631264
// case of: def foo = new HashMap<>()
@@ -1273,6 +1274,28 @@ private void adjustGenerics(ClassNode from, ClassNode to) {
12731274
);
12741275
}
12751276
to.setGenericsTypes(copy);
1277+
*/
1278+
GenericsType[] genericsTypes = source.getGenericsTypes();
1279+
if (genericsTypes == null) { // Map foo = new HashMap<>()
1280+
genericsTypes = target.redirect().getGenericsTypes().clone();
1281+
for (int i = 0, n = genericsTypes.length; i < n; i += 1) {
1282+
GenericsType gt = genericsTypes[i];
1283+
// GROOVY-10055: handle diamond or raw
1284+
ClassNode cn = gt.getUpperBounds() != null
1285+
? gt.getUpperBounds()[0] : gt.getType().redirect();
1286+
genericsTypes[i] = cn.getPlainNodeReference().asGenericsType();
1287+
}
1288+
} else {
1289+
genericsTypes = genericsTypes.clone();
1290+
for (int i = 0, n = genericsTypes.length; i < n; i += 1) {
1291+
GenericsType gt = genericsTypes[i];
1292+
genericsTypes[i] = new GenericsType(gt.getType(),
1293+
gt.getUpperBounds(), gt.getLowerBound());
1294+
genericsTypes[i].setWildcard(gt.isWildcard());
1295+
}
1296+
}
1297+
target.setGenericsTypes(genericsTypes);
1298+
// GRECLIPSE end
12761299
}
12771300

12781301
/**
@@ -4070,18 +4093,21 @@ public void visitMethodCallExpression(MethodCallExpression call) {
40704093

40714094
objectExpression.visit(this);
40724095
call.getMethod().visit(this);
4073-
4096+
// GRECLIPSE add -- GROOVY-10228
4097+
ClassNode receiver = getType(objectExpression);
4098+
if (objectExpression instanceof ConstructorCallExpression) {
4099+
inferDiamondType((ConstructorCallExpression) objectExpression, receiver.getPlainNodeReference());
4100+
}
4101+
// GRECLIPSE end
40744102
// if the call expression is a spread operator call, then we must make sure that
40754103
// the call is made on a collection type
40764104
if (call.isSpreadSafe()) {
4077-
//TODO check if this should not be change to iterator based call logic
4078-
ClassNode expressionType = getType(objectExpression);
4079-
if (!implementsInterfaceOrIsSubclassOf(expressionType, Collection_TYPE) && !expressionType.isArray()) {
4105+
if (!implementsInterfaceOrIsSubclassOf(receiver, Collection_TYPE) && !receiver.isArray()) {
40804106
addStaticTypeError("Spread operator can only be used on collection types", objectExpression);
40814107
return;
40824108
} else {
40834109
// type check call as if it was made on component type
4084-
ClassNode componentType = inferComponentType(expressionType, int_TYPE);
4110+
ClassNode componentType = inferComponentType(receiver, int_TYPE);
40854111
MethodCallExpression subcall = callX(castX(componentType, EmptyExpression.INSTANCE), name, call.getArguments());
40864112
subcall.setLineNumber(call.getLineNumber());
40874113
subcall.setColumnNumber(call.getColumnNumber());
@@ -4105,8 +4131,9 @@ public void visitMethodCallExpression(MethodCallExpression call) {
41054131
checkForbiddenSpreadArgument(argumentList);
41064132

41074133
// for arguments, we need to visit closures *after* the method has been chosen
4108-
4134+
/* GRECLIPSE edit
41094135
ClassNode receiver = getType(objectExpression);
4136+
*/
41104137
visitMethodCallArguments(receiver, argumentList, false, null);
41114138

41124139
ClassNode[] args = getArgumentTypes(argumentList);

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

+32-13
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,8 @@ protected void inferDiamondType(final ConstructorCallExpression cce, final Class
11561156
}
11571157
}
11581158

1159-
private void adjustGenerics(final ClassNode from, final ClassNode to) {
1159+
private void adjustGenerics(final ClassNode source, final ClassNode target) {
1160+
/* GRECLIPSE edit -- GROOVY-10055, GROOVY-10228, GROOVY-10310
11601161
GenericsType[] genericsTypes = from.getGenericsTypes();
11611162
if (genericsTypes == null) {
11621163
// case of: def foo = new HashMap<>()
@@ -1172,6 +1173,28 @@ private void adjustGenerics(final ClassNode from, final ClassNode to) {
11721173
);
11731174
}
11741175
to.setGenericsTypes(copy);
1176+
*/
1177+
GenericsType[] genericsTypes = source.getGenericsTypes();
1178+
if (genericsTypes == null) { // Map foo = new HashMap<>()
1179+
genericsTypes = target.redirect().getGenericsTypes().clone();
1180+
for (int i = 0, n = genericsTypes.length; i < n; i += 1) {
1181+
GenericsType gt = genericsTypes[i];
1182+
// GROOVY-10055: handle diamond or raw
1183+
ClassNode cn = gt.getUpperBounds() != null
1184+
? gt.getUpperBounds()[0] : gt.getType().redirect();
1185+
genericsTypes[i] = cn.getPlainNodeReference().asGenericsType();
1186+
}
1187+
} else {
1188+
genericsTypes = genericsTypes.clone();
1189+
for (int i = 0, n = genericsTypes.length; i < n; i += 1) {
1190+
GenericsType gt = genericsTypes[i];
1191+
genericsTypes[i] = new GenericsType(gt.getType(),
1192+
gt.getUpperBounds(), gt.getLowerBound());
1193+
genericsTypes[i].setWildcard(gt.isWildcard());
1194+
}
1195+
}
1196+
target.setGenericsTypes(genericsTypes);
1197+
// GRECLIPSE end
11751198
}
11761199

11771200
/**
@@ -3738,18 +3761,21 @@ public void visitMethodCallExpression(final MethodCallExpression call) {
37383761

37393762
objectExpression.visit(this);
37403763
call.getMethod().visit(this);
3741-
3764+
// GRECLIPSE add -- GROOVY-10228
3765+
ClassNode receiver = getType(objectExpression);
3766+
if (objectExpression instanceof ConstructorCallExpression) {
3767+
inferDiamondType((ConstructorCallExpression) objectExpression, receiver.getPlainNodeReference());
3768+
}
3769+
// GRECLIPSE end
37423770
// if the call expression is a spread operator call, then we must make sure that
37433771
// the call is made on a collection type
37443772
if (call.isSpreadSafe()) {
3745-
// TODO: check if this should not be change to iterator based call logic
3746-
ClassNode expressionType = getType(objectExpression);
3747-
if (!implementsInterfaceOrIsSubclassOf(expressionType, Collection_TYPE) && !expressionType.isArray()) {
3773+
if (!implementsInterfaceOrIsSubclassOf(receiver, Collection_TYPE) && !receiver.isArray()) {
37483774
addStaticTypeError("Spread operator can only be used on collection types", objectExpression);
37493775
return;
37503776
} else {
37513777
// type check call as if it was made on component type
3752-
ClassNode componentType = inferComponentType(expressionType, int_TYPE);
3778+
ClassNode componentType = inferComponentType(receiver, int_TYPE);
37533779
MethodCallExpression subcall = callX(castX(componentType, EmptyExpression.INSTANCE), name, call.getArguments());
37543780
subcall.setLineNumber(call.getLineNumber());
37553781
subcall.setColumnNumber(call.getColumnNumber());
@@ -3776,13 +3802,6 @@ public void visitMethodCallExpression(final MethodCallExpression call) {
37763802
/* GRECLIPSE edit
37773803
ClassNode receiver = getType(objectExpression);
37783804
*/
3779-
ClassNode receiver;
3780-
if (objectExpression instanceof VariableExpression && hasInferredReturnType(objectExpression)) {
3781-
receiver = getInferredReturnType(objectExpression);
3782-
} else {
3783-
receiver = getType(objectExpression);
3784-
}
3785-
// GRECLIPSE end
37863805
visitMethodCallArguments(receiver, argumentList, false, null);
37873806

37883807
ClassNode[] args = getArgumentTypes(argumentList);

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

+23-15
Original file line numberDiff line numberDiff line change
@@ -1120,22 +1120,27 @@ protected void inferDiamondType(final ConstructorCallExpression cce, final Class
11201120
}
11211121
}
11221122

1123-
private void adjustGenerics(final ClassNode from, final ClassNode to) {
1124-
GenericsType[] genericsTypes = from.getGenericsTypes();
1125-
if (genericsTypes == null) {
1126-
// case of: def foo = new HashMap<>()
1127-
genericsTypes = to.redirect().getGenericsTypes();
1128-
}
1129-
GenericsType[] copy = new GenericsType[genericsTypes.length];
1130-
for (int i = 0; i < genericsTypes.length; i++) {
1131-
GenericsType genericsType = genericsTypes[i];
1132-
copy[i] = new GenericsType(
1133-
wrapTypeIfNecessary(genericsType.getType()),
1134-
genericsType.getUpperBounds(),
1135-
genericsType.getLowerBound()
1136-
);
1123+
private void adjustGenerics(final ClassNode source, final ClassNode target) {
1124+
GenericsType[] genericsTypes = source.getGenericsTypes();
1125+
if (genericsTypes == null) { // Map foo = new HashMap<>()
1126+
genericsTypes = target.redirect().getGenericsTypes().clone();
1127+
for (int i = 0, n = genericsTypes.length; i < n; i += 1) {
1128+
GenericsType gt = genericsTypes[i];
1129+
// GROOVY-10055: handle diamond or raw
1130+
ClassNode cn = gt.getUpperBounds() != null
1131+
? gt.getUpperBounds()[0] : gt.getType().redirect();
1132+
genericsTypes[i] = cn.getPlainNodeReference().asGenericsType();
1133+
}
1134+
} else {
1135+
genericsTypes = genericsTypes.clone();
1136+
for (int i = 0, n = genericsTypes.length; i < n; i += 1) {
1137+
GenericsType gt = genericsTypes[i];
1138+
genericsTypes[i] = new GenericsType(gt.getType(),
1139+
gt.getUpperBounds(), gt.getLowerBound());
1140+
genericsTypes[i].setWildcard(gt.isWildcard()); // GROOVY-10310
1141+
}
11371142
}
1138-
to.setGenericsTypes(copy);
1143+
target.setGenericsTypes(genericsTypes);
11391144
}
11401145

11411146
/**
@@ -3444,6 +3449,9 @@ public void visitMethodCallExpression(final MethodCallExpression call) {
34443449
call.getMethod().visit(this);
34453450

34463451
ClassNode receiver = getType(objectExpression);
3452+
if (objectExpression instanceof ConstructorCallExpression) { // GROOVY-10228
3453+
inferDiamondType((ConstructorCallExpression) objectExpression, receiver.getPlainNodeReference());
3454+
}
34473455
if (call.isSpreadSafe()) { // make sure receiver is array or collection then check element type
34483456
if (!receiver.isArray() && !implementsInterfaceOrIsSubclassOf(receiver, Collection_TYPE)) {
34493457
addStaticTypeError("Spread operator can only be used on collection types", objectExpression);

0 commit comments

Comments
 (0)