Skip to content

Commit

Permalink
GROOVY-11383: STC: connect generics from primitive types to Comparable
Browse files Browse the repository at this point in the history
3_0_X backport
  • Loading branch information
eric-milles committed Jun 20, 2024
1 parent 24328d6 commit 2e969a1
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,7 @@ protected static boolean typeCheckMethodsWithGenerics(final ClassNode receiver,
return typeCheckMethodsWithGenerics(receiver.getGenericsTypes()[0].getType(), argumentTypes, candidateMethod);
}

return typeCheckMethodsWithGenerics(receiver, argumentTypes, candidateMethod, false);
return typeCheckMethodsWithGenerics(StaticTypeCheckingVisitor.wrapTypeIfNecessary(receiver), argumentTypes, candidateMethod, false);
}

private static boolean typeCheckMethodsWithGenerics(final ClassNode receiver, final ClassNode[] argumentTypes, final MethodNode candidateMethod, final boolean isExtensionMethod) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5845,7 +5845,7 @@ protected boolean typeCheckMethodsWithGenericsOrFail(final ClassNode receiver, f
}
}

addStaticTypeError("Cannot call " + (mgt == null ? "" : GenericsUtils.toGenericTypesString(mgt)) + receiver.toString(false) + "#" +
addStaticTypeError("Cannot call " + (mgt == null ? "" : GenericsUtils.toGenericTypesString(mgt)) + prettyPrintTypeName(wrapTypeIfNecessary(receiver)) + "#" +
toMethodParametersString(candidateMethod.getName(), paramTypes) + " with arguments " + formatArgumentList(arguments), location);
return false;
}
Expand Down Expand Up @@ -5899,6 +5899,8 @@ protected void addStaticTypeError(final String msg, final ASTNode expr) {
protected void addNoMatchingMethodError(ClassNode receiver, final String name, final ClassNode[] args, final Expression call) {
if (isClassClassNodeWrappingConcreteType(receiver)) {
receiver = receiver.getGenericsTypes()[0].getType();
} else {
receiver = wrapTypeIfNecessary(receiver);
}
addStaticTypeError("Cannot find matching method " + prettyPrintTypeName(receiver) + "#" + toMethodParametersString(name, args) + ". Please check if the declared type is correct and if the method exists.", call);
}
Expand Down
6 changes: 3 additions & 3 deletions src/test/groovy/bugs/Groovy8609Bug.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ final class Groovy8609Bug extends GroovyTestCase {
}
}
'''
assert err.contains('Cannot call A <ArrayList, HashMap>#getFirstRecord(java.util.ArrayList <HashMap>) with arguments [java.util.ArrayList <TreeMap>]')
assert err.contains('Cannot call A#getFirstRecord(java.util.ArrayList <HashMap>) with arguments [java.util.ArrayList <TreeMap>]')
}

void testUpperBoundWithGenericsThroughWrongType2() {
Expand All @@ -118,7 +118,7 @@ final class Groovy8609Bug extends GroovyTestCase {
}
}
'''
assert err.contains('Cannot call A <ArrayList, HashMap>#getFirstRecord(java.util.ArrayList <HashMap>) with arguments [java.util.ArrayList <HashMap>]')
assert err.contains('Cannot call A#getFirstRecord(java.util.ArrayList <HashMap>) with arguments [java.util.ArrayList <HashMap>]')
}

