This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY-8965 in repository https://gitbox.apache.org/repos/asf/groovy.git
commit e8e4df8e12c95980994030c95ac6e410be373434 Author: Eric Milles <[email protected]> AuthorDate: Mon Jul 11 14:25:27 2022 -0500 GROOVY-8965: `LUB(Double,Integer)` is `(Number or Comparable)` --- .../groovy/ast/tools/WideningCategories.java | 22 ++-- .../transform/stc/TernaryOperatorSTCTest.groovy | 6 +- .../transform/stc/TypeInferenceSTCTest.groovy | 4 +- .../groovy/ast/tools/WideningCategoriesTest.groovy | 112 +++++++++++---------- .../classgen/asm/sc/BugsStaticCompileTest.groovy | 32 +++--- 5 files changed, 85 insertions(+), 91 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java index e919103564..f07568d515 100644 --- a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java +++ b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java @@ -41,12 +41,10 @@ import static org.codehaus.groovy.ast.ClassHelper.byte_TYPE; import static org.codehaus.groovy.ast.ClassHelper.double_TYPE; import static org.codehaus.groovy.ast.ClassHelper.float_TYPE; import static org.codehaus.groovy.ast.ClassHelper.getNextSuperClass; -import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper; import static org.codehaus.groovy.ast.ClassHelper.getWrapper; import static org.codehaus.groovy.ast.ClassHelper.int_TYPE; import static org.codehaus.groovy.ast.ClassHelper.isBigDecimalType; import static org.codehaus.groovy.ast.ClassHelper.isBigIntegerType; -import static org.codehaus.groovy.ast.ClassHelper.isNumberType; import static org.codehaus.groovy.ast.ClassHelper.isObjectType; import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveByte; import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveChar; @@ -173,8 +171,10 @@ public class WideningCategories { * @return first common supertype */ public static ClassNode lowestUpperBound(final List<ClassNode> nodes) { - if (nodes.size() == 1) return nodes.get(0); - return lowestUpperBound(nodes.get(0), lowestUpperBound(nodes.subList(1, nodes.size()))); + int n = nodes.size(); + if (n == 1) return nodes.get(0); + if (n == 2) return lowestUpperBound(nodes.get(0), nodes.get(1)); + return lowestUpperBound(nodes.get(0), lowestUpperBound(nodes.subList(1, n))); } /** @@ -340,20 +340,10 @@ public class WideningCategories { if (isPrimitiveA && isPrimitiveB) { Integer pa = NUMBER_TYPES_PRECEDENCE.get(a); Integer pb = NUMBER_TYPES_PRECEDENCE.get(b); - if (pa!=null && pb!=null) { - if (pa<=pb) return a; - return b; - } - return a.equals(b)?a:lowestUpperBound(getWrapper(a), getWrapper(b), null, null); - } - if (isNumberType(a.redirect()) && isNumberType(b.redirect())) { - ClassNode ua = getUnwrapper(a); - ClassNode ub = getUnwrapper(b); - Integer pa = NUMBER_TYPES_PRECEDENCE.get(ua); - Integer pb = NUMBER_TYPES_PRECEDENCE.get(ub); if (pa != null && pb != null) { - return pa <= pb ? a : b; + return (pa <= pb ? a : b); } + return a.equals(b) ? a : lowestUpperBound(getWrapper(a), getWrapper(b), null, null); } // handle interfaces diff --git a/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy b/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy index 1c5a7da7b7..92b708e40c 100644 --- a/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy +++ b/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy @@ -109,7 +109,7 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase { void testDoubleFloatWithBoxedTypes() { assertScript ''' @ASTTest(phase=INSTRUCTION_SELECTION, value={ - assert node.getNodeMetaData(INFERRED_TYPE) == Double_TYPE + assert node.getNodeMetaData(INFERRED_TYPE).name == 'java.lang.Number' }) def y = true?new Double(1d):new Float(1f) ''' @@ -118,7 +118,7 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase { void testDoubleFloatWithOneBoxedType1() { assertScript ''' @ASTTest(phase=INSTRUCTION_SELECTION, value={ - assert node.getNodeMetaData(INFERRED_TYPE) == Double_TYPE + assert node.getNodeMetaData(INFERRED_TYPE).name == 'java.lang.Number' }) def y = true?1d:new Float(1f) ''' @@ -127,7 +127,7 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase { void testDoubleFloatWithOneBoxedType2() { assertScript ''' @ASTTest(phase=INSTRUCTION_SELECTION, value={ - assert node.getNodeMetaData(INFERRED_TYPE) == Double_TYPE + assert node.getNodeMetaData(INFERRED_TYPE).name == 'java.lang.Number' }) def y = true?new Double(1d):1f ''' diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy index 6f1efc8dc7..c172240660 100644 --- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy +++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy @@ -347,11 +347,13 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase { assertScript """ def foo(o) { if (o instanceof Integer || o instanceof Double) { - ${it}.floatValue() // CCE: Double cannot be cast to Integer + ${it}.floatValue() // ClassCastException } } def bar = foo(1.1d) assert bar == 1.1f + def baz = foo(1) + assert baz == 1 """ } } diff --git a/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy b/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy index 4be116256e..ce0ac8ea1c 100644 --- a/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy +++ b/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy @@ -28,14 +28,14 @@ final class WideningCategoriesTest extends GenericsTestCase { void testBuildCommonTypeWithNullClassNode() { ClassNode a = null - ClassNode b = make(Serializable) + ClassNode b = SERIALIZABLE_TYPE assert lowestUpperBound(a,b) == null assert lowestUpperBound(b,a) == null } void testBuildCommonTypeWithObjectClassNode() { ClassNode a = OBJECT_TYPE - ClassNode b = make(Serializable) + ClassNode b = SERIALIZABLE_TYPE assert lowestUpperBound(a,b) == OBJECT_TYPE assert lowestUpperBound(b,a) == OBJECT_TYPE } @@ -49,40 +49,40 @@ final class WideningCategoriesTest extends GenericsTestCase { void testBuildCommonTypeWithVoidClassNodeAndAnyNode() { ClassNode a = VOID_TYPE - ClassNode b = make(Set) + ClassNode b = SET_TYPE assert lowestUpperBound(a,b) == OBJECT_TYPE assert lowestUpperBound(b,a) == OBJECT_TYPE } void testBuildCommonTypeWithIdenticalInterfaces() { - ClassNode a = make(Serializable) - ClassNode b = make(Serializable) - assert lowestUpperBound(a,b) == make(Serializable) + ClassNode a = SERIALIZABLE_TYPE + ClassNode b = SERIALIZABLE_TYPE + assert lowestUpperBound(a,b) == SERIALIZABLE_TYPE } void testBuildCommonTypeWithOneInterfaceInheritsFromOther() { - ClassNode a = make(Set) + ClassNode a = SET_TYPE ClassNode b = make(SortedSet) - assert lowestUpperBound(a,b) == make(Set) - assert lowestUpperBound(b,a) == make(Set) + assert lowestUpperBound(a,b) == SET_TYPE + assert lowestUpperBound(b,a) == SET_TYPE } void testBuildCommonTypeWithTwoIncompatibleInterfaces() { - ClassNode a = make(Set) - ClassNode b = make(Map) + ClassNode a = SET_TYPE + ClassNode b = MAP_TYPE assert lowestUpperBound(a,b) == OBJECT_TYPE assert lowestUpperBound(b,a) == OBJECT_TYPE } void testBuildCommonTypeWithOneClassAndOneImplementedInterface() { - ClassNode a = make(Set) + ClassNode a = SET_TYPE ClassNode b = make(HashSet) - assert lowestUpperBound(a,b) == make(Set) - assert lowestUpperBound(b,a) == make(Set) + assert lowestUpperBound(a,b) == SET_TYPE + assert lowestUpperBound(b,a) == SET_TYPE } void testBuildCommonTypeWithOneClassAndNoImplementedInterface() { - ClassNode a = make(Map) + ClassNode a = MAP_TYPE ClassNode b = make(HashSet) assert lowestUpperBound(a,b) == OBJECT_TYPE assert lowestUpperBound(b,a) == OBJECT_TYPE @@ -91,8 +91,8 @@ final class WideningCategoriesTest extends GenericsTestCase { void testBuildCommonTypeWithTwoClassesWithoutSuperClass() { ClassNode a = make(ClassA) ClassNode b = make(ClassB) - assert lowestUpperBound(a,b) == make(GroovyObject) // GroovyObject because Groovy classes implicitly implement GroovyObject - assert lowestUpperBound(b,a) == make(GroovyObject) + assert lowestUpperBound(a,b) == GROOVY_OBJECT_TYPE // GroovyObject because Groovy classes implicitly implement GroovyObject + assert lowestUpperBound(b,a) == GROOVY_OBJECT_TYPE } void testBuildCommonTypeWithIdenticalPrimitiveTypes() { @@ -151,15 +151,15 @@ final class WideningCategoriesTest extends GenericsTestCase { void testBuildCommonTypeFromTwoClassesInDifferentBranches() { ClassNode a = make(ClassA1) ClassNode b = make(ClassB1) - assert lowestUpperBound(a,b) == make(GroovyObject) - assert lowestUpperBound(b,a) == make(GroovyObject) + assert lowestUpperBound(a,b) == GROOVY_OBJECT_TYPE + assert lowestUpperBound(b,a) == GROOVY_OBJECT_TYPE } void testBuildCommonTypeFromTwoClassesInDifferentBranchesAndOneCommonInterface() { ClassNode a = make(ClassA1_Serializable) ClassNode b = make(ClassB1_Serializable) - assert lowestUpperBound(a,b).interfaces as Set == [make(Serializable), make(GroovyObject)] as Set - assert lowestUpperBound(b,a).interfaces as Set == [make(Serializable), make(GroovyObject)] as Set + assert lowestUpperBound(a,b).interfaces as Set == [SERIALIZABLE_TYPE, GROOVY_OBJECT_TYPE] as Set + assert lowestUpperBound(b,a).interfaces as Set == [SERIALIZABLE_TYPE, GROOVY_OBJECT_TYPE] as Set } void testBuildCommonTypeFromTwoClassesWithCommonSuperClassAndOneCommonInterface() { @@ -168,32 +168,32 @@ final class WideningCategoriesTest extends GenericsTestCase { ClassNode type = lowestUpperBound(a, b) assert type.name =~ /.*Top/ assert type.superClass == make(Top) // includes interface GroovyObject - assert type.interfaces as Set == [make(Serializable)] as Set // extra interface + assert type.interfaces as Set == [SERIALIZABLE_TYPE] as Set // extra interface type = lowestUpperBound(b, a) assert type.name =~ /.*Top/ assert type.superClass == make(Top) - assert type.interfaces as Set == [make(Serializable)] as Set + assert type.interfaces as Set == [SERIALIZABLE_TYPE] as Set } // GROOVY-8111 void testBuildCommonTypeFromTwoClassesWithTwoCommonInterfacesOneIsSelfReferential() { ClassNode a = boolean_TYPE - ClassNode b = extractTypesFromCode("${getClass().getName()}.Pair<String,String> type").type + ClassNode b = extractTypesFromCode("${this.class.name}.Pair<String,String> type").type ClassNode lub = lowestUpperBound(a, b) assert lub.superClass == OBJECT_TYPE - assert lub.interfaces as Set == [make(Comparable), make(Serializable)] as Set + assert lub.interfaces as Set == [COMPARABLE_TYPE, SERIALIZABLE_TYPE] as Set lub = lowestUpperBound(b, a) assert lub.superClass == OBJECT_TYPE - assert lub.interfaces as Set == [make(Comparable), make(Serializable)] as Set + assert lub.interfaces as Set == [COMPARABLE_TYPE, SERIALIZABLE_TYPE] as Set } void testStringWithGString() { ClassNode a = make(String) ClassNode b = make(GString) ClassNode type = lowestUpperBound(a,b) - assert type.interfaces as Set == [make(CharSequence), make(Comparable), make(Serializable)] as Set + assert type.interfaces as Set == [make(CharSequence), COMPARABLE_TYPE, SERIALIZABLE_TYPE] as Set } void testDistinctPrimitiveTypes() { @@ -210,46 +210,46 @@ final class WideningCategoriesTest extends GenericsTestCase { } void testLUBWithTwoInterfacesAndSameGenericArg() { - ClassNode a = extractTypesFromCode("List<String> type").type - ClassNode b = extractTypesFromCode("List<String> type").type + ClassNode a = extractTypesFromCode('List<String> type').type + ClassNode b = extractTypesFromCode('List<String> type').type ClassNode lub = lowestUpperBound(a,b) - assert lub == make(List) + assert lub == LIST_TYPE assert lub.genericsTypes.length == 1 assert lub.genericsTypes[0].type == STRING_TYPE } void testLUBWithTwoInterfacesAndCommonSuperClassGenericArg() { - ClassNode a = extractTypesFromCode("List<Integer> type").type - ClassNode b = extractTypesFromCode("List<Long> type").type + ClassNode a = extractTypesFromCode('List<Integer> type').type + ClassNode b = extractTypesFromCode('List<Long> type').type ClassNode lub = lowestUpperBound(a,b) - assert lub == make(List) + assert lub == LIST_TYPE assert lub.genericsTypes.length == 1 assert lub.genericsTypes[0].wildcard - assert lub.genericsTypes[0].upperBounds[0].superClass == Number_TYPE - assert make(Comparable) in lub.genericsTypes[0].upperBounds[0].interfaces + assert lub.genericsTypes[0].upperBounds[0].name == 'java.lang.Number' + assert COMPARABLE_TYPE in lub.genericsTypes[0].upperBounds[0].interfaces } void testLUBWithTwoInterfacesAndSingleCommonInterface() { - ClassNode a = extractTypesFromCode("List<Set> type").type - ClassNode b = extractTypesFromCode("List<List> type").type + ClassNode a = extractTypesFromCode('List<Set> type').type + ClassNode b = extractTypesFromCode('List<List> type').type ClassNode lub = lowestUpperBound(a,b) - assert lub == make(List) + assert lub == LIST_TYPE assert lub.genericsTypes.length == 1 assert lub.genericsTypes[0].wildcard - assert lub.genericsTypes[0].upperBounds[0] == make(Collection) + assert lub.genericsTypes[0].upperBounds[0] == COLLECTION_TYPE } void testLUBWithTwoInterfacesAndNestedSingleCommonInterface() { - ClassNode a = extractTypesFromCode("Collection<List<Set>> type").type - ClassNode b = extractTypesFromCode("Collection<List<SortedSet>> type").type + ClassNode a = extractTypesFromCode('Collection<List<Set>> type').type + ClassNode b = extractTypesFromCode('Collection<List<SortedSet>> type').type ClassNode lub = lowestUpperBound(a,b) - assert lub == make(Collection) + assert lub == COLLECTION_TYPE assert lub.genericsTypes.length == 1 def nestedType = lub.genericsTypes[0].type - assert nestedType == make(List) - assert nestedType.genericsTypes.length==1 + assert nestedType == LIST_TYPE + assert nestedType.genericsTypes.length == 1 assert nestedType.genericsTypes[0].wildcard - assert nestedType.genericsTypes[0].upperBounds[0] == make(Set) + assert nestedType.genericsTypes[0].upperBounds[0] == SET_TYPE } void testLUBWithTwoArgumentTypesSharingOneInterfaceNotImplementedBySuperClass() { @@ -264,8 +264,8 @@ final class WideningCategoriesTest extends GenericsTestCase { assert lub.genericsTypes[0].wildcard ClassNode genericType = lub.genericsTypes[0].upperBounds[0] assert genericType instanceof LowestUpperBoundClassNode - assert genericType.superClass == make(Top) - assert genericType.interfaces == [make(Serializable)] + assert genericType.name == "${this.class.name}\$Top" + assert genericType.interfaces == [SERIALIZABLE_TYPE] } void testLUBWithTwoParameterizedTypesSharingOneInterfaceNotImplementedBySuperClass() { @@ -276,32 +276,34 @@ final class WideningCategoriesTest extends GenericsTestCase { ClassNode b = extractTypesFromCode('org.codehaus.groovy.ast.tools.WideningCategoriesTest.PTopLong type').type ClassNode lub = lowestUpperBound(a,b) assert lub instanceof LowestUpperBoundClassNode // a virtual class which extends PTop<? extends Number> and implements Serializable + assert lub.interfaces == [SERIALIZABLE_TYPE] assert lub.unresolvedSuperClass == make(PTop) assert lub.unresolvedSuperClass.genericsTypes.length == 1 assert lub.unresolvedSuperClass.genericsTypes[0].wildcard // ? extends Number - ClassNode genericType = lub.unresolvedSuperClass.genericsTypes[0].upperBounds[0] - assert genericType == Long_TYPE + ClassNode upperBound = lub.unresolvedSuperClass.genericsTypes[0].upperBounds[0] + assert upperBound.name == 'java.lang.Number' + assert upperBound.interfaces == [COMPARABLE_TYPE] } void testCommonAssignableType() { def typeA = extractTypesFromCode('LinkedList type').type def typeB = extractTypesFromCode('List type').type def superType = lowestUpperBound(typeA, typeB) - assert superType == make(List) + assert superType == LIST_TYPE } void testCommonAssignableType2() { def typeA = extractTypesFromCode('LinkedHashSet type').type def typeB = extractTypesFromCode('List type').type def superType = lowestUpperBound(typeA, typeB) - assert superType == make(Collection) + assert superType == COLLECTION_TYPE } void testCommonAssignableTypeWithGenerics() { def typeA = extractTypesFromCode('LinkedHashSet<String> type').type def typeB = extractTypesFromCode('List<String> type').type def superType = lowestUpperBound(typeA, typeB) - assert superType == make(Collection) + assert superType == COLLECTION_TYPE } void testLUBOfTwoListTypes() { @@ -310,7 +312,7 @@ final class WideningCategoriesTest extends GenericsTestCase { def superType = lowestUpperBound(typeA, typeB) assert superType instanceof LowestUpperBoundClassNode assert superType.superClass == make(AbstractList) - assert superType.interfaces as Set == [make(Serializable), make(Cloneable)] as Set + assert superType.interfaces as Set == [SERIALIZABLE_TYPE, make(Cloneable)] as Set } void testLUBOfTwoListTypesWithSameGenerics() { @@ -319,7 +321,7 @@ final class WideningCategoriesTest extends GenericsTestCase { def superType = lowestUpperBound(typeA, typeB) assert superType instanceof LowestUpperBoundClassNode assert superType.superClass == make(AbstractList) - assert superType.interfaces as Set == [make(Serializable), make(Cloneable)] as Set + assert superType.interfaces as Set == [SERIALIZABLE_TYPE, make(Cloneable)] as Set assert superType.genericsTypes.length == 1 assert superType.genericsTypes[0].type == STRING_TYPE @@ -331,7 +333,7 @@ final class WideningCategoriesTest extends GenericsTestCase { def superType = lowestUpperBound(typeA, typeB) assert superType instanceof LowestUpperBoundClassNode assert superType.superClass == make(AbstractList) - assert superType.interfaces as Set == [make(Serializable), make(Cloneable)] as Set + assert superType.interfaces as Set == [SERIALIZABLE_TYPE, make(Cloneable)] as Set assert superType.genericsTypes.length == 1 def type = superType.genericsTypes[0] assert type.wildcard diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy index 68181ad0c7..c78f02a04a 100644 --- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy +++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy @@ -1310,21 +1310,21 @@ println someInt void testStaticMethodFromInnerClassConstructor() { assertScript ''' - class Parent { - String str - Parent(String s) { str = s } - } - class Outer { - private class Inner extends Parent { - static String a = 'ok' - Inner() { super(getA()) } - } + class Parent { + String str + Parent(String s) { str = s } + } + class Outer { + private class Inner extends Parent { + static String a = 'ok' + Inner() { super(getA()) } + } - String test() { new Inner().str } - } - def o = new Outer() - assert o.test() == 'ok' - ''' + String test() { new Inner().str } + } + def o = new Outer() + assert o.test() == 'ok' + ''' } // GROOVY-6876 @@ -1338,7 +1338,7 @@ println someInt } } assert new Foo().method() == -1L - ''' + ''' assertScript ''' class Foo { @@ -1355,7 +1355,7 @@ println someInt class Foo { long rankOrderingOrId void setRankOrderingOrId(long rankOrderingOrId) { - this.rankOrderingOrId = rankOrderingOrId < 0 ? -1 : rankOrderingOrId + this.rankOrderingOrId = rankOrderingOrId < 0 ? -1L : rankOrderingOrId } } def f = new Foo()
