Skip to content

Commit d94ea20

Browse files
eric-millesdaniellansun
authored andcommitted
GROOVY-8965: LUB(Double,Integer) is (Number or Comparable)
(cherry picked from commit 897f3c5)
1 parent 95ebb8a commit d94ea20

File tree

5 files changed

+87
-95
lines changed

5 files changed

+87
-95
lines changed

src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,10 @@
4040
import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
4141
import static org.codehaus.groovy.ast.ClassHelper.float_TYPE;
4242
import static org.codehaus.groovy.ast.ClassHelper.getNextSuperClass;
43-
import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
4443
import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
4544
import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
4645
import static org.codehaus.groovy.ast.ClassHelper.isBigDecimalType;
4746
import static org.codehaus.groovy.ast.ClassHelper.isBigIntegerType;
48-
import static org.codehaus.groovy.ast.ClassHelper.isNumberType;
4947
import static org.codehaus.groovy.ast.ClassHelper.isObjectType;
5048
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveByte;
5149
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveChar;
@@ -172,8 +170,10 @@ public static boolean isNumberCategory(final ClassNode type) {
172170
* @return first common supertype
173171
*/
174172
public static ClassNode lowestUpperBound(final List<ClassNode> nodes) {
175-
if (nodes.size() == 1) return nodes.get(0);
176-
return lowestUpperBound(nodes.get(0), lowestUpperBound(nodes.subList(1, nodes.size())));
173+
int n = nodes.size();
174+
if (n == 1) return nodes.get(0);
175+
if (n == 2) return lowestUpperBound(nodes.get(0), nodes.get(1));
176+
return lowestUpperBound(nodes.get(0), lowestUpperBound(nodes.subList(1, n)));
177177
}
178178

179179
/**
@@ -339,20 +339,10 @@ private static ClassNode lowestUpperBound(final ClassNode a, final ClassNode b,
339339
if (isPrimitiveA && isPrimitiveB) {
340340
Integer pa = NUMBER_TYPES_PRECEDENCE.get(a);
341341
Integer pb = NUMBER_TYPES_PRECEDENCE.get(b);
342-
if (pa!=null && pb!=null) {
343-
if (pa<=pb) return a;
344-
return b;
345-
}
346-
return a.equals(b)?a:lowestUpperBound(getWrapper(a), getWrapper(b), null, null);
347-
}
348-
if (isNumberType(a.redirect()) && isNumberType(b.redirect())) {
349-
ClassNode ua = getUnwrapper(a);
350-
ClassNode ub = getUnwrapper(b);
351-
Integer pa = NUMBER_TYPES_PRECEDENCE.get(ua);
352-
Integer pb = NUMBER_TYPES_PRECEDENCE.get(ub);
353342
if (pa != null && pb != null) {
354-
return pa <= pb ? a : b;
343+
return (pa <= pb ? a : b);
355344
}
345+
return a.equals(b) ? a : lowestUpperBound(getWrapper(a), getWrapper(b), null, null);
356346
}
357347

358348
// handle interfaces

src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase {
109109
void testDoubleFloatWithBoxedTypes() {
110110
assertScript '''
111111
@ASTTest(phase=INSTRUCTION_SELECTION, value={
112-
assert node.getNodeMetaData(INFERRED_TYPE) == Double_TYPE
112+
assert node.getNodeMetaData(INFERRED_TYPE).name == 'java.lang.Number'
113113
})
114114
def y = true?new Double(1d):new Float(1f)
115115
'''
@@ -118,7 +118,7 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase {
118118
void testDoubleFloatWithOneBoxedType1() {
119119
assertScript '''
120120
@ASTTest(phase=INSTRUCTION_SELECTION, value={
121-
assert node.getNodeMetaData(INFERRED_TYPE) == Double_TYPE
121+
assert node.getNodeMetaData(INFERRED_TYPE).name == 'java.lang.Number'
122122
})
123123
def y = true?1d:new Float(1f)
124124
'''
@@ -127,7 +127,7 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase {
127127
void testDoubleFloatWithOneBoxedType2() {
128128
assertScript '''
129129
@ASTTest(phase=INSTRUCTION_SELECTION, value={
130-
assert node.getNodeMetaData(INFERRED_TYPE) == Double_TYPE
130+
assert node.getNodeMetaData(INFERRED_TYPE).name == 'java.lang.Number'
131131
})
132132
def y = true?new Double(1d):1f
133133
'''

src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,13 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
347347
assertScript """
348348
def foo(o) {
349349
if (o instanceof Integer || o instanceof Double) {
350-
${it}.floatValue() // CCE: Double cannot be cast to Integer
350+
${it}.floatValue() // ClassCastException
351351
}
352352
}
353353
def bar = foo(1.1d)
354354
assert bar == 1.1f
355+
def baz = foo(1)
356+
assert baz == 1
355357
"""
356358
}
357359
}

src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy

Lines changed: 59 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ final class WideningCategoriesTest extends GenericsTestCase {
2828

2929
void testBuildCommonTypeWithNullClassNode() {
3030
ClassNode a = null
31-
ClassNode b = make(Serializable)
31+
ClassNode b = SERIALIZABLE_TYPE
3232
assert lowestUpperBound(a,b) == null
3333
assert lowestUpperBound(b,a) == null
3434
}
3535

3636
void testBuildCommonTypeWithObjectClassNode() {
3737
ClassNode a = OBJECT_TYPE
38-
ClassNode b = make(Serializable)
38+
ClassNode b = SERIALIZABLE_TYPE
3939
assert lowestUpperBound(a,b) == OBJECT_TYPE
4040
assert lowestUpperBound(b,a) == OBJECT_TYPE
4141
}
@@ -49,40 +49,40 @@ final class WideningCategoriesTest extends GenericsTestCase {
4949

5050
void testBuildCommonTypeWithVoidClassNodeAndAnyNode() {
5151
ClassNode a = VOID_TYPE
52-
ClassNode b = make(Set)
52+
ClassNode b = SET_TYPE
5353
assert lowestUpperBound(a,b) == OBJECT_TYPE
5454
assert lowestUpperBound(b,a) == OBJECT_TYPE
5555
}
5656

5757
void testBuildCommonTypeWithIdenticalInterfaces() {
58-
ClassNode a = make(Serializable)
59-
ClassNode b = make(Serializable)
60-
assert lowestUpperBound(a,b) == make(Serializable)
58+
ClassNode a = SERIALIZABLE_TYPE
59+
ClassNode b = SERIALIZABLE_TYPE
60+
assert lowestUpperBound(a,b) == SERIALIZABLE_TYPE
6161
}
6262

6363
void testBuildCommonTypeWithOneInterfaceInheritsFromOther() {
64-
ClassNode a = make(Set)
64+
ClassNode a = SET_TYPE
6565
ClassNode b = make(SortedSet)
66-
assert lowestUpperBound(a,b) == make(Set)
67-
assert lowestUpperBound(b,a) == make(Set)
66+
assert lowestUpperBound(a,b) == SET_TYPE
67+
assert lowestUpperBound(b,a) == SET_TYPE
6868
}
6969

7070
void testBuildCommonTypeWithTwoIncompatibleInterfaces() {
71-
ClassNode a = make(Set)
72-
ClassNode b = make(Map)
71+
ClassNode a = SET_TYPE
72+
ClassNode b = MAP_TYPE
7373
assert lowestUpperBound(a,b) == OBJECT_TYPE
7474
assert lowestUpperBound(b,a) == OBJECT_TYPE
7575
}
7676

7777
void testBuildCommonTypeWithOneClassAndOneImplementedInterface() {
78-
ClassNode a = make(Set)
78+
ClassNode a = SET_TYPE
7979
ClassNode b = make(HashSet)
80-
assert lowestUpperBound(a,b) == make(Set)
81-
assert lowestUpperBound(b,a) == make(Set)
80+
assert lowestUpperBound(a,b) == SET_TYPE
81+
assert lowestUpperBound(b,a) == SET_TYPE
8282
}
8383

8484
void testBuildCommonTypeWithOneClassAndNoImplementedInterface() {
85-
ClassNode a = make(Map)
85+
ClassNode a = MAP_TYPE
8686
ClassNode b = make(HashSet)
8787
assert lowestUpperBound(a,b) == OBJECT_TYPE
8888
assert lowestUpperBound(b,a) == OBJECT_TYPE
@@ -91,8 +91,8 @@ final class WideningCategoriesTest extends GenericsTestCase {
9191
void testBuildCommonTypeWithTwoClassesWithoutSuperClass() {
9292
ClassNode a = make(ClassA)
9393
ClassNode b = make(ClassB)
94-
assert lowestUpperBound(a,b) == make(GroovyObject) // GroovyObject because Groovy classes implicitly implement GroovyObject
95-
assert lowestUpperBound(b,a) == make(GroovyObject)
94+
assert lowestUpperBound(a,b) == GROOVY_OBJECT_TYPE // GroovyObject because Groovy classes implicitly implement GroovyObject
95+
assert lowestUpperBound(b,a) == GROOVY_OBJECT_TYPE
9696
}
9797

9898
void testBuildCommonTypeWithIdenticalPrimitiveTypes() {
@@ -151,15 +151,15 @@ final class WideningCategoriesTest extends GenericsTestCase {
151151
void testBuildCommonTypeFromTwoClassesInDifferentBranches() {
152152
ClassNode a = make(ClassA1)
153153
ClassNode b = make(ClassB1)
154-
assert lowestUpperBound(a,b) == make(GroovyObject)
155-
assert lowestUpperBound(b,a) == make(GroovyObject)
154+
assert lowestUpperBound(a,b) == GROOVY_OBJECT_TYPE
155+
assert lowestUpperBound(b,a) == GROOVY_OBJECT_TYPE
156156
}
157157

158158
void testBuildCommonTypeFromTwoClassesInDifferentBranchesAndOneCommonInterface() {
159159
ClassNode a = make(ClassA1_Serializable)
160160
ClassNode b = make(ClassB1_Serializable)
161-
assert lowestUpperBound(a,b).interfaces as Set == [make(Serializable), make(GroovyObject)] as Set
162-
assert lowestUpperBound(b,a).interfaces as Set == [make(Serializable), make(GroovyObject)] as Set
161+
assert lowestUpperBound(a,b).interfaces as Set == [SERIALIZABLE_TYPE, GROOVY_OBJECT_TYPE] as Set
162+
assert lowestUpperBound(b,a).interfaces as Set == [SERIALIZABLE_TYPE, GROOVY_OBJECT_TYPE] as Set
163163
}
164164

165165
void testBuildCommonTypeFromTwoClassesWithCommonSuperClassAndOneCommonInterface() {
@@ -168,32 +168,32 @@ final class WideningCategoriesTest extends GenericsTestCase {
168168
ClassNode type = lowestUpperBound(a, b)
169169
assert type.name =~ /.*Top/
170170
assert type.superClass == make(Top) // includes interface GroovyObject
171-
assert type.interfaces as Set == [make(Serializable)] as Set // extra interface
171+
assert type.interfaces as Set == [SERIALIZABLE_TYPE] as Set // extra interface
172172
type = lowestUpperBound(b, a)
173173
assert type.name =~ /.*Top/
174174
assert type.superClass == make(Top)
175-
assert type.interfaces as Set == [make(Serializable)] as Set
175+
assert type.interfaces as Set == [SERIALIZABLE_TYPE] as Set
176176
}
177177

178178
// GROOVY-8111
179179
void testBuildCommonTypeFromTwoClassesWithTwoCommonInterfacesOneIsSelfReferential() {
180180
ClassNode a = boolean_TYPE
181-
ClassNode b = extractTypesFromCode("${getClass().getName()}.Pair<String,String> type").type
181+
ClassNode b = extractTypesFromCode("${this.class.name}.Pair<String,String> type").type
182182
ClassNode lub = lowestUpperBound(a, b)
183183

184184
assert lub.superClass == OBJECT_TYPE
185-
assert lub.interfaces as Set == [make(Comparable), make(Serializable)] as Set
185+
assert lub.interfaces as Set == [COMPARABLE_TYPE, SERIALIZABLE_TYPE] as Set
186186

187187
lub = lowestUpperBound(b, a)
188188
assert lub.superClass == OBJECT_TYPE
189-
assert lub.interfaces as Set == [make(Comparable), make(Serializable)] as Set
189+
assert lub.interfaces as Set == [COMPARABLE_TYPE, SERIALIZABLE_TYPE] as Set
190190
}
191191

192192
void testStringWithGString() {
193193
ClassNode a = make(String)
194194
ClassNode b = make(GString)
195195
ClassNode type = lowestUpperBound(a,b)
196-
assert type.interfaces as Set == [make(CharSequence), make(Comparable), make(Serializable)] as Set
196+
assert type.interfaces as Set == [make(CharSequence), COMPARABLE_TYPE, SERIALIZABLE_TYPE] as Set
197197
}
198198

199199
void testDistinctPrimitiveTypes() {
@@ -210,46 +210,46 @@ final class WideningCategoriesTest extends GenericsTestCase {
210210
}
211211

212212
void testLUBWithTwoInterfacesAndSameGenericArg() {
213-
ClassNode a = extractTypesFromCode("List<String> type").type
214-
ClassNode b = extractTypesFromCode("List<String> type").type
213+
ClassNode a = extractTypesFromCode('List<String> type').type
214+
ClassNode b = extractTypesFromCode('List<String> type').type
215215
ClassNode lub = lowestUpperBound(a,b)
216-
assert lub == make(List)
216+
assert lub == LIST_TYPE
217217
assert lub.genericsTypes.length == 1
218218
assert lub.genericsTypes[0].type == STRING_TYPE
219219
}
220220

221221
void testLUBWithTwoInterfacesAndCommonSuperClassGenericArg() {
222-
ClassNode a = extractTypesFromCode("List<Integer> type").type
223-
ClassNode b = extractTypesFromCode("List<Long> type").type
222+
ClassNode a = extractTypesFromCode('List<Integer> type').type
223+
ClassNode b = extractTypesFromCode('List<Long> type').type
224224
ClassNode lub = lowestUpperBound(a,b)
225-
assert lub == make(List)
225+
assert lub == LIST_TYPE
226226
assert lub.genericsTypes.length == 1
227227
assert lub.genericsTypes[0].wildcard
228-
assert lub.genericsTypes[0].upperBounds[0].superClass == Number_TYPE
229-
assert make(Comparable) in lub.genericsTypes[0].upperBounds[0].interfaces
228+
assert lub.genericsTypes[0].upperBounds[0].name == 'java.lang.Number'
229+
assert COMPARABLE_TYPE in lub.genericsTypes[0].upperBounds[0].interfaces
230230
}
231231

232232
void testLUBWithTwoInterfacesAndSingleCommonInterface() {
233-
ClassNode a = extractTypesFromCode("List<Set> type").type
234-
ClassNode b = extractTypesFromCode("List<List> type").type
233+
ClassNode a = extractTypesFromCode('List<Set> type').type
234+
ClassNode b = extractTypesFromCode('List<List> type').type
235235
ClassNode lub = lowestUpperBound(a,b)
236-
assert lub == make(List)
236+
assert lub == LIST_TYPE
237237
assert lub.genericsTypes.length == 1
238238
assert lub.genericsTypes[0].wildcard
239-
assert lub.genericsTypes[0].upperBounds[0] == make(Collection)
239+
assert lub.genericsTypes[0].upperBounds[0] == COLLECTION_TYPE
240240
}
241241

242242
void testLUBWithTwoInterfacesAndNestedSingleCommonInterface() {
243-
ClassNode a = extractTypesFromCode("Collection<List<Set>> type").type
244-
ClassNode b = extractTypesFromCode("Collection<List<SortedSet>> type").type
243+
ClassNode a = extractTypesFromCode('Collection<List<Set>> type').type
244+
ClassNode b = extractTypesFromCode('Collection<List<SortedSet>> type').type
245245
ClassNode lub = lowestUpperBound(a,b)
246-
assert lub == make(Collection)
246+
assert lub == COLLECTION_TYPE
247247
assert lub.genericsTypes.length == 1
248248
def nestedType = lub.genericsTypes[0].type
249-
assert nestedType == make(List)
250-
assert nestedType.genericsTypes.length==1
249+
assert nestedType == LIST_TYPE
250+
assert nestedType.genericsTypes.length == 1
251251
assert nestedType.genericsTypes[0].wildcard
252-
assert nestedType.genericsTypes[0].upperBounds[0] == make(Set)
252+
assert nestedType.genericsTypes[0].upperBounds[0] == SET_TYPE
253253
}
254254

255255
void testLUBWithTwoArgumentTypesSharingOneInterfaceNotImplementedBySuperClass() {
@@ -265,7 +265,7 @@ final class WideningCategoriesTest extends GenericsTestCase {
265265
ClassNode genericType = lub.genericsTypes[0].upperBounds[0]
266266
assert genericType instanceof LowestUpperBoundClassNode
267267
assert genericType.superClass == make(Top)
268-
assert genericType.interfaces == [make(Serializable)]
268+
assert genericType.interfaces == [SERIALIZABLE_TYPE]
269269
}
270270

271271
void testLUBWithTwoParameterizedTypesSharingOneInterfaceNotImplementedBySuperClass() {
@@ -276,32 +276,34 @@ final class WideningCategoriesTest extends GenericsTestCase {
276276
ClassNode b = extractTypesFromCode('org.codehaus.groovy.ast.tools.WideningCategoriesTest.PTopLong type').type
277277
ClassNode lub = lowestUpperBound(a,b)
278278
assert lub instanceof LowestUpperBoundClassNode // a virtual class which extends PTop<? extends Number> and implements Serializable
279+
assert lub.interfaces == [SERIALIZABLE_TYPE]
279280
assert lub.unresolvedSuperClass == make(PTop)
280281
assert lub.unresolvedSuperClass.genericsTypes.length == 1
281282
assert lub.unresolvedSuperClass.genericsTypes[0].wildcard // ? extends Number
282-
ClassNode genericType = lub.unresolvedSuperClass.genericsTypes[0].upperBounds[0]
283-
assert genericType == Long_TYPE
283+
ClassNode upperBound = lub.unresolvedSuperClass.genericsTypes[0].upperBounds[0]
284+
assert upperBound.superClass == Number_TYPE
285+
assert upperBound.interfaces.contains(COMPARABLE_TYPE)
284286
}
285287

286288
void testCommonAssignableType() {
287289
def typeA = extractTypesFromCode('LinkedList type').type
288290
def typeB = extractTypesFromCode('List type').type
289291
def superType = lowestUpperBound(typeA, typeB)
290-
assert superType == make(List)
292+
assert superType == LIST_TYPE
291293
}
292294

293295
void testCommonAssignableType2() {
294296
def typeA = extractTypesFromCode('LinkedHashSet type').type
295297
def typeB = extractTypesFromCode('List type').type
296298
def superType = lowestUpperBound(typeA, typeB)
297-
assert superType == make(Collection)
299+
assert superType == COLLECTION_TYPE
298300
}
299301

300302
void testCommonAssignableTypeWithGenerics() {
301303
def typeA = extractTypesFromCode('LinkedHashSet<String> type').type
302304
def typeB = extractTypesFromCode('List<String> type').type
303305
def superType = lowestUpperBound(typeA, typeB)
304-
assert superType == make(Collection)
306+
assert superType == COLLECTION_TYPE
305307
}
306308

307309
void testLUBOfTwoListTypes() {
@@ -310,7 +312,7 @@ final class WideningCategoriesTest extends GenericsTestCase {
310312
def superType = lowestUpperBound(typeA, typeB)
311313
assert superType instanceof LowestUpperBoundClassNode
312314
assert superType.superClass == make(AbstractList)
313-
assert superType.interfaces as Set == [make(Serializable), make(Cloneable)] as Set
315+
assert superType.interfaces as Set == [SERIALIZABLE_TYPE, make(Cloneable)] as Set
314316
}
315317

316318
void testLUBOfTwoListTypesWithSameGenerics() {
@@ -319,7 +321,7 @@ final class WideningCategoriesTest extends GenericsTestCase {
319321
def superType = lowestUpperBound(typeA, typeB)
320322
assert superType instanceof LowestUpperBoundClassNode
321323
assert superType.superClass == make(AbstractList)
322-
assert superType.interfaces as Set == [make(Serializable), make(Cloneable)] as Set
324+
assert superType.interfaces as Set == [SERIALIZABLE_TYPE, make(Cloneable)] as Set
323325
assert superType.genericsTypes.length == 1
324326
assert superType.genericsTypes[0].type == STRING_TYPE
325327

@@ -331,23 +333,21 @@ final class WideningCategoriesTest extends GenericsTestCase {
331333
def superType = lowestUpperBound(typeA, typeB)
332334
assert superType instanceof LowestUpperBoundClassNode
333335
assert superType.superClass == make(AbstractList)
334-
assert superType.interfaces as Set == [make(Serializable), make(Cloneable)] as Set
336+
assert superType.interfaces as Set == [SERIALIZABLE_TYPE, make(Cloneable)] as Set
335337
assert superType.genericsTypes.length == 1
336338
def type = superType.genericsTypes[0]
337339
assert type.wildcard
338340
assert type.upperBounds[0] instanceof LowestUpperBoundClassNode
339-
[Comparable, Serializable].each {
340-
assert make(it) in type.upperBounds[0].interfaces
341-
}
341+
assert type.upperBounds[0].interfaces.contains(COMPARABLE_TYPE)
342+
assert type.upperBounds[0].interfaces.contains(SERIALIZABLE_TYPE)
342343
}
343344

344345
void testLUBOfArrayTypes() {
345346
def typeA = extractTypesFromCode('Number[] type').type
346347
def typeB = extractTypesFromCode('Integer[] type').type
347348
def superType = lowestUpperBound(typeA, typeB)
348349
assert superType.isArray()
349-
def component = superType.getComponentType()
350-
assert component == make(Number)
350+
assert superType.componentType == Number_TYPE
351351
}
352352

353353
// ---------- Classes and Interfaces used in this unit test ----------------

0 commit comments

Comments
 (0)