void testUpperBoundWithGenericsThroughWrongType3() {
Expand All @@ -138,6 +138,6 @@ final class Groovy8609Bug extends GroovyTestCase {
}
}
'''
assert err.contains('Cannot call A <ArrayList, HashMap>#getFirstRecord(java.util.ArrayList <HashMap>) with arguments [java.util.ArrayList <HashMap>]')
assert err.contains('Cannot call A#getFirstRecord(java.util.ArrayList <HashMap>) with arguments [java.util.ArrayList <HashMap>]')
}
}
36 changes: 24 additions & 12 deletions src/test/groovy/transform/stc/BugsSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -30,61 +30,71 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { it / 2 } }
''', 'Cannot find matching method java.lang.Object#div(int)'
''',
'Cannot find matching method java.lang.Object#div(int)'
}
void testShouldNotAllowDivBynUntypedVariable() {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { 2 / it } }
''', 'Cannot find matching method int#div(java.lang.Object)'
''',
'Cannot find matching method java.lang.Integer#div(java.lang.Object)'
}
void testShouldNotAllowModOnUntypedVariable() {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { it % 2 } }
''', 'Cannot find matching method java.lang.Object#mod(int)'
''',
'Cannot find matching method java.lang.Object#mod(int)'
}
void testShouldNotAllowModBynUntypedVariable() {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { 2 % it } }
''', 'Cannot find matching method int#mod(java.lang.Object)'
''',
'Cannot find matching method java.lang.Integer#mod(java.lang.Object)'
}
void testShouldNotAllowMulOnUntypedVariable() {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { it * 2 } }
''', 'Cannot find matching method java.lang.Object#multiply(int)'
''',
'Cannot find matching method java.lang.Object#multiply(int)'
}
void testShouldNotAllowMulBynUntypedVariable() {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { 2 * it } }
''', 'Cannot find matching method int#multiply(java.lang.Object)'
''',
'Cannot find matching method java.lang.Integer#multiply(java.lang.Object)'
}
void testShouldNotAllowPlusOnUntypedVariable() {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { it + 2 } }
''', 'Cannot find matching method java.lang.Object#plus(int)'
''',
'Cannot find matching method java.lang.Object#plus(int)'
}
void testShouldNotAllowPlusWithUntypedVariable() {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { 2 + it } }
''', 'Cannot find matching method int#plus(java.lang.Object)'
''',
'Cannot find matching method java.lang.Integer#plus(java.lang.Object)'
}
void testShouldNotAllowMinusOnUntypedVariable() {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { it - 2 } }
''', 'Cannot find matching method java.lang.Object#minus(int)'
''',
'Cannot find matching method java.lang.Object#minus(int)'
}
void testShouldNotAllowMinusByUntypedVariable() {
shouldFailWithMessages '''
def foo(Closure cls) {}
def bar() { foo { 2 - it } }
''', 'Cannot find matching method int#minus(java.lang.Object)'
''',
'Cannot find matching method java.lang.Integer#minus(java.lang.Object)'
}

// GROOVY-7929
Expand All @@ -100,7 +110,8 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
x()
}
}
''', 'Cannot find matching method <UnionType:C+T>#x'
''',
'Cannot find matching method <UnionType:C+T>#x'
}

// GROOVY-10102
Expand Down Expand Up @@ -204,7 +215,8 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
L<String> items = ['foo', 'bar'] as L<String>
items.removeIf({a, b -> 1} as Comparator<?>)
assert items
''', 'Cannot call L <String>#removeIf(java.util.Comparator <? super java.lang.String>) with arguments [java.util.Comparator <?>]'
''',
'Cannot call L#removeIf(java.util.Comparator <? super java.lang.String>) with arguments [java.util.Comparator <?>]'
}

void testGroovy5482ListsAndFlowTyping() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
numbers.sequence
numbers.string
''',
'Cannot call <CS extends java.lang.CharSequence> java.util.ArrayList <java.lang.Number>#getSequence() with arguments []',
'Cannot call java.util.ArrayList <java.lang.Number>#getString() with arguments []',
'Cannot call <CS extends java.lang.CharSequence> java.util.ArrayList#getSequence() with arguments []',
'Cannot call java.util.ArrayList#getString() with arguments []',
'No such property: sequence for class: java.util.ArrayList',
'No such property: string for class: java.util.ArrayList'
}
Expand Down
39 changes: 27 additions & 12 deletions src/test/groovy/transform/stc/GenericsSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
List<String> list = []
list << 1
''',
'Cannot call <T> java.util.ArrayList <String>#leftShift(T) with arguments [int]'
'Cannot call <T> java.util.ArrayList#leftShift(T) with arguments [int]'
}

