Skip to content

Commit 8d80199

Browse files
committed
GROOVY-10067
1 parent e50f68f commit 8d80199

File tree

10 files changed

+229
-12
lines changed

10 files changed

+229
-12
lines changed

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

+34
Original file line numberDiff line numberDiff line change
@@ -2411,4 +2411,38 @@ public void testTypeChecked10063() {
24112411

24122412
runConformTest(sources, "42");
24132413
}
2414+
2415+
@Test
2416+
public void testTypeChecked10067() {
2417+
//@formatter:off
2418+
String[] sources = {
2419+
"Main.groovy",
2420+
"def <N extends Number> N getNumber() {\n" +
2421+
" return (N) 42\n" +
2422+
"}\n" +
2423+
"def f(Integer i) {\n" +
2424+
"}\n" +
2425+
"def g(int i) {\n" +
2426+
"}\n" +
2427+
"@groovy.transform.TypeChecked\n" +
2428+
"void test() {\n" +
2429+
" Integer i = this.<Integer>getNumber()\n" +
2430+
" f(this.<Integer>getNumber())\n" +
2431+
" g(this.<Integer>getNumber())\n" +
2432+
" i = (Integer) getNumber()\n" +
2433+
" f((Integer) getNumber())\n" +
2434+
" g((Integer) getNumber())\n" +
2435+
" i = getNumber()\n" +
2436+
//" f(getNumber())\n" +
2437+
//" g(getNumber())\n" +
2438+
" i = number\n" +
2439+
//" f(number)\n" +
2440+
//" g(number)\n" +
2441+
"}\n" +
2442+
"test()\n",
2443+
};
2444+
//@formatter:on
2445+
2446+
runConformTest(sources);
2447+
}
24142448
}

base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/GenericsType.java

