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/03/30 19:46:33 UTC
[groovy] 01/03: checking generics of super used raw type instead of parameterized type
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
commit 4a9624b87ebc3d374e2ceff1cbb66ab3fbb50496
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Feb 27 11:19:16 2021 -0600
checking generics of super used raw type instead of parameterized type
abstarct class A<X> {}
class C<Y> extends A<Y> {}
A<Z> a = new C<Z>() // was checking C<Z> compatible with A (raw)
---
.../java/org/codehaus/groovy/ast/GenericsType.java | 119 +--
.../groovy/transform/stc/GenericsSTCTest.groovy | 1056 +++++++++++++++++---
.../asm/sc/GenericsStaticCompileTest.groovy | 8 +-
3 files changed, 947 insertions(+), 236 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
index e689249..36d5c8c 100644
--- a/src/main/java/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -22,6 +22,7 @@ import org.codehaus.groovy.ast.tools.GenericsUtils;
import org.codehaus.groovy.ast.tools.WideningCategories;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
@@ -61,6 +62,7 @@ public class GenericsType extends ASTNode {
this.type = Objects.requireNonNull(type); // TODO: ensure type is not primitive
}
+ @Override
public String toString() {
return toString(this, new HashSet<>());
}
@@ -189,12 +191,8 @@ public class GenericsType extends ASTNode {
//--------------------------------------------------------------------------
/**
- * Compares this generics type with the provided class node. If the provided
- * class node is compatible with the generics specification, returns true.
- * Otherwise, returns false. The check is complete, meaning that nested
- * generics are also checked.
- *
- * @return if {@code classNode} is or is not compatible with this generics specification
+ * Determines if the provided type is compatible with this specification.
+ * The check is complete, meaning that nested generics are also checked.
*/
public boolean isCompatibleWith(final ClassNode classNode) {
GenericsType[] genericsTypes = classNode.getGenericsTypes();
@@ -212,21 +210,24 @@ public class GenericsType extends ASTNode {
return name0.equals(getName());
}
if (getLowerBound() != null) {
+ // check for "? super T" vs "T"
if (name0.equals(getLowerBound().getUnresolvedName())) {
return true;
}
} else if (getUpperBounds() != null) {
+ // check for "? extends T" vs "T"
if (name0.equals(getUpperBounds()[0].getUnresolvedName())) {
return true;
}
}
+ // check for "? extends/super X" vs "T extends/super X"
return checkGenerics(classNode);
}
if (isWildcard() || isPlaceholder()) {
// if the generics spec is a wildcard or a placeholder then check the bounds
ClassNode lowerBound = getLowerBound();
if (lowerBound != null) {
- // for a lower bound, perform the upper bound checks with reversed arguments
+ // test bound and type in reverse for lower bound vs upper bound
if (!implementsInterfaceOrIsSubclassOf(lowerBound, classNode)) {
return false;
}
@@ -240,19 +241,16 @@ public class GenericsType extends ASTNode {
return false;
}
}
- // if the provided classnode is a subclass of the upper bound
- // then check that the generic types supplied by the class node are compatible with
- // this generics specification
- // for example, we could have the spec saying List<String> but provided classnode
- // saying List<Integer>
+ // if the provided type is a subclass of the upper bound(s) then
+ // check that the generic types supplied are compatible with this
+ // for example, this spec could be "Type<X>" but type is "Type<Y>"
return checkGenerics(classNode);
}
- // if there are no bounds, the generic type is basically Object, and everything is compatible
+ // if there are no bounds, the generic type is basically Object and everything is compatible
return true;
}
- // last, we could have the spec saying List<String> and a classnode saying List<Integer> so
- // we must check that generics are compatible
- return getType().equals(classNode) && compareGenericsWithBound(classNode, type);
+ // not placeholder or wildcard; no covariance allowed for type or bound(s)
+ return classNode.equals(getType()) && compareGenericsWithBound(classNode, getType());
}
private static boolean implementsInterfaceOrIsSubclassOf(final ClassNode type, final ClassNode superOrInterface) {
@@ -332,24 +330,31 @@ public class GenericsType extends ASTNode {
// class node are not parameterized. This means that we must create a
// new class node with the parameterized types that the current class node
// has defined.
- ClassNode node = GenericsUtils.parameterizeType(classNode, face);
- return compareGenericsWithBound(node, bound);
+ if (face.getGenericsTypes() != null) {
+ face = GenericsUtils.parameterizeType(classNode, face);
+ }
+ return compareGenericsWithBound(face, bound);
}
}
}
if (bound instanceof WideningCategories.LowestUpperBoundClassNode) {
// another special case here, where the bound is a "virtual" type
// we must then check the superclass and the interfaces
- boolean success = compareGenericsWithBound(classNode, bound.getSuperClass());
- if (success) {
- for (ClassNode face : bound.getInterfaces()) {
- success &= compareGenericsWithBound(classNode, face);
- if (!success) break;
- }
- if (success) return true;
+ if (compareGenericsWithBound(classNode, bound.getSuperClass())
+ && Arrays.stream(bound.getInterfaces()).allMatch(face -> compareGenericsWithBound(classNode, face))) {
+ return true;
}
}
- return compareGenericsWithBound(getParameterizedSuperClass(classNode), bound);
+ if (classNode.equals(ClassHelper.OBJECT_TYPE)) {
+ return false;
+ }
+ ClassNode superClass = classNode.getUnresolvedSuperClass();
+ if (superClass == null) {
+ superClass = ClassHelper.OBJECT_TYPE;
+ } else if (superClass.getGenericsTypes() != null) {
+ superClass = GenericsUtils.parameterizeType(classNode, superClass);
+ }
+ return compareGenericsWithBound(superClass, bound);
}
GenericsType[] cnTypes = classNode.getGenericsTypes();
@@ -357,7 +362,7 @@ public class GenericsType extends ASTNode {
cnTypes = classNode.redirect().getGenericsTypes();
}
if (cnTypes == null) {
- // may happen if generic type is Foo<T extends Foo> and classnode is Foo -> Foo
+ // may happen if generic type is Foo<T extends Foo> and ClassNode is Foo -> Foo
return true;
}
@@ -460,59 +465,19 @@ public class GenericsType extends ASTNode {
}
/**
- * If you have a class which extends a class using generics, returns the superclass with parameterized types. For
- * example, if you have:
- * <code>class MyList<T> extends LinkedList<T>
- * def list = new MyList<String>
- * </code>
- * then the parameterized superclass for MyList<String> is LinkedList<String>
- * @param classNode the class for which we want to return the parameterized superclass
- * @return the parameterized superclass
- */
- private static ClassNode getParameterizedSuperClass(final ClassNode classNode) {
- if (ClassHelper.OBJECT_TYPE.equals(classNode)) return null;
- ClassNode superClass = classNode.getUnresolvedSuperClass();
- if (superClass == null) return ClassHelper.OBJECT_TYPE;
-
- if (!classNode.isUsingGenerics() || !superClass.isUsingGenerics()) {
- return superClass;
- }
-
- GenericsType[] genericsTypes = classNode.getGenericsTypes();
- GenericsType[] redirectGenericTypes = classNode.redirect().getGenericsTypes();
- superClass = superClass.getPlainNodeReference();
- if (genericsTypes == null || redirectGenericTypes == null || superClass.getGenericsTypes() == null) {
- return superClass;
- }
- for (int i = 0, genericsTypesLength = genericsTypes.length; i < genericsTypesLength; i += 1) {
- if (redirectGenericTypes[i].isPlaceholder()) {
- GenericsType genericsType = genericsTypes[i];
- GenericsType[] superGenericTypes = superClass.getGenericsTypes();
- for (int j = 0, superGenericTypesLength = superGenericTypes.length; j < superGenericTypesLength; j += 1) {
- final GenericsType superGenericType = superGenericTypes[j];
- if (superGenericType.isPlaceholder() && superGenericType.getName().equals(redirectGenericTypes[i].getName())) {
- superGenericTypes[j] = genericsType;
- }
- }
- }
- }
- return superClass;
- }
-
- /**
- * Represents GenericsType name
- * TODO In order to distinguish GenericsType with same name(See GROOVY-8409), we should add a property to keep the declaring class.
- *
- * fixing GROOVY-8409 steps:
- * 1) change the signature of constructor GenericsTypeName to `GenericsTypeName(String name, ClassNode declaringClass)`
- * 2) try to fix all compilation errors(if `GenericsType` has declaringClass property, the step would be a bit easy to fix...)
- * 3) run all tests to see whether the change breaks anything
- * 4) if all tests pass, congratulations! but if some tests are broken, try to debug and find why...
- *
+ * Represents {@link GenericsType} name.
+ * <p>
+ * TODO: In order to distinguish GenericsType with same name, we should add a property to keep the declaring class.
+ * <ol>
+ * <li> change the signature of constructor GenericsTypeName to `GenericsTypeName(String name, ClassNode declaringClass)`
+ * <li> try to fix all compilation errors(if `GenericsType` has declaringClass property, the step would be a bit easy to fix...)
+ * <li> run all tests to see whether the change breaks anything
+ * <li> if all tests pass, congratulations! but if some tests are broken, try to debug and find why...
+ * </ol>
* We should find a way to set declaring class for `GenericsType` first, it can be completed at the resolving phase.
*/
public static class GenericsTypeName {
- private String name;
+ private final String name;
public GenericsTypeName(final String name) {
this.name = Objects.requireNonNull(name);
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 81dab95..70da3e4 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -27,36 +27,39 @@ import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
*/
class GenericsSTCTest extends StaticTypeCheckingTestCase {
- void testDeclaration() {
+ void testDeclaration1() {
assertScript '''
List test = new LinkedList<String>()
'''
}
- void testDeclaration5() {
+ void testDeclaration2() {
assertScript '''
Map<String,Integer> obj = new HashMap<String,Integer>()
'''
}
- void testDeclaration6() {
+ void testDeclaration3() {
shouldFailWithMessages '''
Map<String,String> obj = new HashMap<String,Integer>()
- ''', 'Incompatible generic argument types. Cannot assign java.util.HashMap <String, Integer> to: java.util.Map <String, String>'
+ ''',
+ 'Incompatible generic argument types. Cannot assign java.util.HashMap <String, Integer> to: java.util.Map <String, String>'
}
void testDeclaration4() {
// no generics checked after first wildcard
shouldFailWithMessages '''
Map<? extends CharSequence,String> obj = new HashMap<String,Integer>()
- ''', 'Incompatible generic argument types. Cannot assign java.util.HashMap <String, Integer> to: java.util.Map <? extends java.lang.CharSequence, String>'
+ ''',
+ 'Incompatible generic argument types. Cannot assign java.util.HashMap <String, Integer> to: java.util.Map <? extends java.lang.CharSequence, String>'
}
void testAddOnList() {
shouldFailWithMessages '''
List<String> list = []
list.add(1)
- ''', "[Static type checking] - Cannot find matching method java.util.List#add(int)"
+ ''',
+ 'Cannot find matching method java.util.List#add(int)'
}
void testAddOnList2() {
@@ -82,7 +85,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
List<String> list = []
list << 1
- ''', 'Cannot call <T> java.util.List <String>#leftShift(T) with arguments [int]'
+ ''',
+ 'Cannot call <T> java.util.List <String>#leftShift(T) with arguments [int]'
}
void testAddOnList2UsingLeftShift() {
@@ -130,14 +134,16 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
List<Integer> list = new LinkedList<>()
list.add 'Hello'
- ''', 'Cannot find matching method java.util.LinkedList#add(java.lang.String). Please check if the declared type is correct and if the method exists.'
+ ''',
+ 'Cannot find matching method java.util.LinkedList#add(java.lang.String). Please check if the declared type is correct and if the method exists.'
}
void testAddOnListWithDiamondAndWrongTypeUsingLeftShift() {
shouldFailWithMessages '''
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 <java.lang.Integer>#leftShift(T) with arguments [java.lang.String]'
}
void testAddOnListWithDiamondAndNullUsingLeftShift() {
@@ -147,7 +153,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testReturnTypeInference() {
+ void testReturnTypeInference1() {
assertScript '''
class Foo<U> {
U method() { }
@@ -157,18 +163,262 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testReturnTypeInferenceWithDiamond() {
+ void testReturnTypeInference2() {
assertScript '''
- class Foo<U> {
- U method() { }
+ Object m() {
+ def s = '1234'
+ println 'Hello'
+ }
+ '''
+ }
+
+ void testReturnTypeInferenceWithMethodGenerics1() {
+ assertScript '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.toString(false) == 'java.util.List <java.lang.Long>'
+ })
+ def list = Arrays.asList(new Long[]{1L,0L})
+ assert list.size() == 2
+ assert list.get(0) == 1
+ assert list.get(1) == 0
+ '''
+
+ assertScript '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.toString(false) == 'java.util.List <java.lang.Long>'
+ })
+ def list = Arrays.asList(1L,0L)
+ assert list.size() == 2
+ assert list.get(0) == 1
+ assert list.get(1) == 0
+ '''
+
+ assertScript '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.toString(false) == 'java.util.List <java.lang.Long>'
+ })
+ def list = Arrays.asList(0L)
+ assert list.size() == 1
+ assert list.get(0) == 0
+ '''
+
+ assertScript '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.toString(false) == 'java.util.List <T extends java.lang.Object>'
+ })
+ def list = Arrays.asList()
+ assert list.size() == 0
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10062
+ void testReturnTypeInferenceWithMethodGenerics2() {
+ assertScript '''
+ def <T> T m(T t, ... zeroOrMore) {
}
- Foo<Integer> foo = new Foo<>()
- Integer result = foo.method()
+
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type == Integer_TYPE
+ })
+ def obj = m(42)
+ '''
+ }
+
+ void testReturnTypeInferenceWithMethodGenerics3() {
+ assertScript '''
+ Number number = Optional.of(42).get()
+ assert number.intValue() == 42
+ '''
+ }
+
+ // GROOVY-9796
+ void testReturnTypeInferenceWithMethodGenerics4() {
+ shouldFailWithMessages '''
+ Number number = Optional.of(42).orElse(Double.NaN)
+ assert number.intValue() == 42
+ ''',
+ 'Cannot find matching method java.util.Optional#orElse(double).'
+ }
+
+ void testReturnTypeInferenceWithMethodGenerics5() {
+ assertScript '''
+ Number number = Optional.of((Number) 42).orElse(Double.NaN)
+ assert number.intValue() == 42
+ '''
+ }
+
+ // GROOVY-9796
+ void testReturnTypeInferenceWithMethodGenerics6() {
+ shouldFailWithMessages '''
+ Number number = Optional.ofNullable((Integer) null).orElse(42d)
+ assert number.intValue() == 42
+ ''',
+ 'Cannot find matching method java.util.Optional#orElse(double).'
+ }
+
+ void testReturnTypeInferenceWithMethodGenerics7() {
+ assertScript '''
+ Number number = Optional.<Number>ofNullable((Integer) null).orElse(42d)
+ assert number.intValue() == 42
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-9033
+ void testReturnTypeInferenceWithMethodGenerics8() {
+ shouldFailWithMessages '''
+ List<String> test() {
+ def x = [].each { }
+ x.add(new Object())
+ return x // List<E>
+ }
+ ''',
+ 'Incompatible generic argument types.' // Cannot assign java.util.List<java.lang.Object> to: java.util.List<java.lang.String>
+
+ assertScript '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.genericsTypes[0].toString() == 'java.lang.String'
+ assert type.genericsTypes[1].toString() == 'java.util.List<java.lang.Object>' // not List<E>
+ })
+ def map = [ key: [] ]
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10049, GROOVY-10053
+ void testReturnTypeInferenceWithMethodGenerics9() {
+ assertScript '''
+ def <X> Set<X> f(Class<X> x) {
+ Collections.singleton(x.newInstance(42))
+ }
+ def <T extends Number> List<T> g(Class<T> t) {
+ f(t).stream().filter(n -> n.intValue() > 0).toList()
+ }
+
+ def result = g(Integer)
+ assert result == [ 42 ]
+ '''
+
+ ['t::cast', 'n -> t.cast(n)', 'n -> (N) n', '{ n -> (N) n }'].each { cast ->
+ assertScript """
+ Set<Number> f() {
+ Collections.<Number>singleton(42)
+ }
+ def <N extends Number> Set<N> g(Class<N> t) {
+ Set<N> result = new HashSet<>()
+ f().stream().filter(t::isInstance)
+ .map($cast).forEach(n -> result.add(n))
+ return result
+ }
+
+ def result = g(Integer)
+ assert result == [42] as Set
+ """
+ }
+
+ assertScript '''
+ def <T> String test(Iterable<T> iterable) {
+ Iterator<T> it = iterable.iterator()
+ if (it.hasNext()) {
+ List<String[]> table = []
+ it.forEachRemaining(r -> {
+ if (r instanceof List) {
+ String[] cells = ((List) r).stream().map(c -> c?.toString())
+ table.add(cells)
+ }
+ })
+ return table
+ }
+ }
+
+ String result = test([ ['x'], ['y'], [null] ])
+ assert result == '[[x], [y], [null]]'
+ '''
+ }
+
+ // GROOVY-10051
+ void testReturnTypeInferenceWithMethodGenerics10() {
+ assertScript '''
+ abstract class State<H extends Handle> {
+ // Why not return HandleContainer<H>? I can't really say.
+ def <T extends Handle> HandleContainer<T> getHandleContainer(key) {
+ }
+ }
+ class HandleContainer<H extends Handle> {
+ H handle
+ }
+ interface Handle {
+ Result getResult()
+ }
+ class Result {
+ int itemCount
+ String[] items
+ }
+
+ List<String> getStrings(State state, List keys) {
+ keys.collectMany { key ->
+ List<String> strings = Collections.emptyList()
+ def container = state.getHandleContainer(key) // returns HandleContainer<Object> not HandleContainer<SearchHandle>
+ if (container != null) {
+ def result = container.handle.result
+ if (result != null && result.itemCount > 0) {
+ strings = Arrays.asList(result.items)
+ }
+ }
+ strings
+ }
+ }
+
+ assert getStrings(null,[]).isEmpty()
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10067
+ void testReturnTypeInferenceWithMethodGenerics11() {
+ assertScript '''
+ def <N extends Number> N getNumber() {
+ return (N) 42
+ }
+ def f(Integer i) {
+ }
+ def g(int i) {
+ }
+
+ Integer i = this.<Integer>getNumber()
+ f(this.<Integer>getNumber())
+ g(this.<Integer>getNumber())
+
+ i = (Integer) getNumber()
+ f((Integer) getNumber())
+ g((Integer) getNumber())
+
+ i = getNumber()
+ f(getNumber())
+ g(getNumber())
+
+ i = number
+ f(number)
+ g(number)
+ '''
+ }
+
+ // GROOVY-8974
+ void testReturnTypeInferenceWithMethodGenerics12() {
+ assertScript '''
+ def <T> T identity(T t) { t }
+ List<String> list = identity(new ArrayList<>())
+ list.add('foo')
+ def foo = list[0]
+ assert foo.toUpperCase() == 'FOO'
'''
}
// GROOVY-9064
- void testReturnTypeInferenceWithGenerics() {
+ void testReturnTypeInferenceWithMethodGenerics13() {
assertScript '''
List getSomeRows() { [new String[]{'x'}] }
List<String[]> rows = getSomeRows()
@@ -179,20 +429,70 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testReturnTypeInferenceWithMethodGenerics1() {
+ // GROOVY-8409
+ void testReturnTypeInferenceWithMethodGenerics14() {
+ ['R', 'S', 'T', 'U'].each { t -> // BiFunction uses R, T and U
+ assertScript """
+ def <$t> $t applyFunction(java.util.function.BiFunction<Date, URL, $t> action) {
+ $t result = action.apply(new Date(), new URL('https://www.example.com'))
+ return result
+ }
+
+ // GroovyCastException: Cannot cast object 'foo' with class 'java.lang.String' to class 'java.util.Date'
+ java.util.function.BiFunction<Date, URL, String> func = { Date d, URL u -> 'foo' }
+ def result = applyFunction(func)
+ assert result == 'foo'
+ """
+ }
+ }
+
+ @NotYetImplemented // GROOVY-8409, GROOVY-10067
+ void testReturnTypeInferenceWithMethodGenerics15() {
+ shouldFailWithMessages '''
+ List<CharSequence> list = ['x'].collect() // GROOVY-10074
+ ''',
+ 'Incompatible generic argument types. Cannot assign java.util.List<java.lang.String> to: java.util.List<java.lang.CharSequence>'
+
+ shouldFailWithMessages '''
+ List<CharSequence> list = ['x'].stream().toList() // TODO: fix type param bound of StreamGroovyMethods#toList(Stream<T>)
+ ''',
+ 'Incompatible generic argument types. Cannot assign java.util.List<java.lang.String> to: java.util.List<java.lang.CharSequence>'
+
assertScript '''
- List<Long> list = Arrays.asList([0L,0L] as Long[])
+ import static java.util.stream.Collectors.toList
+ List<CharSequence> list = ['x'].stream().collect(toList())
'''
}
- void testReturnTypeInferenceWithMethodGenerics2() {
+ @NotYetImplemented // GROOVY-7316, GROOVY-10256
+ void testReturnTypeInferenceWithMethodGenerics16() {
+ shouldFailWithMessages '''
+ def <T extends CharSequence> T chars() {
+ }
+ List test() {
+ chars()
+ }
+ ''',
+ 'Cannot return value of type #T for method returning java.util.List'
+ }
+
+ // GROOVY-10098
+ void testReturnTypeInferenceWithMethodGenerics17() {
assertScript '''
- List<Long> list = Arrays.asList(0L,0L)
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T extends Number> {
+ T p
+ T m() {
+ Closure<T> x = { -> p }
+ x() // Cannot return value of type Object for method returning T
+ }
+ }
+ assert new C<>(42).m() == 42
'''
}
// GROOVY-8638
- void testReturnTypeInferenceWithMethodGenerics3() {
+ void testReturnTypeInferenceWithMethodGenerics18() {
assertScript '''
@Grab('com.google.guava:guava:30.1.1-jre')
import com.google.common.collect.*
@@ -208,36 +508,43 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- // GROOVY-10098
- void testReturnTypeInferenceWithMethodGenerics4() {
+ // GROOVY-10222
+ void testReturnTypeInferenceWithMethodGenerics19() {
assertScript '''
- @groovy.transform.TupleConstructor(defaults=false)
- class C<T extends Number> {
- T p
- T m() {
- Closure<T> x = { -> p }
- x() // Cannot return value of type Object on method returning type T
- }
+ class Task {
+ def <T> T exec(args) {
+ args
+ }
}
- assert new C<>(42).m() == 42
+ class Test {
+ Task task
+ def <T> T exec(args) {
+ task.exec(args) // Cannot return value of type #T for method returning T
+ }
+ }
+ String result = new Test(task: new Task()).exec('works')
+ assert result == 'works'
'''
}
// GROOVY-9500
- void testReturnTypeInferenceWithMethodGenerics5() {
+ void testReturnTypeInferenceWithMethodGenerics20() {
assertScript '''
trait Entity<D> {
}
+
abstract class Path<F extends Entity, T extends Entity> implements Iterable<Path.Segment<F,T>> {
interface Segment<F, T> {
F start()
T end()
}
+
abstract F start()
T end() {
- end // Cannot return value of type Path$Segment<F,T> on method returning type T
+ end // Cannot return value of type Path$Segment<F,T> for method returning T
}
T end
+
@Override
void forEach(java.util.function.Consumer<? super Segment<F, T>> action) {
}
@@ -248,194 +555,423 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
Iterator<Segment<F, T>> iterator() {
}
}
+
null
'''
}
- // GROOVY-10051
- void testReturnTypeInferenceWithMethodGenerics6() {
- assertScript '''
- abstract class State<H extends Handle> {
- // Why not return HandleContainer<H>? I can't really say.
- def <T extends Handle> HandleContainer<T> getHandleContainer(key) {
+ @NotYetImplemented // GROOVY-10339
+ void testReturnTypeInferenceWithMethodGenerics21() {
+ for (type in ['Character', 'Integer']) {
+ shouldFailWithMessages """
+ Character foo() {
}
- }
- class HandleContainer<H extends Handle> {
- H handle
- }
- interface Handle {
- Result getResult()
- }
- class Result {
- int itemCount
- String[] items
- }
+ def <T> T bar(T x, T y) {
+ }
+ $type z = bar(foo(), 1)
+ """,
+ 'Cannot assign value of type'
+ }
+ }
- List<String> getStrings(State state, List keys) {
- keys.collectMany { key ->
- List<String> strings = Collections.emptyList()
- def container = state.getHandleContainer(key) // returns HandleContainer<Object> not HandleContainer<SearchHandle>
- if (container != null) {
- def result = container.handle.result
- if (result != null && result.itemCount > 0) {
- strings = Arrays.asList(result.items)
- }
- }
- strings
+ @NotYetImplemented // GROOVY-10339
+ void testReturnTypeInferenceWithMethodGenerics22() {
+ for (type in ['Comparable', 'Serializable']) {
+ assertScript """
+ String foo() {
+ }
+ def <T> T bar(T x, T y) {
}
+ $type z = bar(foo(), 1)
+ """
+ }
+ }
+
+ // GROOVY-10347
+ void testReturnTypeInferenceWithMethodGenerics23() {
+ assertScript '''
+ String[] one = ['foo','bar'], two = ['baz']
+ Map<String,Integer> map = one.collectEntries{[it,1]} + two.collectEntries{[it,2]}
+ assert map == [foo:1, bar:1, baz:2]
+ '''
+ }
+
+ // GROOVY-10347
+ void testReturnTypeInferenceWithMethodGenerics24() {
+ assertScript '''
+ class Pogo {
+ String s
+ }
+ class Sorter implements Comparator<Pogo>, Serializable {
+ int compare(Pogo p1, Pogo p2) { p1.s <=> p2.s }
}
- assert getStrings(null,[]).isEmpty()
+ Pogo[] pogos = [new Pogo(s:'foo'), new Pogo(s:'bar')]
+ List<String> strings = pogos.sort(true, new Sorter())*.s // sort(T[],boolean,Comparator<? super T>)
+ assert strings == ['bar', 'foo']
'''
}
void testDiamondInferrenceFromConstructor1() {
assertScript '''
- Set< Long > s2 = new HashSet<>()
+ class Foo<U> {
+ U method() { }
+ }
+ Foo<Integer> foo = new Foo<>()
+ Integer result = foo.method()
'''
}
void testDiamondInferrenceFromConstructor2() {
assertScript '''
- new HashSet<>(Arrays.asList(0L,0L));
+ Set<Long> set = new HashSet<>()
'''
}
void testDiamondInferrenceFromConstructor3() {
+ assertScript '''
+ new HashSet<>(Arrays.asList(0L))
+ '''
+
+ // not diamond inference, but tests compatible assignment
+ assertScript '''
+ Set<Number> set = new HashSet<Number>(Arrays.asList(0L))
+ '''
+
shouldFailWithMessages '''
- Set< Number > s3 = new HashSet<>(Arrays.asList(0L,0L));
- ''', 'Cannot assign java.util.HashSet <java.lang.Long> to: java.util.Set <Number>'
+ Set<Number> set = new HashSet<>(Arrays.asList(0L))
+ ''',
+ 'Cannot assign java.util.HashSet <java.lang.Long> to: java.util.Set <Number>'
+ }
+
+ @NotYetImplemented
+ void testDiamondInferrenceFromConstructor3a() {
+ assertScript '''
+ Set<Number> set = new HashSet<>(Arrays.asList(0L))
+ '''
+
+ assertScript '''
+ Set<? super Number> set = new HashSet<>(Arrays.asList(0L))
+ '''
+
+ assertScript '''
+ Set<? extends Number> set = new HashSet<>(Arrays.asList(0L))
+ '''
}
+ @NotYetImplemented // GROOVY-7419
void testDiamondInferrenceFromConstructor4() {
assertScript '''
- Set<Number> s4 = new HashSet<Number>(Arrays.asList(0L,0L))
+ Map<Thread.State, Object> map = new EnumMap<>(Thread.State)
+ assert map.size() == 0
+ assert map.isEmpty()
+ '''
+ }
+
+ // GROOVY-6232
+ void testDiamondInferrenceFromConstructor5() {
+ ['"a",new Object()', 'new Object(),"b"', '"a","b"'].each { args ->
+ assertScript """
+ class C<T> {
+ C(T x, T y) {
+ }
+ }
+ C<Object> c = new C<>($args)
+ """
+ }
+ }
+
+ // GROOVY-9948
+ void testDiamondInferrenceFromConstructor6() {
+ assertScript '''
+ class C<T> {
+ T p
+ C(T p) {
+ this.p = p
+ }
+ }
+
+ C<Integer> c = new C<>(1)
+ assert c.p < 10
+ '''
+ }
+
+ // GROOVY-9948
+ void testDiamondInferrenceFromConstructor7() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> {
+ T p
+ }
+
+ C<Integer> c = new C<>(1)
+ assert c.p < 10
+ '''
+ }
+
+ // GROOVY-9984
+ void testDiamondInferrenceFromConstructor7a() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> {
+ T p
+ }
+
+ C<Integer> c = new C<>(null)
+ assert c.p === null
+ '''
+ }
+
+ // GROOVY-9956
+ void testDiamondInferrenceFromConstructor8() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> {
+ T p
+ }
+ interface I { }
+ class D implements I { }
+
+ C<I> ci = new C<I>(new D())
+ ci = new C<>(new D()) // infers C<D> on RHS
+ '''
+ }
+
+ // GROOVY-9996
+ void testDiamondInferrenceFromConstructor8a() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> {
+ T p
+ }
+ interface I { }
+ class D implements I { }
+ void test(C<I> c) { assert c.p instanceof D }
+
+ I i = new D() // infers D for "i"
+ def ci = new C<>(i) // infers C<D> for "ci"
+ test(ci)
+ '''
+ }
+
+ // GROOVY-10011
+ void testDiamondInferrenceFromConstructor8b() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> {
+ T p
+ }
+ interface I { }
+ class D implements I { }
+
+ void test(I i) {
+ if (i instanceof D) {
+ C<D> cd = new C<>(i)
+ }
+ }
+ test(new D())
+ '''
+ }
+
+ @NotYetImplemented
+ void testDiamondInferrenceFromConstructor9() {
+ assertScript '''
+ abstract class A<X> { }
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> extends A<T> {
+ T p
+ }
+ interface I { }
+ class D implements I { }
+
+ A<I> ai = new C<>(new D())
+ '''
+
+ shouldFailWithMessages '''
+ abstract class A<X> { }
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> extends A<T> {
+ T p
+ }
+ interface I { }
+ class D implements I { }
+
+ A<String> ax = new C<>(new D())
+ ''',
+ 'Incompatible generic argument types. Cannot assign C<D> to: A<java.lang.String>'
+
+ shouldFailWithMessages '''
+ Set<List<String>> strings = new HashSet<>([new ArrayList<Number>()])
+ ''',
+ 'Incompatible generic argument types. Cannot assign java.util.HashSet<java.util.ArrayList<java.lang.Number>> to: java.util.Set<java.util.List<java.lang.String>>'
+ }
+
+ // GROOVY-9972
+ void testDiamondInferrenceFromConstructor9a() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> {
+ T p
+ }
+ class D {
+ public String f = 'D#f'
+ }
+ C<D> cd = true ? new C<>(new D()) : new C<>(new D())
+ assert cd.p.f.toLowerCase() == 'd#f'
+ '''
+
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> {
+ T p
+ }
+ class D {
+ public String f = 'D#f'
+ }
+ boolean b = false
+ C<D> cd = b ? new C<>(new D()) : (b ? new C<>((D) null) : new C<>(new D()))
+ assert cd.p.f.toLowerCase() == 'd#f'
'''
- }
-
- // GROOVY-9984
- void testDiamondInferrenceFromConstructor5() {
+/*
assertScript '''
@groovy.transform.TupleConstructor(defaults=false)
class C<T> {
T p
}
-
- C<Integer> c = new C<>(null)
- assert c.p === null
+ class D {
+ public String f = 'D#f'
+ }
+ def cd
+ if (true) {
+ cd = new C<>(new D())
+ } else {
+ cd = new C<>((D) null)
+ }
+ assert cd.p.f.toLowerCase() == 'd#f'
+ '''
+*/
+ assertScript '''
+ @groovy.transform.TupleConstructor
+ class C {
+ List<D> list
+ }
+ class D {
+ }
+ List test(C... array) {
+ // old code used "List<D> many" as target for guts of closure
+ List<D> many = array.collectMany { it.list ?: [] }
+ }
+ def result = test(new C(), new C(list:[new D()]))
+ assert result.size() == 1
'''
}
- // GROOVY-9996
- void testDiamondInferrenceFromConstructor6() {
+ @NotYetImplemented
+ void testDiamondInferrenceFromConstructor9b() {
assertScript '''
@groovy.transform.TupleConstructor(defaults=false)
class C<T> {
T p
}
- interface I { }
- class D implements I { }
- void test(C<I> c) { assert c.p instanceof D }
-
- I i = new D() // infers D for "i"
- def ci = new C<>(i) // infers C<D> for "ci"
- test(ci)
+ class D {
+ public String f = 'D#f'
+ }
+ def foo = { flag, C<D> cd = (flag ? new C<>(new D()) : new C<>(new D())) ->
+ cd.p.f.toLowerCase()
+ }
+ assert foo.call(true) == 'd#f'
'''
- }
- // GROOVY-10011
- void testDiamondInferrenceFromConstructor7() {
- assertScript '''
+ shouldFailWithMessages '''
@groovy.transform.TupleConstructor(defaults=false)
class C<T> {
T p
}
- interface I { }
- class D implements I { }
-
- void test(I i) {
- if (i instanceof D) {
- C<D> cd = new C<>(i)
- }
+ class D {
+ public String f = 'D#f'
}
- test(new D())
- '''
- }
-
- // GROOVY-8974
- void testDiamondInferrenceFromConstructor8() {
- assertScript '''
- def <T> T identity(T t) { t }
- List<String> list = identity(new ArrayList<>())
- list.add('foo')
- def foo = list[0]
- assert foo.toUpperCase() == 'FOO'
- '''
+ def foo = { flag, C<D> cd = (flag ? new C<>(new D()) : new C<>(new Object())) ->
+ cd.p.f.toLowerCase()
+ }
+ ''',
+ 'Incompatible generic argument types. Cannot assign C<? extends java.lang.Object> to: C<D>'
}
- // GROOVY-10283
- void testDiamondInferrenceFromConstructor9() {
+ @NotYetImplemented // GROOVY-9963
+ void testDiamondInferrenceFromConstructor10() {
assertScript '''
- class A<T1, T2> {
- }
- class B<T1 extends Number, T2 extends A<C, ? extends T1>> {
- T2 t
- B(T2 t) {
- this.t = t
- }
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> {
+ T p
}
- class C {
+ static void m(String s) {
+ assert s.isEmpty()
}
-
- new B<Integer,A<C,Integer>>(new A<>())
+ m(new C<>("").p)
'''
}
- // GROOVY-9972
- void testDiamondInferrenceFromConstructor10() {
+ @NotYetImplemented // GROOVY-10080
+ void testDiamondInferrenceFromConstructor11() {
assertScript '''
- @groovy.transform.TupleConstructor
+ @groovy.transform.TupleConstructor(defaults=false)
class C<T> {
T p
}
class D {
- public String f = 'D#f'
+ int m(Object[] objects) {
+ 42
+ }
}
- C<D> cd = true ? new C<>(new D()) : new C<>(new D())
- assert cd.p.f.toLowerCase() == 'd#f'
+ def closure = { ->
+ new C<>(new D())
+ }
+ def result = closure().p.m(new BigDecimal[0]) // Cannot find matching method Object#m(...)
+ assert result == 42
'''
+ }
- assertScript '''
- @groovy.transform.TupleConstructor
+ @NotYetImplemented // GROOVY-10086
+ void testDiamondInferrenceFromConstructor12() {
+ shouldFailWithMessages '''
+ @groovy.transform.TupleConstructor(defaults=false)
class C<T> {
T p
}
class D {
- public String f = 'D#f'
}
- boolean b = false
- C<D> cd = b ? new C<>(new D()) : (b ? new C<>((D) null) : new C<>(new D()))
- assert cd.p.f.toLowerCase() == 'd#f'
- '''
+ void m(int i, C<D>... zeroOrMore) {
+ D d = zeroOrMore[0].p
+ }
+ m(0, new C<>(1))
+ ''',
+ 'Cannot call', 'm(int, C<D>[]) with arguments [int, C<java.lang.Integer>]'
+ }
+ // GROOVY-9970
+ void testDiamondInferrenceFromConstructor13() {
assertScript '''
- @groovy.transform.TupleConstructor
- class C {
- List<D> list
+ @groovy.transform.TupleConstructor(defaults=false)
+ class A<T extends B> {
+ T p
}
- class D {
+ class B {
}
- List test(C... array) {
- // old code used "List<D> many" as target for guts of closure
- List<D> many = array.collectMany { it.list ?: [] }
+ class C<T extends Number> {
+ void test(T n) {
+ A<B> x = new A<>(new B())
+ def closure = { ->
+ A<B> y = new A<>(new B())
+ }
+ closure.call()
+ }
}
- def result = test(new C(), new C(list:[new D()]))
- assert result.size() == 1
+ new C<Long>().test(42L)
'''
}
// GROOVY-9983
- void testDiamondInferrenceFromConstructor11() {
+ void testDiamondInferrenceFromConstructor14() {
String types = '''
@groovy.transform.TupleConstructor(defaults=false)
class A<T> {
@@ -480,6 +1016,216 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'Cannot call C#m(A<B>) with arguments [A<? extends java.lang.Object>]'*/
}
+ @NotYetImplemented // GROOVY-10114
+ void testDiamondInferrenceFromConstructor14a() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class A<T> {
+ T p
+ }
+ class B {
+ Character m() {
+ (Character) '!'
+ }
+ }
+ (false ? new A<B>(new B()) : new A<>(new B())).p.m()
+ (false ? new A< >(new B()) : new A<>(new B())).p.m()
+ def a = (true ? new A<>(new B()) : new A<>(new B()))
+ assert a.p.m() == (char)'!'
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-9995
+ void testDiamondInferrenceFromConstructor15() {
+ [
+ ['Closure<A<Long>>', 'java.util.concurrent.Callable<A<Long>>'],
+ ['new A<>(42L)', 'return new A<>(42L)']
+ ].combinations { functionalType, returnStmt ->
+ assertScript """
+ @groovy.transform.TupleConstructor(defaults=false)
+ class A<T extends Number> {
+ T p
+ }
+ $functionalType callable = { ->
+ $returnStmt
+ }
+ Long n = callable.call().p
+ assert n == 42L
+ """
+ }
+ }
+
+ // GROOVY-10283
+ void testDiamondInferrenceFromConstructor16() {
+ assertScript '''
+ class A<T1, T2> {
+ }
+ class B<T1 extends Number, T2 extends A<C, ? extends T1>> {
+ T2 t
+ B(T2 t) {
+ this.t = t
+ }
+ }
+ class C {
+ }
+
+ new B<Integer,A<C,Integer>>(new A<>())
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10291
+ void testDiamondInferrenceFromConstructor17() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class A<X> {
+ X x
+ }
+ class B<Y> {
+ def m(Y y) { null }
+ def test() {
+ def c = { Y yy -> null }
+
+ Y y = null
+ m(new A<>(y).x) // works
+ c(new A<>(y).x) // fails
+ }
+ }
+ new B().test()
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10228
+ void testDiamondInferrenceFromConstructor18() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<T> {
+ T p
+ }
+ def m(Number n) {
+ 'works'
+ }
+ def x = 12345
+ x = m(new C<>(x).getP()) // Cannot find matching method
+ assert x == 'works'
+ '''
+ }
+
+ // GROOVY-10323
+ void testDiamondInferrenceFromConstructor19() {
+ assertScript '''
+ class C<T> {
+ }
+ def <T,T> T m(C<T> c) {
+ }
+ Number n = m(new C<>())
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10324
+ void testDiamondInferrenceFromConstructor20() {
+ assertScript '''
+ class C<T> {
+ }
+ def <X> X m(C<X> c) {
+ }
+ List<String> x = m(new C<>())
+ '''
+ }
+
+ // GROOVY-10310
+ void testDiamondInferrenceFromConstructor21() {
+ assertScript '''
+ @groovy.transform.TupleConstructor
+ class A<T> {
+ T f
+ }
+ class B<T> {
+ }
+ def <T> A<T> m(T t, B<? extends T> b_of_t) {
+ new A<>(t)
+ }
+ def x = 'x'
+ m(x, new B<>()) // Cannot call m(T,B<? extends T>) with arguments...
+ '''
+ }
+
+ // GROOVY-10344
+ void testDiamondInferrenceFromConstructor22() {
+ assertScript '''
+ class C<X,Y> {
+ }
+ def <T extends C<? extends Number, ? extends Number>> T m(T t) {
+ return t
+ }
+ def x = m(new C<>())
+ assert x instanceof C
+ '''
+ }
+
+ @NotYetImplemented // GROOVY-10230
+ void testDiamondInferrenceFromConstructor23() {
+ assertScript '''
+ class A {
+ def <T extends C<Number,Number>> T m(T t) {
+ return t
+ }
+ }
+ class B extends A {
+ @Override
+ def <T extends C<Number,Number>> T m(T t) {
+ T x = null; super.m(true ? t : x)
+ }
+ }
+ class C<X,Y> {
+ }
+ def x = new B().m(new C<>())
+ assert x instanceof C
+ '''
+ }
+
+ // GROOVY-10351
+ void testDiamondInferrenceFromConstructor24() {
+ assertScript '''
+ class C<T> {
+ C(T one, D<T,? extends T> two) {
+ }
+ }
+ class D<U,V> {
+ }
+ D<Integer,? extends Integer> d_of_i_and_i = null
+ C<Integer> c_of_i = new C<>(1,d_of_i_and_i) // 3 witnesses for T
+ '''
+ }
+
+ // GROOVY-10368
+ void testDiamondInferrenceFromConstructor25() {
+ ['T', 'T extends Number', 'T extends Object'].each {
+ assertScript """
+ class C<$it> {
+ C(p) {
+ }
+ }
+ void m(C<Integer> c) {
+ }
+ m(new C<>(null)) // Cannot call m(C<Integer>) with arguments [C<# extends Number>]
+ """
+ }
+ }
+
+ @NotYetImplemented // GROOVY-10367
+ void testDiamondInferrenceFromConstructor26() {
+ assertScript '''
+ @groovy.transform.TupleConstructor(defaults=false)
+ class C<X, Y extends X> { // works without Y
+ X x
+ }
+ def <Z extends Number> void test(Z z) {
+ z = new C<>(z).x // Cannot assign value of type Object to variable of type Z
+ }
+ test(null)
+ '''
+ }
+
// GROOVY-10280
void testTypeArgumentPropagation() {
assertScript '''
@@ -532,13 +1278,15 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testLinkedListWithListArgumentAndWrongElementTypes() {
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.List <java.lang.Integer>]'
+ ''',
+ 'Cannot call java.util.LinkedList <String>#<init>(java.util.Collection <? extends java.lang.String>) with arguments [java.util.List <java.lang.Integer>]'
}
void testCompatibleGenericAssignmentWithInference() {
shouldFailWithMessages '''
List<String> elements = ['a','b', 1]
- ''', 'Incompatible generic argument types. Cannot assign java.util.List <java.io.Serializable> to: java.util.List <String>'
+ ''',
+ 'Incompatible generic argument types. Cannot assign java.util.List <java.io.Serializable> to: java.util.List <String>'
}
void testGenericAssignmentWithSubClass() {
@@ -550,7 +1298,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testGenericAssignmentWithSubClassAndWrongGenericType() {
shouldFailWithMessages '''
List<Integer> list = new groovy.transform.stc.GenericsSTCTest.MyList()
- ''', 'Incompatible generic argument types'
+ ''',
+ 'Incompatible generic argument types'
}
void testAddShouldBeAllowedOnUncheckedGenerics() {
@@ -566,7 +1315,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testAssignmentShouldFailBecauseOfLowerBound() {
shouldFailWithMessages '''
List<? super Number> list = ['string']
- ''', 'Number'
+ ''',
+ 'Number'
}
// GROOVY-9914, GROOVY-10036
@@ -653,15 +1403,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
''', 'Cannot find matching method FooWithGenerics#say(java.lang.Object)'
}
- void testVoidReturnTypeInferrence() {
- assertScript '''
- Object m() {
- def s = '1234'
- println 'Hello'
- }
- '''
- }
-
// GROOVY-5237
void testGenericTypeArgumentAsField() {
assertScript '''
@@ -1139,8 +1880,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-5528
void testAssignmentToInterfaceFromUserClassWithGenerics() {
- assertScript '''class UserList<T> extends LinkedList<T> {}
- List<String> list = new UserList<String>()
+ assertScript '''
+ class UserList<T> extends LinkedList<T> {}
+ List<String> list = new UserList<String>()
'''
}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/GenericsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/GenericsStaticCompileTest.groovy
index ed1fb12..3a667c5 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/GenericsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/GenericsStaticCompileTest.groovy
@@ -18,12 +18,16 @@
*/
package org.codehaus.groovy.classgen.asm.sc
+import groovy.test.NotYetImplemented
import groovy.transform.stc.GenericsSTCTest
/**
- * Unit tests for static type checking : generics.
+ * Unit tests for static compilation : generics.
*/
class GenericsStaticCompileTest extends GenericsSTCTest implements StaticCompilationTestSupport {
+ @Override @NotYetImplemented // GROOVY-8409
+ void testReturnTypeInferenceWithMethodGenerics14() {
+ super.testReturnTypeInferenceWithMethodGenerics14()
+ }
}
-