void testAddOnList2UsingLeftShift() {
Expand Down Expand Up @@ -143,7 +143,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
List<Integer> list = new LinkedList<>()
list << 'Hello'
''',
'Cannot call <T> java.util.LinkedList <java.lang.Integer>#leftShift(T) with arguments [java.lang.String]'
'Cannot call <T> java.util.LinkedList#leftShift(T) with arguments [java.lang.String]'
}

void testAddOnListWithDiamondAndNullUsingLeftShift() {
Expand All @@ -153,6 +153,21 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}

void testCompareToOnPrimitive() {
assertScript '''
int a = 1
assert (a < 2)
assert !(a < 1)
assert (a <= 1)
'''
// GROOVY-11383
shouldFailWithMessages '''
int a = 42
def b = (a < new Object())
''',
'Cannot find matching method java.lang.Integer#compareTo(java.lang.Object)'
}

void testReturnTypeInference1() {
assertScript '''
class Foo<U> {
Expand Down Expand Up @@ -1941,7 +1956,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
List<String> list = new LinkedList<String>([1,2,3])
''',
'Cannot call java.util.LinkedList <String>#<init>(java.util.Collection <? extends java.lang.String>) with arguments [java.util.ArrayList <java.lang.Integer>]'
'Cannot call java.util.LinkedList#<init>(java.util.Collection <? extends java.lang.String>) with arguments [java.util.ArrayList <java.lang.Integer>]'
}

void testCompatibleGenericAssignmentWithInference() {
Expand Down Expand Up @@ -2336,7 +2351,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
A<String, Integer> a = new B()
a.test()
''',
'Cannot call A <String, Integer>#<init>(java.lang.Class <String>, java.lang.Class <Integer>) with arguments [java.lang.Class <java.lang.Integer>, java.lang.Class <java.lang.String>]'
'Cannot call A#<init>(java.lang.Class <String>, java.lang.Class <Integer>) with arguments [java.lang.Class <java.lang.Integer>, java.lang.Class <java.lang.String>]'
}

void testConstructorCallWithClassParameterUsingClassLiteralArg() {
Expand Down Expand Up @@ -2392,13 +2407,13 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
def map = new HashMap<Integer, Integer>()
map[123] = new Object()
''',
'Cannot call <K,V> java.util.HashMap <Integer, Integer>#putAt(java.lang.Integer, java.lang.Integer) with arguments [int, java.lang.Object]'
'Cannot call <K,V> java.util.HashMap#putAt(java.lang.Integer, java.lang.Integer) with arguments [int, java.lang.Object]'

shouldFailWithMessages '''
def map = new HashMap<String, Integer>()
map['x'] = new Object()
''',
'Cannot call <K,V> java.util.HashMap <String, Integer>#putAt(java.lang.String, java.lang.Integer) with arguments [java.lang.String, java.lang.Object]'
'Cannot call <K,V> java.util.HashMap#putAt(java.lang.String, java.lang.Integer) with arguments [java.lang.String, java.lang.Object]'
}

// GROOVY-9069
Expand All @@ -2414,8 +2429,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
''',
'Cannot call java.util.Map <String, Map>#put(java.lang.String, java.util.Map <String, List>) with arguments [java.lang.String, java.util.LinkedHashMap <String, List>]',
'Cannot call <K,V> java.util.Map <String, Map>#putAt(java.lang.String, java.util.Map <String, List>) with arguments [java.lang.String, java.util.LinkedHashMap <String, List>]'
'Cannot call java.util.Map#put(java.lang.String, java.util.Map <String, List>) with arguments [java.lang.String, java.util.LinkedHashMap <String, List>]',
'Cannot call <K,V> java.util.Map#putAt(java.lang.String, java.util.Map <String, List>) with arguments [java.lang.String, java.util.LinkedHashMap <String, List>]'

assertScript '''
void test(Map<String, Map<String, List<String>>> maps) {
Expand Down Expand Up @@ -2559,7 +2574,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
''',
'Cannot call <X> groovy.transform.stc.GenericsSTCTest$ClassA <Long>#bar(java.lang.Class <Long>) with arguments [java.lang.Class <? extends java.lang.Object>]'
'Cannot call <X> groovy.transform.stc.GenericsSTCTest$ClassA#bar(java.lang.Class <Long>) with arguments [java.lang.Class <? extends java.lang.Object>]'
}

// GROOVY-8961, GROOVY-9915
Expand Down Expand Up @@ -2929,7 +2944,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
Collection<Integer> numbers = (Collection<Integer>) [1,2,3]
boolean r = list.addAll(numbers)
''',
'Cannot call java.util.ArrayList <java.lang.String>#addAll(java.util.Collection <? extends java.lang.String>) with arguments [java.util.Collection <Integer>]'
'Cannot call java.util.ArrayList#addAll(java.util.Collection <? extends java.lang.String>) with arguments [java.util.Collection <Integer>]'
}

// GROOVY-5528
Expand Down Expand Up @@ -3241,7 +3256,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
Map<Date, Date> map = new HashMap<>()
map['foo'] = new Date()
''',
'Cannot call <K,V> java.util.HashMap <java.util.Date, java.util.Date>#putAt(java.util.Date, java.util.Date) with arguments [java.lang.String, java.util.Date]'
'Cannot call <K,V> java.util.HashMap#putAt(java.util.Date, java.util.Date) with arguments [java.lang.String, java.util.Date]'
}
void testInferDiamondForAssignmentWithDatesAndIllegalValueUsingPut() {
shouldFailWithMessages '''
Expand Down Expand Up @@ -3281,7 +3296,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
Map<Date, Date> map = new HashMap<>()
map[new Date()] = 'foo'
''',
'Cannot call <K,V> java.util.HashMap <java.util.Date, java.util.Date>#putAt(java.util.Date, java.util.Date) with arguments [java.util.Date, java.lang.String]'
'Cannot call <K,V> java.util.HashMap#putAt(java.util.Date, java.util.Date) with arguments [java.util.Date, java.lang.String]'
}