+11-7
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ public boolean matches(ClassNode classNode) {
265265
// if the classnode we compare to is a generics placeholder (like <E>) then we
266266
// only need to check that the names are equal
267267
if (genericsTypes==null) return true;
268-
/* GRECLIPSE edit
268+
/* GRECLIPSE edit -- GROOVY-9945, GROOVY-10067
269269
if (isWildcard()) {
270270
if (lowerBound!=null) return genericsTypes[0].getName().equals(lowerBound.getUnresolvedName());
271271
if (upperBounds!=null) {
@@ -280,15 +280,19 @@ public boolean matches(ClassNode classNode) {
280280
return genericsTypes[0].getName().equals(name);
281281
*/
282282
String name0 = genericsTypes[0].getName();
283-
if (isWildcard()) {
284-
if (getLowerBound() != null) {
285-
return name0.equals(getLowerBound().getUnresolvedName());
283+
if (!isWildcard()) {
284+
return name0.equals(getName());
285+
}
286+
if (getLowerBound() != null) {
287+
if (name0.equals(getLowerBound().getUnresolvedName())) {
288+
return true;
286289
}
287-
if (getUpperBounds() != null) {
288-
return name0.equals(getUpperBounds()[0].getUnresolvedName());
290+
} else if (getUpperBounds() != null) {
291+
if (name0.equals(getUpperBounds()[0].getUnresolvedName())) {
292+
return true;
289293
}
290294
}
291-
return name0.equals(getName());
295+
return checkGenerics(classNode);
292296
// GRECLIPSE end
293297
}
294298
if (wildcard || placeholder) {

base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/tools/GenericsUtils.java

+17
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,23 @@ public static void extractPlaceholders(ClassNode node, Map<GenericsTypeName, Gen
166166
if (!node.isUsingGenerics() || !node.isRedirectNode()) return;
167167
GenericsType[] parameterized = node.getGenericsTypes();
168168
if (parameterized == null || parameterized.length == 0) return;
169+
// GRECLIPSE add -- GROOVY-10067
170+
if (node.isGenericsPlaceHolder()) {
171+
GenericsType gt = parameterized[0];
172+
map.put(new GenericsType.GenericsTypeName(gt.getName()), gt);
173+
ClassNode lowerBound = gt.getLowerBound();
174+
if (lowerBound != null) {
175+
extractPlaceholders(lowerBound, map);
176+
}
177+
ClassNode[] upperBounds = gt.getUpperBounds();
178+
if (upperBounds != null) {
179+
for (ClassNode upperBound : upperBounds) {
180+
extractPlaceholders(upperBound, map);
181+
}
182+
}
183+
return;
184+
}
185+
// GRECLIPSE end
169186
GenericsType[] redirectGenericsTypes = node.redirect().getGenericsTypes();
170187
if (redirectGenericsTypes == null ||
171188
(node.isGenericsPlaceHolder() && redirectGenericsTypes.length != parameterized.length) /* GROOVY-8609 */) {

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

+33-1
Original file line numberDiff line numberDiff line change
@@ -488,12 +488,19 @@ static boolean isAssignableTo(ClassNode type, ClassNode toBeAssignedTo) {
488488
}
489489
if (implementsInterfaceOrIsSubclassOf(type, toBeAssignedTo)) {
490490
if (OBJECT_TYPE.equals(toBeAssignedTo)) return true;
491+
/* GRECLIPSE edit -- GROOVY-10067
491492
if (toBeAssignedTo.isUsingGenerics()) {
492493
// perform additional check on generics
493494
// ? extends toBeAssignedTo
494495
GenericsType gt = GenericsUtils.buildWildcardType(toBeAssignedTo);
495496
return gt.isCompatibleWith(type);
496497
}
498+
*/
499+
if (toBeAssignedTo.getGenericsTypes() != null) {
500+
GenericsType gt = toBeAssignedTo.isGenericsPlaceHolder() ? toBeAssignedTo.getGenericsTypes()[0] : GenericsUtils.buildWildcardType(toBeAssignedTo);
501+
return gt.isCompatibleWith(type);
502+
}
503+
// GRECLIPSE end
497504
return true;
498505
}
499506

@@ -1915,6 +1922,11 @@ static void extractGenericsConnections(Map<GenericsTypeName, GenericsType> conne
19151922
// structural match route
19161923
if (target.isGenericsPlaceHolder()) {
19171924
connections.put(new GenericsTypeName(target.getUnresolvedName()), new GenericsType(type));
1925+
// GRECLIPSE add -- GROOVY-10067
1926+
} else if (type.isGenericsPlaceHolder()) {
1927+
// "T extends java.util.List<X> -> java.util.List<E>" vs "java.util.List<E>"
1928+
extractGenericsConnections(connections, extractType(new GenericsType(type)), target);
1929+
// GRECLIPSE end
19181930
} else {
19191931
extractGenericsConnections(connections, type.getGenericsTypes(), target.getGenericsTypes());
19201932
}
@@ -2106,11 +2118,12 @@ static ClassNode applyGenericsContext(final Map<GenericsTypeName, GenericsType>
21062118
if (type.isArray()) {
21072119
return applyGenericsContext(spec, type.getComponentType()).makeArray();
21082120
}
2109-
ClassNode newType = type.getPlainNodeReference();
2121+
//ClassNode newType = type.getPlainNodeReference();
21102122
GenericsType[] gt = type.getGenericsTypes();
21112123
if (asBoolean(spec)) {
21122124
gt = applyGenericsContext(spec, gt);
21132125
}
2126+
/* GRECLIPSE edit -- GROOVY-10067
21142127
newType.setGenericsTypes(gt);
21152128
if (type.isGenericsPlaceHolder()) {
21162129
boolean nonTrivial = hasNonTrivialBounds(gt[0]);
@@ -2127,6 +2140,25 @@ static ClassNode applyGenericsContext(final Map<GenericsTypeName, GenericsType>
21272140
newType.setGenericsPlaceHolder(true);
21282141
}
21292142
return newType;
2143+
*/
2144+
if (!type.isGenericsPlaceHolder()) {
2145+
ClassNode cn = type.getPlainNodeReference();
2146+
cn.setGenericsTypes(gt);
2147+
return cn;
2148+
}
2149+
if (gt[0].isPlaceholder()) {
2150+
if (type.getGenericsTypes()[0] == gt[0]) {
2151+
return type; // nothing to do
2152+
} else if (!hasNonTrivialBounds(gt[0])) {
2153+
ClassNode cn = make(gt[0].getName());
2154+
cn.setRedirect(type);
2155+
cn.setGenericsTypes(gt);
2156+
cn.setGenericsPlaceHolder(true);
2157+
return cn;
2158+
}
2159+
}
2160+
return getCombinedBoundType(gt[0]);
2161+
// GRECLIPSE end
21302162
}
21312163

21322164
static ClassNode getCombinedBoundType(GenericsType genericsType) {

base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/GenericsType.java

+17
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ public boolean isCompatibleWith(final ClassNode classNode) {
225225
if (genericsTypes == null) {
226226
return true;
227227
}
228+
/* GRECLIPSE edit -- GROOVY-10067
228229
if (isWildcard()) {
229230
if (getLowerBound() != null) {
230231
ClassNode lowerBound = getLowerBound();
@@ -240,6 +241,22 @@ public boolean isCompatibleWith(final ClassNode classNode) {
240241
}
241242
}
242243
return genericsTypes[0].name.equals(name);
244+
*/
245+
String name0 = genericsTypes[0].getName();
246+
if (!isWildcard()) {
247+
return name0.equals(getName());
248+
}
249+
if (getLowerBound() != null) {
250+
if (name0.equals(getLowerBound().getUnresolvedName())) {
251+
return true;
252+
}
253+
} else if (getUpperBounds() != null) {
254+
if (name0.equals(getUpperBounds()[0].getUnresolvedName())) {
255+
return true;
256+
}
257+
}
258+
return checkGenerics(classNode);
259+
// GRECLIPSE end
243260
}
244261
if (isWildcard() || isPlaceholder()) {
245262
// if the generics spec is a wildcard or a placeholder then check the bounds

base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/tools/GenericsUtils.java

+17
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,23 @@ public static void extractPlaceholders(ClassNode node, Map<GenericsType.Generics
162162
if (!node.isUsingGenerics() || !node.isRedirectNode()) return;
163163
GenericsType[] parameterized = node.getGenericsTypes();
164164
if (parameterized == null || parameterized.length == 0) return;
165+
// GRECLIPSE add -- GROOVY-10067
166+
if (node.isGenericsPlaceHolder()) {
167+
GenericsType gt = parameterized[0];
168+
map.put(new GenericsType.GenericsTypeName(gt.getName()), gt);
169+
ClassNode lowerBound = gt.getLowerBound();
170+
if (lowerBound != null) {
171+
extractPlaceholders(lowerBound, map);
172+
}
173+
ClassNode[] upperBounds = gt.getUpperBounds();
174+
if (upperBounds != null) {
175+
for (ClassNode upperBound : upperBounds) {
176+
extractPlaceholders(upperBound, map);
177+
}
178+
}
179+
return;
180+
}
181+
// GRECLIPSE end
165182
GenericsType[] redirectGenericsTypes = node.redirect().getGenericsTypes();
166183
if (redirectGenericsTypes == null ||
167184
(node.isGenericsPlaceHolder() && redirectGenericsTypes.length != parameterized.length) /* GROOVY-8609 */ ) {

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

+33-2
Original file line numberDiff line numberDiff line change
@@ -468,12 +468,19 @@ public static boolean isAssignableTo(ClassNode type, ClassNode toBeAssignedTo) {
468468
return true;
469469
}
470470
if (implementsInterfaceOrIsSubclassOf(type, toBeAssignedTo)) {
471+
/* GRECLIPSE edit -- GROOVY-10067
471472
if (toBeAssignedTo.getGenericsTypes() != null) {
472473
// perform additional check on generics
473474
// ? extends toBeAssignedTo
474475
GenericsType gt = GenericsUtils.buildWildcardType(toBeAssignedTo);
475476
return gt.isCompatibleWith(type);
476477
}
478+
*/
479+
if (toBeAssignedTo.getGenericsTypes() != null) {
480+
GenericsType gt = toBeAssignedTo.isGenericsPlaceHolder() ? toBeAssignedTo.getGenericsTypes()[0] : GenericsUtils.buildWildcardType(toBeAssignedTo);
481+
return gt.isCompatibleWith(type);
482+
}
483+
// GRECLIPSE end
477484
return true;
478485
}
479486
// SAM check
@@ -1816,7 +1823,11 @@ static void extractGenericsConnections(final Map<GenericsTypeName, GenericsType>
18161823

18171824
if (target.isGenericsPlaceHolder()) {
18181825
connections.put(new GenericsTypeName(target.getUnresolvedName()), new GenericsType(type));
1819-
1826+
// GRECLIPSE add -- GROOVY-10067
1827+
} else if (type.isGenericsPlaceHolder()) {
1828+
// "T extends java.util.List<X> -> java.util.List<E>" vs "java.util.List<E>"
1829+
extractGenericsConnections(connections, extractType(new GenericsType(type)), target);
1830+
// GRECLIPSE end
18201831
} else if (type.isArray() && target.isArray()) {
18211832
extractGenericsConnections(connections, type.getComponentType(), target.getComponentType());
18221833

@@ -2004,11 +2015,12 @@ static ClassNode applyGenericsContext(final Map<GenericsTypeName, GenericsType>
20042015
if (type.isArray()) {
20052016
return applyGenericsContext(spec, type.getComponentType()).makeArray();
20062017
}
2007-
ClassNode newType = type.getPlainNodeReference();
2018+
//ClassNode newType = type.getPlainNodeReference();
20082019
GenericsType[] gt = type.getGenericsTypes();
20092020
if (asBoolean(spec)) {
20102021
gt = applyGenericsContext(spec, gt);
20112022
}
2023+
/* GRECLIPSE edit -- GROOVY-10067
20122024
newType.setGenericsTypes(gt);
20132025
if (type.isGenericsPlaceHolder()) {
20142026
boolean nonTrivial = hasNonTrivialBounds(gt[0]);
@@ -2025,6 +2037,25 @@ static ClassNode applyGenericsContext(final Map<GenericsTypeName, GenericsType>
20252037
newType.setGenericsPlaceHolder(true);
20262038
}
20272039
return newType;
2040+
*/
2041+
if (!type.isGenericsPlaceHolder()) {
2042+
ClassNode cn = type.getPlainNodeReference();
2043+
cn.setGenericsTypes(gt);
2044+
return cn;
2045+
}
2046+
if (gt[0].isPlaceholder()) {
2047+
if (type.getGenericsTypes()[0] == gt[0]) {
2048+
return type; // nothing to do
2049+
} else if (!hasNonTrivialBounds(gt[0])) {
2050+
ClassNode cn = make(gt[0].getName());
2051+
cn.setRedirect(type);
2052+
cn.setGenericsTypes(gt);
2053+
cn.setGenericsPlaceHolder(true);
2054+
return cn;
2055+
}
2056+
}
2057+
return getCombinedBoundType(gt[0]);
2058+
// GRECLIPSE end
20282059
}
20292060

20302061
static ClassNode getCombinedBoundType(final GenericsType genericsType) {

base/org.codehaus.groovy40/src/org/codehaus/groovy/ast/GenericsType.java

+17
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ public boolean isCompatibleWith(final ClassNode classNode) {
230230
if (genericsTypes == null) {
231231
return true;
232232
}
233+
/* GRECLIPSE edit -- GROOVY-10067
233234
if (isWildcard()) {
234235
if (getLowerBound() != null) {
235236
ClassNode lowerBound = getLowerBound();
@@ -245,6 +246,22 @@ public boolean isCompatibleWith(final ClassNode classNode) {
245246
}
246247
}
247248
return genericsTypes[0].name.equals(name);
249+
*/
250+
String name0 = genericsTypes[0].getName();
251+
if (!isWildcard()) {
252+
return name0.equals(getName());
253+
}
254+
if (getLowerBound() != null) {
255+
if (name0.equals(getLowerBound().getUnresolvedName())) {
256+
return true;
257+
}
258+
} else if (getUpperBounds() != null) {
259+
if (name0.equals(getUpperBounds()[0].getUnresolvedName())) {
260+
return true;
261+
}
262+
}
263+
return checkGenerics(classNode);
264+
// GRECLIPSE end
248265
}
249266
if (isWildcard() || isPlaceholder()) {
250267
// if the generics spec is a wildcard or a placeholder then check the bounds

base/org.codehaus.groovy40/src/org/codehaus/groovy/ast/tools/GenericsUtils.java

+17
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,23 @@ public static void extractPlaceholders(ClassNode node, Map<GenericsType.Generics
163163
if (!node.isUsingGenerics() || !node.isRedirectNode()) return;
164164
GenericsType[] parameterized = node.getGenericsTypes();
165165
if (parameterized == null || parameterized.length == 0) return;
166+
// GRECLIPSE add -- GROOVY-10067
167+
if (node.isGenericsPlaceHolder()) {
168+
GenericsType gt = parameterized[0];
169+
map.put(new GenericsType.GenericsTypeName(gt.getName()), gt);
170+
ClassNode lowerBound = gt.getLowerBound();
171+
if (lowerBound != null) {
172+
extractPlaceholders(lowerBound, map);
173+
}
174+
ClassNode[] upperBounds = gt.getUpperBounds();
175+
if (upperBounds != null) {
176+
for (ClassNode upperBound : upperBounds) {
177+
extractPlaceholders(upperBound, map);
178+
}
179+
}
180+
return;
181+
}
182+
// GRECLIPSE end
166183
GenericsType[] redirectGenericsTypes = node.redirect().getGenericsTypes();
167184
if (redirectGenericsTypes == null ||
168185
(node.isGenericsPlaceHolder() && redirectGenericsTypes.length != parameterized.length) /* GROOVY-8609 */ ) {

0 commit comments

Comments
 (0)