You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/07/18 16:10:52 UTC
[groovy] branch GROOVY_3_0_X updated: GROOVY-10086, GROOVY-10230, GROOVY-10316, GROOVY-10344: STC: CCE diamond
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
new 4080975ed3 GROOVY-10086, GROOVY-10230, GROOVY-10316, GROOVY-10344: STC: CCE diamond
4080975ed3 is described below
commit 4080975ed3e01b81e067c9e2ffc07e5b3287b63e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Jul 18 09:58:42 2022 -0500
GROOVY-10086, GROOVY-10230, GROOVY-10316, GROOVY-10344: STC: CCE diamond
3_0_X backport
---
.../transform/stc/StaticTypeCheckingVisitor.java | 36 +-
.../groovy/transform/stc/GenericsSTCTest.groovy | 834 ++++++++++++++++++---
2 files changed, 743 insertions(+), 127 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 16cd5a0678..edf4617707 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1082,6 +1082,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
inferredType = type;
}
+ if (inferredType.isGenericsPlaceHolder()) // GROOVY-10344: "T t = new C<>()"
+ inferredType = getCombinedBoundType(inferredType.getGenericsTypes()[0]);
adjustGenerics(inferredType, cceType);
storeType(cce, cceType);
@@ -3137,10 +3139,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
dummyMN.setDeclaringClass(orig.getDeclaringClass());
dummyMN.setGenericsTypes(orig.getGenericsTypes());
}
- ClassNode classNode = inferReturnTypeGenerics(receiver, dummyMN, arguments);
- ClassNode[] inferred = new ClassNode[classNode.getGenericsTypes().length];
- for (int i = 0; i < classNode.getGenericsTypes().length; i++) {
- GenericsType genericsType = classNode.getGenericsTypes()[i];
+ ClassNode returnType = inferReturnTypeGenerics(receiver, dummyMN, arguments);
+ GenericsType[] returnTypeGenerics = returnType.getGenericsTypes();
+ ClassNode[] inferred = new ClassNode[returnTypeGenerics.length];
+ for (int i = 0, n = returnTypeGenerics.length; i < n; i += 1) {
+ GenericsType genericsType = returnTypeGenerics[i];
ClassNode value = createUsableClassNodeFromGenericsType(genericsType);
inferred[i] = value;
}
@@ -5337,9 +5340,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
* argument is {@code List<T>} without explicit type arguments. Knowning the
* method target of "m", {@code T} could be resolved.
*/
- private static void resolvePlaceholdersFromImplicitTypeHints(final ClassNode[] actuals, final ArgumentListExpression argumentList, final Parameter[] parameterArray) {
- for (int i = 0, n = actuals.length; i < n; i += 1) {
+ private void resolvePlaceholdersFromImplicitTypeHints(final ClassNode[] actuals, final ArgumentListExpression argumentList, final Parameter[] parameterArray) {
+ int np = parameterArray.length;
+ for (int i = 0, n = actuals.length; i < n && np > 0; i += 1) {
Expression a = argumentList.getExpression(i);
+ Parameter p = parameterArray[Math.min(i, np - 1)];
+
+ ClassNode at = actuals[i], pt = p.getOriginType();
+ if (!isUsingGenericsOrIsArrayUsingGenerics(pt)) continue;
+ if (i >= (np - 1) && pt.isArray() && !at.isArray()) pt = pt.getComponentType();
+
+ if (a instanceof ConstructorCallExpression) {
+ inferDiamondType((ConstructorCallExpression) a, pt); // GROOVY-10086, GROOVY-10316
+ }
+
// check for method call without type arguments, with a known target
if (!(a instanceof MethodCall) || (a instanceof MethodCallExpression
&& ((MethodCallExpression) a).isUsingGenerics())) continue;
@@ -5347,14 +5361,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (aNode == null || aNode.getGenericsTypes() == null) continue;
// and unknown generics
- ClassNode at = actuals[i];
if (!GenericsUtils.hasUnresolvedGenerics(at)) continue;
- int np = parameterArray.length;
- Parameter p = parameterArray[Math.min(i, np - 1)];
-
- ClassNode pt = p.getOriginType();
- if (i >= (np - 1) && pt.isArray() && !at.isArray()) pt = pt.getComponentType();
+ while (!at.equals(pt) && !at.equals(OBJECT_TYPE)) {
+ ClassNode sc = GenericsUtils.getSuperClass(at, pt);
+ at = applyGenericsContext(GenericsUtils.extractPlaceholders(at), sc);
+ }
// try to resolve placeholder(s) in argument type using parameter type
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 0b28f76d50..95ff8fc135 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -383,6 +383,34 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ void testReturnTypeInferenceWithMethodGenerics1x() {
+ assertScript '''
+ interface Handle {
+ int getCount()
+ }
+ class HandleContainer<H extends Handle> {
+ H handle
+ }
+ interface Input {
+ HandleContainer<? extends Handle> getResult(key)
+ }
+ interface State {
+ def <X extends Handle> HandleContainer<X> getResult(key)
+ }
+
+ void test(Input input, State state) {
+ def container = state.getResult('k') ?: input.getResult('k')
+ Handle handle = container.handle
+ Integer count = handle.count
+ assert count == 1
+ }
+
+ Handle h = {->1}
+ def c = new HandleContainer(handle: h)
+ test({k->c} as Input, {k->c} as State)
+ '''
+ }
+
@NotYetImplemented // GROOVY-10067
void testReturnTypeInferenceWithMethodGenerics11() {
assertScript '''
@@ -618,6 +646,79 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10589
+ void testReturnTypeInferenceWithMethodGenerics25() {
+ String pogo = '''
+ @groovy.transform.TupleConstructor
+ class Pogo {
+ final java.time.Instant timestamp
+ }
+ List<Pogo> pogos = []
+ '''
+ assertScript pogo + '''
+ Comparator<Pogo> cmp = { Pogo a, Pogo b -> a.timestamp <=> b.timestamp }
+ pogos = pogos.sort(false, cmp)
+ '''
+ assertScript pogo + '''
+ pogos = pogos.sort(false) { Pogo a, Pogo b ->
+ a.timestamp <=> b.timestamp
+ }
+ '''
+ assertScript pogo + '''
+ pogos = pogos.sort(false) { it.timestamp }
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10622
+ void testReturnTypeInferenceWithMethodGenerics26() {
+ String types = '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class A<X> {
+ X x
+ }
+ @groovy.transform.TupleConstructor(defaults=false)
+ class B<Y> {
+ Y y
+ }
+ class C {
+ C(byte b) { }
+ }
+ '''
+ assertScript types + '''
+ def <T extends A<Byte>> void test(B<T> b_of_t) {
+ def t = b_of_t.getY()
+ def x = t.getX()
+ new C(x)
+ }
+ test(new B<>(new A<>((byte)1)))
+ '''
+ assertScript types + '''
+ def <T extends A<Byte>> void test(B<T> b_of_t) {
+ def t = b_of_t.y
+ def x = t.x
+ new C(x)
+ }
+ test(new B<>(new A<>((byte)1)))
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10637
+ void testReturnTypeInferenceWithMethodGenerics27() {
+ assertScript '''
+ class Outer extends groovy.transform.stc.MyBean<Inner> {
+ static class Inner {
+ String string
+ }
+ def bar() {
+ { -> value.string }.call()
+ }
+ }
+
+ def foo = new Outer(value: new Outer.Inner(string:'hello world'))
+ assert foo.bar() == 'hello world'
+ '''
+ }
+
void testDiamondInferrenceFromConstructor1() {
assertScript '''
class Foo<U> {
@@ -928,7 +1029,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- @NotYetImplemented // GROOVY-10086
+ // GROOVY-10086
void testDiamondInferrenceFromConstructor12() {
shouldFailWithMessages '''
@groovy.transform.TupleConstructor(defaults=false)
@@ -942,7 +1043,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
m(0, new C<>(1))
''',
- 'Cannot call', 'm(int, C<D>[]) with arguments [int, C<java.lang.Integer>]'
+ 'Cannot call', 'm(int, C <D>[]) with arguments [int, C <java.lang.Integer>]'
}
// GROOVY-9970
@@ -1000,7 +1101,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
C.m(flag ? new A<>(new B()) : new A<>((B)null))
C.m(flag ? new A<>(new B()) : new A<>((B)new E())) // Cannot call m(A<B>) with arguments [A<? extends B>]
'''
-/*
+
shouldFailWithMessages types + '''
A<B> x = new A<>(new Object())
A<B> y = true ? new A<>(new B()) : new A<>(new Object())
@@ -1008,11 +1109,10 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
C.m(new A<>(new Object()))
C.m(true ? new A<>(new B()) : new A<>(new Object()))
''',
- 'Cannot assign A<java.lang.Object> to: A<B>',
- 'Cannot assign A<? extends java.lang.Object> to: A<B>',
- 'Cannot call C#m(A<B>) with arguments [A<java.lang.Object>]',
- 'Cannot call C#m(A<B>) with arguments [A<? extends java.lang.Object>]'
-*/
+ 'Cannot assign A <java.lang.Object> to: A <B>',
+ 'Cannot assign A <? extends java.lang.Object> to: A <B>',
+ 'Cannot call C#m(A <B>) with arguments [A <java.lang.Object>]'/*,
+ 'Cannot call C#m(A <B>) with arguments [A <? extends java.lang.Object>]'*/
}
@NotYetImplemented // GROOVY-10114
@@ -1242,7 +1342,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- @NotYetImplemented // GROOVY-10316
+ // GROOVY-10316
void testDiamondInferrenceFromConstructor28() {
assertScript '''
class A<T> {
@@ -1270,6 +1370,66 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10266
+ void testDiamondInferrenceFromConstructor30() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class A<T> {
+ T t
+ }
+ class B<U> {
+ def m() {
+ U v = null
+ U w = new A<>(v).t
+
+ String x = ""
+ String y = new A<>(x).t
+ }
+ }
+ new B<String>().m()
+ '''
+ }
+
+ // GROOVY-10662
+ void testDiamondInferrenceFromConstructor31() {
+ assertScript '''
+ class A<X, T> {
+ A(T t, X x) {}
+ void m(X x) {}
+ }
+ class B<T extends Number> {
+ void test() {
+ T t = (T) null
+ Character c = 'c'
+ def a = new A<>(c, t)
+ a.m((T) null) // Cannot find matching method A#m(T)
+ }
+ }
+ new B<Integer>().test()
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10633
+ void testDiamondInferrenceFromConstructor32() {
+ assertScript '''
+ class A<T, Y> {
+ public B<Y> f
+ A(B<Y> b_of_y, T t) {
+ this.f = b_of_y
+ }
+ }
+ class B<T> {
+ void m(T t) {
+ }
+ }
+ <T extends Number> void test() {
+ def x = new B<T>()
+ new A<>(x, '').f.m((T) null)
+ }
+ test()
+ '''
+ }
+
// GROOVY-10280
void testTypeArgumentPropagation() {
assertScript '''
@@ -1360,7 +1520,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
List<? super Number> list = ['string']
''',
- 'Number'
+ 'Cannot assign java.util.List <java.lang.String> to: java.util.List <? super java.lang.Number>'
}
// GROOVY-9914, GROOVY-10036
@@ -1386,6 +1546,112 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10222
+ void testAssignmentShouldWorkForParameterizedType() {
+ assertScript '''
+ class C<T> {
+ def <X> X m() {
+ }
+ void test() {
+ T x = m() // Cannot assign value of type X to variable of type T
+ }
+ }
+ new C().test()
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10342
+ void testAssignmentShouldWorkForParameterizedType2() {
+ assertScript '''
+ class C<T> {
+ T t
+ }
+ def <X> X m() {
+ 123
+ }
+ def <N extends Number> void test() {
+ int x = m()
+ Integer y = m()
+ C<Integer> z = new C<>(); z.t = m()
+
+ C<N> c_of_n = new C<N>(); c_of_n.t = m() // Cannot assign value of type #X to variable of type N
+ }
+ test()
+ '''
+
+ shouldFailWithMessages '''
+ def <X extends CharSequence> X m() {
+ }
+ def <N extends Number> void test() {
+ N n = m()
+ }
+ ''',
+ 'Cannot assign value of type java.lang.CharSequence to variable of type N'
+ }
+
+ // GROOVY-9555
+ void testAssignmentShouldWorkForProperUpperBound() {
+ assertScript '''
+ interface I<T> {
+ }
+ class C implements I<Object> {
+ }
+ interface Factory {
+ def <T extends I> T getInstance(Class<T> clazz)
+ }
+
+ void test(Factory f) {
+ C c = f.getInstance(C)
+ assert c instanceof C
+ assert c instanceof I
+ }
+ test { Class clazz -> clazz.newInstance() }
+ '''
+
+ File parentDir = File.createTempDir()
+ config.with {
+ targetDirectory = File.createTempDir()
+ jointCompilationOptions = [memStub: true]
+ }
+ try {
+ def a = new File(parentDir, 'Face.java')
+ a.write '''
+ public interface Face<T> {
+ }
+ '''
+ def b = new File(parentDir, 'Impl.java')
+ b.write '''
+ public class Impl implements Face<Object> {
+ }
+ '''
+ def c = new File(parentDir, 'Supplier.java')
+ c.write '''
+ public interface Supplier {
+ public <T extends Face> T getInstance(Class<T> clazz);
+ }
+ '''
+ def d = new File(parentDir, 'Tester.groovy')
+ d.write '''
+ void test(Supplier s) {
+ def x = s.getInstance(Impl)
+ assert x instanceof Impl
+ assert x instanceof Face
+ }
+ test { Class clazz -> clazz.newInstance() }
+ '''
+
+ def loader = new GroovyClassLoader(this.class.classLoader)
+ def cu = new JavaAwareCompilationUnit(config, loader)
+ cu.addSources(a, b, c, d)
+ cu.compile()
+
+ loader.loadClass('Tester').main()
+ } finally {
+ parentDir.deleteDir()
+ config.targetDirectory.deleteDir()
+ }
+ }
+
void testGroovy5154() {
assertScript '''
class Foo {
@@ -1962,6 +2228,115 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ @NotYetImplemented // GROOVY-8409, GROOVY-9915
+ void testShouldUseMethodGenericType10() {
+ assertScript '''
+ interface OngoingStubbing<T> /*extends IOngoingStubbing*/ {
+ // type parameter from enclosing type in signature:
+ OngoingStubbing<T> thenReturn(T value)
+ }
+ static <T> OngoingStubbing<T> when(T methodCall) {
+ [thenReturn: { T value -> null }] as OngoingStubbing<T>
+ }
+ Optional<String> foo() {
+ }
+
+ when(foo()).thenReturn(Optional.empty())
+ '''
+ }
+
+ // GROOVY-8409, GROOVY-9902
+ void testShouldUseMethodGenericType11() {
+ File parentDir = File.createTempDir()
+ config.with {
+ targetDirectory = File.createTempDir()
+ jointCompilationOptions = [memStub: true]
+ }
+ try {
+ def a = new File(parentDir, 'Main.groovy')
+ a.write '''
+ def obj = new Pojo()
+ Foo raw = obj.getFoo('')
+ raw.bar = raw.baz // Cannot assign value of type Object to variable of type R
+ '''
+ def b = new File(parentDir, 'Pojo.java')
+ b.write '''
+ public class Pojo {
+ public <R extends I> Foo<R> getFoo(String key) {
+ return new Foo<>();
+ }
+ }
+ '''
+ def c = new File(parentDir, 'Types.groovy')
+ c.write '''
+ interface I {
+ }
+ class Foo<T extends I> {
+ T bar
+ T baz
+ }
+ '''
+
+ def loader = new GroovyClassLoader(this.class.classLoader)
+ def cu = new JavaAwareCompilationUnit(config, loader)
+ cu.addSources(a, b, c)
+ cu.compile()
+
+ loader.loadClass('Main').main()
+ } finally {
+ parentDir.deleteDir()
+ config.targetDirectory.deleteDir()
+ }
+ }
+
+ // GROOVY-10088
+ void testShouldUseMethodGenericType12() {
+ shouldFailWithMessages '''
+ class C<T> {
+ void setP(T t) { }
+ }
+ class D<X> extends C<X> {
+ }
+
+ new D<Number>().p = 'x'
+ ''',
+ 'Cannot assign value of type java.lang.String to variable of type T'
+ }
+
+ // GROOVY-10225
+ void testShouldUseMethodGenericType13() {
+ assertScript '''
+ def <T> T m(T t) {
+ assert t == null
+ }
+ def <N extends Number, X extends N> void test() {
+ X x = (X) null
+ m(false ? x : (X) null) // was NPE
+ }
+ test()
+ '''
+ }
+
+ // GROOVY-10315
+ void testShouldUseMethodGenericType14() {
+ for (args in ['m2(), c.m()'/*, 'c.m(), m2()'*/]) {
+ assertScript """
+ class C<T> {
+ def T m() {
+ }
+ }
+ def <X> X m2() {
+ }
+ def <Y> void m3(Y y1, Y y2) {
+ }
+ def <Z> void test(C<Z> c) {
+ m3($args)
+ }
+ test(new C<String>())
+ """
+ }
+ }
+
// GROOVY-10364
void testShouldUseMethodGenericType15() {
assertScript '''
@@ -2186,6 +2561,29 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10373
+ void testAssignNullTypeParameterWithUpperBounds2() {
+ assertScript '''
+ class A<I, E extends I> {
+ void bar(E y) { }
+ }
+ class B<T> {
+ }
+ class C<S extends B<Character>> {
+ A<S, ? extends S> foo() {
+ (A<S, ? extends S>) null
+ }
+ }
+ class D<I extends B<Character>> {
+ void test() {
+ C<I> x = (C<I>) null
+ x?.foo()?.bar(null)
+ }
+ }
+ new D<B<Character>>().test()
+ '''
+ }
+
void testMethodCallWithArgumentUsingNestedGenerics() {
assertScript '''
ThreadLocal<Map<Integer, String>> cachedConfigs = new ThreadLocal<Map<Integer, String>>()
@@ -2406,6 +2804,39 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-7549, GROOVY-9847
+ void testRegressionInGenericsTypeInference2() {
+ assertScript '''
+ class Test {
+ @groovy.transform.ToString(excludes='children')
+ private static class TreeAttr {
+ String name
+ Integer val = 0
+ List<TreeAttr> children = []
+ }
+
+ static main(args) {
+ new Test().test(1)
+ }
+
+ void test(Integer count) {
+ TreeAttr root = new TreeAttr(name:'foo')
+ List<TreeAttr> collector = root.children
+
+ for (name in ['bar','baz']) { // tokens in a path
+ def item = collector.find { it.name == name }
+ if (!item) {
+ item = new TreeAttr(name: name)
+ collector.add(item)
+ }
+ collector = item.children
+ if (count) item.val += count
+ }
+ }
+ }
+ '''
+ }
+
// In Groovy, we do not throw warnings (in general) and in that situation, not for unchecked
// assignments like in Java
// In the following test, the LHS of the assignment uses generics, while the RHS does not.
@@ -2595,6 +3026,21 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ @NotYetImplemented // GROOVY-10153
+ void testCompatibleArgumentsForPlaceholders11() {
+ ['A', 'B', 'C'].each { T ->
+ assertScript """
+ class A {}
+ class B extends A {}
+ class C extends B {}
+ class Foo<T extends A> {}
+
+ Foo<? super C> foo = new Foo<$T>()
+ // ^ lower bound is C (explicit); upper bound is A (implicit)
+ """
+ }
+ }
+
void testIncompatibleArgumentsForPlaceholders1() {
shouldFailWithMessages '''
def <T extends Number> T test(T one, T two) { }
@@ -2821,7 +3267,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
- void testCorrectlyBoundedBySuperGenericParameterType() {
+ void testCorrectlyBoundedBySuperGenericParameterType1() {
assertScript '''
class Foo {
static <T extends List<? super CharSequence>> void bar(T a) {}
@@ -2830,6 +3276,31 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-8034
+ void testCorrectlyBoundedBySuperGenericParameterType2() {
+ assertScript '''
+ class A<I, O> {
+ def <IO extends A<? super O, ?>> IO andThen(IO next) { next }
+ }
+
+ def a1 = new A<String , Integer>()
+ def a2 = new A<Integer, Double >()
+ def a3 = new A<Double , String >()
+ def a4 = new A<String , Double >()
+ def a5 = new A<Number , Object >()
+
+ a1.andThen(a2)
+ a2.andThen(a3)
+ a3.andThen(a4)
+ a4.andThen(a5)
+
+ a1.andThen(a2)
+ .andThen(a3)
+ .andThen(a4)
+ .andThen(a5)
+ '''
+ }
+
void testCorrectlyBoundedByExtendsPlaceholderParameterType() {
assertScript '''
class Foo {
@@ -2935,31 +3406,30 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-5721
void testExtractComponentTypeFromSubclass() {
assertScript '''
- class MyList extends ArrayList<Double> {}
+ class MyList extends ArrayList<Double> {}
- List<Double> list1 = new ArrayList<Double>()
- list1 << 0.0d
+ List<Double> list1 = new ArrayList<Double>()
+ list1 << 0.0d
- // OK
- Double d1 = list1.get(0)
+ // OK
+ Double d1 = list1.get(0)
- //---------------------------
+ //---------------------------
- List<Double> list2 = new MyList()
- list2 << 0.0d
+ List<Double> list2 = new MyList()
+ list2 << 0.0d
- //Groovyc: [Static type checking] - Cannot assign value of type java.lang.Object to variable of type java.lang.Double
- Double d2 = list2.get(0)
+ //Groovyc: [Static type checking] - Cannot assign value of type java.lang.Object to variable of type java.lang.Double
+ Double d2 = list2.get(0)
- //---------------------------
+ //---------------------------
- MyList list3 = new MyList()
- list3 << 0.0d
+ MyList list3 = new MyList()
+ list3 << 0.0d
- //Groovyc: [Static type checking] - Cannot assign value of type java.lang.Object to variable of type java.lang.Double
- Double d3 = list3.get(0)
+ //Groovyc: [Static type checking] - Cannot assign value of type java.lang.Object to variable of type java.lang.Double
+ Double d3 = list3.get(0)
'''
-
}
// GROOVY-5724
@@ -3024,8 +3494,49 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10166
+ void testShouldFindMethodEvenWithRepeatNames1() {
+ assertScript '''
+ abstract class A<T extends C> {
+ T getC() {
+ }
+ Map toMap() {
+ c.getMap(this)
+ }
+ }
+
+ class C<T extends A> {
+ Map getMap(T a) {
+ }
+ }
+
+ new C()
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10049, GROOVY-10166
+ void testShouldFindMethodEvenWithRepeatNames2() {
+ assertScript '''
+ abstract class A<T extends C> {
+ T getC() {
+ }
+ }
+
+ class C<T extends A> {
+ T get() {
+ A a = null
+ a.c.get(1)
+ }
+ T get(int i) {
+ }
+ }
+
+ new C()
+ '''
+ }
+
// GROOVY-10196
- void testShouldFindMethodEvenWithRepeatNames() {
+ void testShouldFindMethodEvenWithRepeatNames3() {
assertScript '''
interface M<K,V> {
}
@@ -3045,34 +3556,59 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- // GROOVY-5893
- @NotYetImplemented
+ @NotYetImplemented // GROOVY-10322
+ void testShouldFindMethodEvenWithRepeatNames4() {
+ assertScript '''
+ class C<T> {
+ def <T> T m(T t) { // this T hides T from C<T>
+ return t
+ }
+ }
+ int x = new C<String>().m(1) // no error, param and return types are `int` not `String`
+ assert x == 1
+ '''
+ }
+
+ // GROOVY-10337
+ void testShouldFindMethodEvenWithRepeatNames5() {
+ assertScript '''
+ class C<X,Y> {
+ C(C<Y,? extends Y> that) {
+ }
+ }
+ def <T> void test() {
+ new C<Number,T>((C<T,T>)null) // cannot call ctor with argument C<T,T>
+ }
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-5893
void testPlusInClosure() {
assertScript '''
- def list = [1, 2, 3]
+ def list = [1, 2, 3]
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
- assert node.getNodeMetaData(INFERRED_TYPE) == int_TYPE
- })
- def sum = 0
- list.each { int i -> sum = sum+i }
- assert sum == 6
+ @ASTTest(phase=INSTRUCTION_SELECTION,value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == int_TYPE
+ })
+ def sum = 0
+ list.each { int i -> sum = sum+i }
+ assert sum == 6
- sum = 0
- list.each { int i -> sum += i }
- assert sum == 6
+ sum = 0
+ list.each { int i -> sum += i }
+ assert sum == 6
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
- })
- def sumWithInject = list.inject(0, { int x, int y -> x + y })
- sum = sumWithInject
- assert sum == 6
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
+ })
+ def sumWithInject = list.inject(0, { int x, int y -> x + y })
+ sum = sumWithInject
+ assert sum == 6
'''
}
// GROOVY-10320
- void testPlusOverload() {
+ void testPlusOverride() {
assertScript '''
interface I<T extends I> {
T plus(T t_aka_i)
@@ -3194,70 +3730,64 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-6051
void testGenericsReturnTypeInferenceShouldNotThrowNPE() {
assertScript '''
- class Bar {
- public static List<Date> bar(List<Date> dummy) {}
- }
- class Foo extends Bar {
- static public Date genericItem() {
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- def inft = node.getNodeMetaData(INFERRED_TYPE)
- assert inft == make(List)
- assert inft.genericsTypes[0].type == make(Date)
- })
- def res = bar(null)
+ class Bar {
+ static List<Date> bar(List<Date> dates) {
+ }
+ }
+ class Foo extends Bar {
+ static public Date genericItem() {
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def inft = node.getNodeMetaData(INFERRED_TYPE)
+ assert inft == make(List)
+ assert inft.genericsTypes[0].type == make(Date)
+ })
+ def res = bar(null)
- res[0]
+ res[0]
+ }
}
- }
- new Foo()
+ new Foo()
'''
}
// GROOVY-6035
void testReturnTypeInferenceWithClosure() {
assertScript '''import org.codehaus.groovy.ast.expr.ClosureExpression
- class CTypeTest {
-
- public static void test1(String[] args) {
-
- // Cannot assign value of type java.lang.Object to variable of type CTypeTest
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
- def cl = node.rightExpression.arguments[0]
- assert cl instanceof ClosureExpression
- def type = cl.getNodeMetaData(INFERRED_TYPE)
- assert type == CLOSURE_TYPE
- assert type.isUsingGenerics()
- assert type.genericsTypes
- assert type.genericsTypes[0].type.name == 'CTypeTest'
-
- type = node.getNodeMetaData(INFERRED_TYPE)
- assert type.name == 'CTypeTest'
- })
- def s1 = cache {
- return new CTypeTest();
- }
-
- CTypeTest s2 = cache {
- new CTypeTest()
+ class CTypeTest {
+ static test(String[] args) {
+ // Cannot assign value of type Object to variable of type CTypeTest
+ @ASTTest(phase=INSTRUCTION_SELECTION,value={
+ def cl = node.rightExpression.arguments[0]
+ assert cl instanceof ClosureExpression
+ def type = cl.getNodeMetaData(INFERRED_TYPE)
+ assert type == CLOSURE_TYPE
+ assert type.isUsingGenerics()
+ assert type.genericsTypes
+ assert type.genericsTypes[0].type.name == 'CTypeTest'
+
+ type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.name == 'CTypeTest'
+ })
+ def s1 = cache {
+ new CTypeTest()
+ }
+ CTypeTest s2 = cache {
+ new CTypeTest()
+ }
+ }
+ static <T> T cache(Closure<T> closure) {
+ return closure.call();
+ }
}
-
- }
-
-
- static <T> T cache(Closure<T> closure) {
- return closure.call();
- }
-
- }
- 1
+ 1
'''
}
// GROOVY-10557
void testReturnTypeInferenceWithClosure2() {
- assertScript '''
+ assertScript '''import java.util.function.Function
class C {
- def <T> T m(java.util.function.Function<Reader,T> f) {
+ def <T> T m(Function<Reader,T> f) {
new StringReader("").withCloseable { reader ->
f.apply(reader)
}
@@ -3301,7 +3831,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
Foo<Map> f = new Foo<Map>("a",1)
}
bar()
- ''', '[Static type checking] - Cannot find matching method Foo#<init>(java.lang.String, int)'
+ ''',
+ 'Cannot find matching method Foo#<init>(java.lang.String, int)'
}
// GROOVY-5742
@@ -3767,8 +4298,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testInVariantAndContraVariantGenerics() {
assertScript '''
class Thing {
- public <O> void contravariant(Class<? super O> type, O object) {}
- public <O> void invariant(Class<O> type, O object) {}
+ def <O> void contravariant(Class<? super O> type, O object) {}
+ def <O> void invariant(Class<O> type, O object) {}
void m() {
invariant(String, "foo")
contravariant(String, "foo") // fails, can't find method
@@ -3780,12 +4311,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-6731
void testContravariantMethodResolution() {
- assertScript '''
- interface Function<T, R> {
- R apply(T t)
- }
+ assertScript '''import java.util.function.Function
- public <I, O> void transform(Function<? super I, ? extends O> function) {
+ def <I, O> void transform(Function<? super I, ? extends O> function) {
function.apply('')
}
@@ -3800,24 +4328,86 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testContravariantMethodResolutionWithImplicitCoercion() {
- assertScript '''
- interface Function<T, R> {
- R apply(T t)
- }
+ @NotYetImplemented // GROOVY-9998
+ void testContravariantMethodResolution2() {
+ assertScript '''import groovy.transform.*
- public <I, O> void transform(Function<? super I, ? extends O> function) {
- function.apply('')
+ @TupleConstructor(defaults=false)
+ class A {
+ final int order
+ }
+ @InheritConstructors @ToString(includeSuperProperties=true)
+ class B extends A {
}
- String result = null
- transform {
- result = 'ok'
+ Comparator<A> comparator = { a1, a2 -> Integer.compare(a1.order, a2.order) }
+
+ def input = [new B(2), new B(3), new B(1), new B(0)]
+ // sorted(Comparator<? super B>) using Comparator<A>
+ def result = input.stream().sorted(comparator).toList()
+ assert result.toString().equals("[B(0), B(1), B(2), B(3)]")
+ '''
+ }
+
+ void testContravariantMethodResolutionWithImplicitCoercion1() {
+ assertScript '''
+ // static <T,E> List<T> collectMany(Iterable<E> it, Closure<? extends Collection<? extends T>> fn)
+ List<String> strings = [1,2,3].collectMany {
+ Collections.emptyList()
}
- assert result == 'ok'
+ assert strings.isEmpty()
'''
}
+ void testContravariantMethodResolutionWithImplicitCoercion2() {
+ ['public', 'static'].each { modifier ->
+ assertScript """import java.util.function.Function
+
+ $modifier <I, O> void transform(Function<? super I, ? extends O> function) {
+ function.apply('')
+ }
+
+ boolean called = false
+ transform {
+ called = true
+ }
+ assert called
+ """
+ }
+ }
+
+ void testContravariantMethodResolutionWithImplicitCoercion3() {
+ File parentDir = File.createTempDir()
+ config.with {
+ targetDirectory = File.createTempDir()
+ jointCompilationOptions = [memStub: true]
+ }
+ try {
+ def a = new File(parentDir, 'Bean.java')
+ a.write '''
+ class Bean {
+ static Class<? extends CharSequence> getType() { return String.class; }
+ }
+ '''
+ def b = new File(parentDir, 'Main.groovy')
+ b.write '''
+ def <T> T create(Class<T> c) { null }
+ CharSequence cs = create(Bean.type)
+ assert cs == null
+ '''
+
+ def loader = new GroovyClassLoader(this.class.classLoader)
+ def cu = new JavaAwareCompilationUnit(config, loader)
+ cu.addSources(a, b)
+ cu.compile()
+
+ loader.loadClass('Main').main()
+ } finally {
+ parentDir.deleteDir()
+ config.targetDirectory.deleteDir()
+ }
+ }
+
// GROOVY-5981
void testCovariantAssignment() {
assertScript '''
@@ -3993,6 +4583,20 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'Cannot assign java.util.List <java.lang.Integer> to: java.util.List <CharSequence>'
}
+ @NotYetImplemented // GROOVY-10295
+ void testReturnTypeChecking2() {
+ assertScript '''
+ List<CharSequence> test() {
+ return ['foo','bar','baz']
+ }
+ '''
+ assertScript '''
+ Map<String,Object> test() {
+ return [date: new Date(), string: new String()]
+ }
+ '''
+ }
+
void testBoundedReturnTypeChecking() {
assertScript '''
class Foo {