void testCallMethodWithParameterizedArrayList() {
Expand Down
4 changes: 2 additions & 2 deletions src/test/groovy/transform/stc/STCAssignmentTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,15 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
int i = 0
i += new Object()
''',
'Cannot find matching method int#plus(java.lang.Object)'
'Cannot find matching method java.lang.Integer#plus(java.lang.Object)'
}

void testIntMinusEqualsObject() {
shouldFailWithMessages '''
int i = 0
i -= new Object()
''',
'Cannot find matching method int#minus(java.lang.Object)'
'Cannot find matching method java.lang.Integer#minus(java.lang.Object)'
}

void testStringPlusEqualsString() {
Expand Down
2 changes: 1 addition & 1 deletion src/test/groovy/transform/stc/STCnAryExpressionTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class STCnAryExpressionTest extends StaticTypeCheckingTestCase {
int num = 2
num+obj
''',
'Cannot find matching method int#plus(java.lang.Object)'
'Cannot find matching method java.lang.Integer#plus(java.lang.Object)'
}

void testPrimitiveComparison() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ class TypeCheckingExtensionsTest extends StaticTypeCheckingTestCase {
Date y = new Date()
x+y
''',
'Cannot find matching method int#plus(java.util.Date)'
'Cannot find matching method java.lang.Integer#plus(java.util.Date)'

extension = 'groovy/transform/stc/BinaryOperatorTestExtension.groovy'
assertScript '''
Expand All @@ -364,7 +364,7 @@ class TypeCheckingExtensionsTest extends StaticTypeCheckingTestCase {
Date y = new Date()
x << y
''',
'Cannot find matching method int#leftShift(java.util.Date)'
'Cannot find matching method java.lang.Integer#leftShift(java.util.Date)'

extension = 'groovy/transform/stc/BinaryOperatorTestExtension.groovy'
assertScript '''
Expand Down
2 changes: 1 addition & 1 deletion src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
method().toUpperCase()
}
''',
'Cannot find matching method int#toUpperCase()'
'Cannot find matching method java.lang.Integer#toUpperCase()'
}

void testDeclarationTypeInference() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class InheritConstructorsTransformTest extends GroovyShellTestCase {
assert op.toString() == '3|DOWN'
'''
assert message.contains('Cannot find matching method OrderPublisher#<init>(java.util.Date)')
assert message.contains('Cannot call OrderPublisher <RoundingMode>#<init>(java.util.Set <RoundingMode>) with arguments [java.util.HashSet <Date>]')
assert message.contains('Cannot call OrderPublisher#<init>(java.util.Set <RoundingMode>) with arguments [java.util.HashSet <Date>]')
}

// GROOVY-9323
Expand Down

0 comments on commit 2e969a1

Please sign in to comment.