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/11/18 16:58:27 UTC
[groovy] branch GROOVY_3_0_X updated: GROOVY-10813: `parameterizeSAM`: no type parameters from method context
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 321cfc6339 GROOVY-10813: `parameterizeSAM`: no type parameters from method context
321cfc6339 is described below
commit 321cfc6339acead488ded3e5800c65291f1068ba
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Nov 18 09:26:57 2022 -0600
GROOVY-10813: `parameterizeSAM`: no type parameters from method context
---
.../codehaus/groovy/ast/tools/GenericsUtils.java | 91 ++--
src/test/groovy/bugs/Groovy7204.groovy | 559 ++++++++++++++++++++
src/test/groovy/bugs/Groovy7204Bug.groovy | 579 ---------------------
src/test/groovy/bugs/Groovy8059Bug.groovy | 49 --
src/test/groovy/transform/stc/LambdaTest.groovy | 25 +
.../groovy/ast/tools/GenericsUtilsTest.groovy | 145 ++++--
6 files changed, 740 insertions(+), 708 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 35390dc31b..c71053c699 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -710,6 +710,17 @@ public class GenericsUtils {
private static final boolean PARAMETERIZED_TYPE_CACHE_ENABLED = Boolean.parseBoolean(getSystemPropertySafe("groovy.enable.parameterized.type.cache", "true"));
+ private static final EvictableCache<ParameterizedTypeCacheKey, SoftReference<ClassNode>> PARAMETERIZED_TYPE_CACHE = new ConcurrentSoftCache<>(64);
+
+ /**
+ * Clears the parameterized type cache.
+ * <p>
+ * It is useful to IDE as the type being compiled are continuously being edited/altered, see GROOVY-8675
+ */
+ public static void clearParameterizedTypeCache() {
+ PARAMETERIZED_TYPE_CACHE.clearAll();
+ }
+
/**
* Convenience method for {@link #findParameterizedTypeFromCache(ClassNode, ClassNode, boolean)}
* when the {@code tryToFindExactType} boolean is {@code false}.
@@ -732,7 +743,7 @@ public class GenericsUtils {
new ParameterizedTypeCacheKey(genericsClass, actualType),
key -> new SoftReference<>(findParameterizedType(key.getGenericsClass(), key.getActualType(), tryToFindExactType)));
- return sr == null ? null : sr.get();
+ return sr != null ? sr.get() : null;
}
/**
@@ -763,41 +774,34 @@ public class GenericsUtils {
ClassNode type;
while ((type = todo.poll()) != null) {
- if (type.equals(genericsClass)) {
- return type;
- }
if (done.add(type)) {
- boolean parameterized = (type.getGenericsTypes() != null);
- for (ClassNode cn : type.getInterfaces()) {
- if (parameterized)
- cn = parameterizeType(type, cn);
- todo.add(cn);
- }
- if (!actualType.isInterface()) {
+ if (!type.isInterface()) {
ClassNode cn = type.getUnresolvedSuperClass();
if (cn != null && cn.redirect() != ClassHelper.OBJECT_TYPE) {
- if (parameterized)
+ if (hasUnresolvedGenerics(cn)) {
cn = parameterizeType(type, cn);
+ }
+ if (cn.equals(genericsClass)) {
+ return cn;
+ }
todo.add(cn);
}
}
+ for (ClassNode cn : type.getInterfaces()) {
+ if (hasUnresolvedGenerics(cn)) {
+ cn = parameterizeType(type, cn);
+ }
+ if (cn.equals(genericsClass)) {
+ return cn;
+ }
+ todo.add(cn);
+ }
}
}
return null;
}
- private static final EvictableCache<ParameterizedTypeCacheKey, SoftReference<ClassNode>> PARAMETERIZED_TYPE_CACHE = new ConcurrentSoftCache<>(64);
-
- /**
- * Clears the parameterized type cache.
- * <p>
- * It is useful to IDE as the type being compiled are continuously being edited/altered, see GROOVY-8675
- */
- public static void clearParameterizedTypeCache() {
- PARAMETERIZED_TYPE_CACHE.clearAll();
- }
-
/**
* map declaring generics type to actual generics type, e.g. GROOVY-7204:
* declaring generics types: T, S extends Serializable
@@ -812,7 +816,7 @@ public class GenericsUtils {
* so we need actual types: T: String, S: Long
*/
public static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMap(final ClassNode declaringClass, final ClassNode actualReceiver) {
- return doMakeDeclaringAndActualGenericsTypeMap(declaringClass, actualReceiver, false);
+ return correlateTypeParametersAndTypeArguments(declaringClass, actualReceiver, false);
}
/**
@@ -827,25 +831,42 @@ public class GenericsUtils {
* @since 3.0.0
*/
public static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMapOfExactType(final ClassNode declaringClass, final ClassNode actualReceiver) {
- return doMakeDeclaringAndActualGenericsTypeMap(declaringClass, actualReceiver, true);
+ return correlateTypeParametersAndTypeArguments(declaringClass, actualReceiver, true);
}
- private static Map<GenericsType, GenericsType> doMakeDeclaringAndActualGenericsTypeMap(final ClassNode declaringClass, final ClassNode actualReceiver, final boolean tryToFindExactType) {
- Map<GenericsType, GenericsType> map = Collections.emptyMap();
+ private static Map<GenericsType, GenericsType> correlateTypeParametersAndTypeArguments(final ClassNode declaringClass, final ClassNode actualReceiver, final boolean tryToFindExactType) {
ClassNode parameterizedType = findParameterizedTypeFromCache(declaringClass, actualReceiver, tryToFindExactType);
if (parameterizedType != null && parameterizedType.isRedirectNode() && !parameterizedType.isGenericsPlaceHolder()) { // GROOVY-10166
// declaringClass may be "List<T> -> List<E>" and parameterizedType may be "List<String> -> List<E>" or "List<> -> List<E>"
- GenericsType[] targetGenericsTypes = parameterizedType.redirect().getGenericsTypes();
- if (targetGenericsTypes != null) {
- GenericsType[] sourceGenericsTypes = parameterizedType.getGenericsTypes();
- if (sourceGenericsTypes == null) sourceGenericsTypes = EMPTY_GENERICS_ARRAY;
- map = new LinkedHashMap<>();
- for (int i = 0, m = sourceGenericsTypes.length, n = targetGenericsTypes.length; i < n; i += 1) {
- map.put(targetGenericsTypes[i], i < m ? sourceGenericsTypes[i] : targetGenericsTypes[i]);
+ final GenericsType[] typeParameters = parameterizedType.redirect().getGenericsTypes();
+ if (typeParameters != null) {
+ final GenericsType[] typeArguments = parameterizedType.getGenericsTypes();
+ final int m = typeArguments == null ? 0 : typeArguments.length;
+ final int n = typeParameters.length;
+
+ Map<GenericsType, GenericsType> map = new LinkedHashMap<>();
+ for (int i = 0; i < n; i += 1) {
+ map.put(typeParameters[i], i < m ? typeArguments[i] : erasure(typeParameters[i]));
}
+ return map;
}
}
- return map;
+ return Collections.emptyMap();
+ }
+
+ /**
+ * @see org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport#extractType(GenericsType)
+ */
+ private static GenericsType erasure(GenericsType gt) {
+ ClassNode cn = gt.getType().redirect(); // discard the placeholder
+
+ if (gt.getType().getGenericsTypes() != null)
+ gt = gt.getType().getGenericsTypes()[0];
+
+ if (gt.getUpperBounds() != null)
+ cn = gt.getUpperBounds()[0]; // TODO: if length > 1 then union type?
+
+ return cn.asGenericsType();
}
/**
diff --git a/src/test/groovy/bugs/Groovy7204.groovy b/src/test/groovy/bugs/Groovy7204.groovy
new file mode 100644
index 0000000000..41e7b2fb09
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy7204.groovy
@@ -0,0 +1,559 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.bugs
+
+import groovy.test.NotYetImplemented
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy7204 {
+
+ @Test
+ void testTypeChecked1() {
+ assertScript '''import groovy.transform.*
+ @TypeChecked
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @TypeChecked
+ interface CrudRepository<T, S extends Serializable> {
+ void delete(T arg)
+ void delete(S arg)
+ }
+
+ @TypeChecked
+ interface MyRepository extends CrudRepository<String, Long> {
+ }
+
+ @TypeChecked
+ class MyRepositoryImpl implements MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @Test
+ void testTypeChecked2() {
+ assertScript '''import groovy.transform.*
+ @TypeChecked
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @TypeChecked
+ abstract class CrudRepository<T, S extends Serializable> {
+ abstract void delete(T arg)
+ abstract void delete(S arg)
+ }
+
+ @TypeChecked
+ abstract class MyRepository extends CrudRepository<String, Long> {
+ }
+
+ @TypeChecked
+ class MyRepositoryImpl extends MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @Test
+ void testTypeChecked3() {
+ assertScript '''import groovy.transform.*
+ @TypeChecked
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @TypeChecked
+ interface CrudRepository<T, S extends Serializable> {
+ void delete(T arg)
+ void delete(S arg)
+ }
+
+ @TypeChecked
+ interface MyRepository2 extends CrudRepository<String, Long> {
+ }
+
+ @TypeChecked
+ interface MyRepository extends MyRepository2 {
+ }
+
+ @TypeChecked
+ class MyRepositoryImpl implements MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @Test
+ void testTypeChecked4() {
+ assertScript '''import groovy.transform.*
+ @TypeChecked
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @TypeChecked
+ abstract class CrudRepository<T, S extends Serializable> {
+ abstract void delete(T arg)
+ abstract void delete(S arg)
+ }
+
+ @TypeChecked
+ abstract class MyRepository2 extends CrudRepository<String, Long> {
+ }
+
+ @TypeChecked
+ abstract class MyRepository extends MyRepository2 {
+ }
+
+ @TypeChecked
+ class MyRepositoryImpl extends MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @Test
+ void testTypeChecked5() {
+ assertScript '''import groovy.transform.*
+ @TypeChecked
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @TypeChecked
+ interface CrudRepository<T, S extends Serializable> {
+ void delete(T arg)
+ void delete(S arg)
+ }
+
+ @TypeChecked
+ abstract class MyRepository2 implements CrudRepository<String, Long> {
+ }
+
+ @TypeChecked
+ abstract class MyRepository extends MyRepository2 {
+ }
+
+ @TypeChecked
+ class MyRepositoryImpl extends MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @NotYetImplemented @Test
+ void testTypeChecked6() {
+ assertScript '''import groovy.transform.*
+ class Repository<T, S extends Serializable> {
+ void delete(T arg) { assert true }
+ void delete(S arg) { assert false: 'wrong method invoked' }
+ }
+
+ @TypeChecked
+ def test() {
+ Repository<String, Long> r = new Repository<String, Long>()
+ r.delete('foo')
+ }
+
+ test()
+ '''
+ }
+
+ //
+
+ @Test
+ void testCompileStatic1() {
+ assertScript '''import groovy.transform.*
+ @CompileStatic
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @CompileStatic
+ interface CrudRepository<T, S extends Serializable> {
+ void delete(T arg)
+ void delete(S arg)
+ }
+
+ @CompileStatic
+ interface MyRepository extends CrudRepository<String, Long> {
+ }
+
+ @CompileStatic
+ class MyRepositoryImpl implements MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @Test
+ void testCompileStatic2() {
+ assertScript '''import groovy.transform.*
+ @CompileStatic
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @CompileStatic
+ abstract class CrudRepository<T, S extends Serializable> {
+ abstract void delete(T arg)
+ abstract void delete(S arg)
+ }
+
+ @CompileStatic
+ abstract class MyRepository extends CrudRepository<String, Long> {
+ }
+
+ @CompileStatic
+ class MyRepositoryImpl extends MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @Test
+ void testCompileStatic3() {
+ assertScript '''import groovy.transform.*
+ @CompileStatic
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @CompileStatic
+ interface CrudRepository<T, S extends Serializable> {
+ void delete(T arg)
+ void delete(S arg)
+ }
+
+ @CompileStatic
+ interface MyRepository2 extends CrudRepository<String, Long> {
+ }
+
+ @CompileStatic
+ interface MyRepository extends MyRepository2 {
+ }
+
+ @CompileStatic
+ class MyRepositoryImpl implements MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @Test
+ void testCompileStatic4() {
+ assertScript '''import groovy.transform.*
+ @CompileStatic
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @CompileStatic
+ abstract class CrudRepository<T, S extends Serializable> {
+ abstract void delete(T arg)
+ abstract void delete(S arg)
+ }
+
+ @CompileStatic
+ abstract class MyRepository2 extends CrudRepository<String, Long> {
+ }
+
+ @CompileStatic
+ abstract class MyRepository extends MyRepository2 {
+ }
+
+ @CompileStatic
+ class MyRepositoryImpl extends MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @Test
+ void testCompileStatic5() {
+ assertScript '''import groovy.transform.*
+ @CompileStatic
+ public class MyClass {
+ static MyRepository factory() {
+ return new MyRepositoryImpl()
+ }
+
+ static void main(String[] args) {
+ MyRepository r = factory()
+ r.delete('foo')
+ }
+ }
+
+ @CompileStatic
+ interface CrudRepository<T, S extends Serializable> {
+ void delete(T arg)
+ void delete(S arg)
+ }
+
+ @CompileStatic
+ abstract class MyRepository2 implements CrudRepository<String, Long> {
+ }
+
+ @CompileStatic
+ abstract class MyRepository extends MyRepository2 {
+ }
+
+ @CompileStatic
+ class MyRepositoryImpl extends MyRepository {
+ @Override
+ public void delete(String arg) {
+ assert true
+ }
+
+ @Override
+ public void delete(Long arg) {
+ assert false: 'wrong method invoked'
+ }
+ }
+ '''
+ }
+
+ @Test
+ void testCompileStatic6() {
+ assertScript '''import groovy.transform.*
+ class Repository<T, S extends Serializable> {
+ void delete(T arg) { assert true }
+ void delete(S arg) { assert false: 'wrong method invoked' }
+ }
+
+ @CompileStatic
+ def test() {
+ Repository<String, Long> r = new Repository<String, Long>()
+ r.delete('foo')
+ }
+
+ test()
+ '''
+ }
+
+ @Test // GROOVY-8059
+ void testCompileStatic7() {
+ assertScript '''import groovy.transform.*
+ abstract class A<K extends Serializable, V> {
+ void delete(K key) {}
+ void delete(V val) {}
+ }
+ class C extends A<String, Integer> {
+ }
+
+ @CompileStatic
+ class Test {
+ Test() {
+ def obj = new C()
+ obj.delete(Integer.valueOf(1))
+ }
+ }
+
+ new Test()
+ '''
+ }
+
+ @Test
+ void testCompileStatic8() {
+ assertScript '''import groovy.transform.*
+ class Trie<T> {
+ }
+
+ @CompileStatic
+ class Base<T> {
+ protected List<Trie<T>> list = []
+ Base() {
+ list.add(new Trie<String>()) // should fail!!
+ }
+ }
+
+ @CompileStatic
+ class Test extends Base<String> {
+ Trie<String> getFirstElement() {
+ list.get(0)
+ }
+ }
+
+ assert new Test().firstElement instanceof Trie
+ '''
+ }
+
+ @Test
+ void testCompileStatic9() {
+ assertScript '''import groovy.transform.*
+ class Trie<T> {
+ }
+
+ class Base<T> extends ArrayList<Trie<T>> {
+ }
+
+ @CompileStatic
+ class Test extends Base<String> {
+ Test() {
+ add(new Trie<String>())
+ }
+ Trie<String> getFirstElement() {
+ get(0)
+ }
+ }
+
+ assert new Test().firstElement instanceof Trie
+ '''
+ }
+}
diff --git a/src/test/groovy/bugs/Groovy7204Bug.groovy b/src/test/groovy/bugs/Groovy7204Bug.groovy
deleted file mode 100644
index 5c5f20ec92..0000000000
--- a/src/test/groovy/bugs/Groovy7204Bug.groovy
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.bugs
-
-import groovy.test.GroovyTestCase
-
-class Groovy7204Bug extends GroovyTestCase {
- void testTypeChecked1() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @TypeChecked
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @TypeChecked
- interface CrudRepository<T, S extends Serializable> {
- void delete(T arg);
- void delete(S arg);
- }
-
- @TypeChecked
- interface MyRepository extends CrudRepository<String, Long> {
- }
-
- @TypeChecked
- class MyRepositoryImpl implements MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
- void testTypeChecked2() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @TypeChecked
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @TypeChecked
- abstract class CrudRepository<T, S extends Serializable> {
- abstract void delete(T arg);
- abstract void delete(S arg);
- }
-
- @TypeChecked
- abstract class MyRepository extends CrudRepository<String, Long> {
- }
-
- @TypeChecked
- class MyRepositoryImpl extends MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
- void testTypeChecked3() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @TypeChecked
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @TypeChecked
- interface CrudRepository<T, S extends Serializable> {
- void delete(T arg);
- void delete(S arg);
- }
-
- @TypeChecked
- interface MyRepository2 extends CrudRepository<String, Long> {
- }
-
- @TypeChecked
- interface MyRepository extends MyRepository2 {
- }
-
- @TypeChecked
- class MyRepositoryImpl implements MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
- void testTypeChecked4() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @TypeChecked
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @TypeChecked
- abstract class CrudRepository<T, S extends Serializable> {
- abstract void delete(T arg);
- abstract void delete(S arg);
- }
-
- @TypeChecked
- abstract class MyRepository2 extends CrudRepository<String, Long> {
- }
-
- @TypeChecked
- abstract class MyRepository extends MyRepository2 {
- }
-
- @TypeChecked
- class MyRepositoryImpl extends MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
- void testTypeChecked5() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @TypeChecked
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @TypeChecked
- interface CrudRepository<T, S extends Serializable> {
- void delete(T arg);
- void delete(S arg);
- }
-
- @TypeChecked
- abstract class MyRepository2 implements CrudRepository<String, Long> {
- }
-
- @TypeChecked
- abstract class MyRepository extends MyRepository2 {
- }
-
- @TypeChecked
- class MyRepositoryImpl extends MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
-
- void testCompileStatic1() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @CompileStatic
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @CompileStatic
- interface CrudRepository<T, S extends Serializable> {
- void delete(T arg);
- void delete(S arg);
- }
-
- @CompileStatic
- interface MyRepository extends CrudRepository<String, Long> {
- }
-
- @CompileStatic
- class MyRepositoryImpl implements MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
- void testCompileStatic2() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @CompileStatic
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @CompileStatic
- abstract class CrudRepository<T, S extends Serializable> {
- abstract void delete(T arg);
- abstract void delete(S arg);
- }
-
- @CompileStatic
- abstract class MyRepository extends CrudRepository<String, Long> {
- }
-
- @CompileStatic
- class MyRepositoryImpl extends MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
- void testCompileStatic3() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @CompileStatic
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @CompileStatic
- interface CrudRepository<T, S extends Serializable> {
- void delete(T arg);
- void delete(S arg);
- }
-
- @CompileStatic
- interface MyRepository2 extends CrudRepository<String, Long> {
- }
-
- @CompileStatic
- interface MyRepository extends MyRepository2 {
- }
-
- @CompileStatic
- class MyRepositoryImpl implements MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
- void testCompileStatic4() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @CompileStatic
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @CompileStatic
- abstract class CrudRepository<T, S extends Serializable> {
- abstract void delete(T arg);
- abstract void delete(S arg);
- }
-
- @CompileStatic
- abstract class MyRepository2 extends CrudRepository<String, Long> {
- }
-
- @CompileStatic
- abstract class MyRepository extends MyRepository2 {
- }
-
- @CompileStatic
- class MyRepositoryImpl extends MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
- void testCompileStatic5() {
- assertScript '''
- import java.io.Serializable;
-
- import groovy.transform.CompileStatic;
- import groovy.transform.TypeChecked;
-
- @CompileStatic
- public class MyClass {
- static MyRepository factory() {
- return new MyRepositoryImpl()
- }
-
- static void main(String[] args) {
- MyRepository r = factory()
- r.delete('foo')
- }
- }
-
- @CompileStatic
- interface CrudRepository<T, S extends Serializable> {
- void delete(T arg);
- void delete(S arg);
- }
-
- @CompileStatic
- abstract class MyRepository2 implements CrudRepository<String, Long> {
- }
-
- @CompileStatic
- abstract class MyRepository extends MyRepository2 {
- }
-
- @CompileStatic
- class MyRepositoryImpl extends MyRepository {
- @Override
- public void delete(String arg) {
- System.out.println("String");
- assert true
- }
-
- @Override
- public void delete(Long arg) {
- System.out.println("Long");
- assert false: 'wrong method invoked'
- }
- }
- '''
- }
-
- void testCompileStatic6() {
- assertScript '''
- import java.io.Serializable;
- import groovy.transform.CompileStatic;
-
- @CompileStatic
- class Repository<T, S extends Serializable> {
- void delete(T arg) { assert true }
- void delete(S arg) { assert false: 'wrong method invoked' }
- }
-
- @CompileStatic
- def test() {
- Repository<String, Long> r = new Repository<String, Long>()
- r.delete('foo')
- }
-
- test()
- '''
- }
-
- void testCompileStatic7() {
- assertScript '''
- @groovy.transform.CompileStatic
- class Trie<T> {}
-
- @groovy.transform.CompileStatic
- class Base<T> {
- protected List<Trie<T>> list
-
- Base() {
- list = new ArrayList<Trie<T>>()
- list.add(new Trie<String>())
- }
- }
-
- @groovy.transform.CompileStatic
- class Derived extends Base<String> {
- Trie<String> getFirstElement() {
- list.get(0)
- }
- }
-
- assert new Derived().getFirstElement() instanceof Trie
- '''
- }
-
- void testCompileStatic8() {
- assertScript '''
- @groovy.transform.CompileStatic
- class Trie<T> {}
-
- @groovy.transform.CompileStatic
- class Base<T> extends ArrayList<Trie<T>> {
-
- Base() {
- this.add(new Trie<String>())
- }
- }
-
- @groovy.transform.CompileStatic
- class Derived extends Base<String> {
- Trie<String> getFirstElement() {
- this.get(0)
- }
- }
-
- assert new Derived().getFirstElement() instanceof Trie
- '''
- }
-}
diff --git a/src/test/groovy/bugs/Groovy8059Bug.groovy b/src/test/groovy/bugs/Groovy8059Bug.groovy
deleted file mode 100644
index 85d77fd676..0000000000
--- a/src/test/groovy/bugs/Groovy8059Bug.groovy
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-
-
-package groovy.bugs
-
-import groovy.test.GroovyTestCase
-
-class Groovy8059Bug extends GroovyTestCase {
- void test1() {
- assertScript '''
- @groovy.transform.CompileStatic
- class Base<K extends Serializable, V> {
- void delete(K key) {}
- void delete(V value) {}
- }
-
- @groovy.transform.CompileStatic
- class Foo extends Base<String, Integer> {}
-
- @groovy.transform.CompileStatic
- public class Class1 {
- Class1() {
- Foo foo = new Foo()
- foo.delete(Integer.valueOf(1))
- }
- }
- new Class1()
- '''
- }
-}
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index f01c511a0e..31d531f9d1 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -799,6 +799,31 @@ final class LambdaTest {
}
}
+ @Test // GROOVY-10813
+ void testConsumer11() {
+ ['CompileStatic', 'TypeChecked'].each { xform ->
+ assertScript """
+ @groovy.transform.${xform}
+ void test() {
+ java.util.function.Consumer c = x -> print(x)
+ c.accept('works')
+ }
+ test()
+ """
+ assertScript """
+ interface I<T extends CharSequence> {
+ void accept(T t)
+ }
+ @groovy.transform.${xform}
+ void test() {
+ I i = x -> print(x)
+ i.accept('works')
+ }
+ test()
+ """
+ }
+ }
+
@Test
void testFunctionalInterface1() {
assertScript '''
diff --git a/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
index 1b30f71817..ef2893362d 100644
--- a/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
@@ -48,12 +48,12 @@ final class GenericsUtilsTest {
ClassNode source = findClassNode('Derived', classNodeList)
ClassNode result = GenericsUtils.findParameterizedType(target, source)
- assert 'Base' == result.name
+ assert result.name == 'Base'
assert result.isUsingGenerics()
- assert 2 == result.genericsTypes.length
- assert 'java.lang.String' == result.genericsTypes[0].type.name
- assert 'java.util.List' == result.genericsTypes[1].type.name
- assert target === result.redirect()
+ assert result.genericsTypes.length == 2
+ assert result.genericsTypes[0].type.name == 'java.lang.String'
+ assert result.genericsTypes[1].type.name == 'java.util.List'
+ assert result.redirect() === target
}
@Test
@@ -67,12 +67,12 @@ final class GenericsUtilsTest {
ClassNode source = findClassNode('Derived', classNodeList)
ClassNode result = GenericsUtils.findParameterizedType(target, source)
- assert 'Base' == result.name
+ assert result.name == 'Base'
assert result.isUsingGenerics()
- assert 2 == result.genericsTypes.length
- assert 'java.lang.String' == result.genericsTypes[0].type.name
- assert 'java.util.List' == result.genericsTypes[1].type.name
- assert target === result.redirect()
+ assert result.genericsTypes.length == 2
+ assert result.genericsTypes[0].type.name == 'java.lang.String'
+ assert result.genericsTypes[1].type.name == 'java.util.List'
+ assert result.redirect() === target
}
@Test
@@ -87,12 +87,12 @@ final class GenericsUtilsTest {
ClassNode source = findClassNode('Derived', classNodeList)
ClassNode result = GenericsUtils.findParameterizedType(target, source)
- assert 'Base' == result.name
+ assert result.name == 'Base'
assert result.isUsingGenerics()
- assert 2 == result.genericsTypes.length
- assert 'java.lang.String' == result.genericsTypes[0].type.name
- assert 'java.util.List' == result.genericsTypes[1].type.name
- assert target === result.redirect()
+ assert result.genericsTypes.length == 2
+ assert result.genericsTypes[0].type.name == 'java.lang.String'
+ assert result.genericsTypes[1].type.name == 'java.util.List'
+ assert result.redirect() === target
}
@Test
@@ -106,12 +106,12 @@ final class GenericsUtilsTest {
ClassNode source = findClassNode('Derived', classNodeList)
ClassNode result = GenericsUtils.findParameterizedType(target, source)
- assert 'Base' == result.name
+ assert result.name == 'Base'
assert result.isUsingGenerics()
- assert 2 == result.genericsTypes.length
- assert 'java.lang.String' == result.genericsTypes[0].type.name
- assert 'java.util.List' == result.genericsTypes[1].type.name
- assert target === result.redirect()
+ assert result.genericsTypes.length == 2
+ assert result.genericsTypes[0].type.name == 'java.lang.String'
+ assert result.genericsTypes[1].type.name == 'java.util.List'
+ assert result.redirect() === target
}
@Test
@@ -126,12 +126,12 @@ final class GenericsUtilsTest {
ClassNode source = findClassNode('Derived', classNodeList)
ClassNode result = GenericsUtils.findParameterizedType(target, source)
- assert 'Base' == result.name
+ assert result.name == 'Base'
assert result.isUsingGenerics()
- assert 2 == result.genericsTypes.length
- assert 'java.lang.String' == result.genericsTypes[0].type.name
- assert 'java.util.List' == result.genericsTypes[1].type.name
- assert target === result.redirect()
+ assert result.genericsTypes.length == 2
+ assert result.genericsTypes[0].type.name == 'java.lang.String'
+ assert result.genericsTypes[1].type.name == 'java.util.List'
+ assert result.redirect() === target
}
@Test
@@ -147,12 +147,12 @@ final class GenericsUtilsTest {
ClassNode source = findClassNode('Derived', classNodeList)
ClassNode result = GenericsUtils.findParameterizedType(target, source)
- assert 'Base' == result.name
+ assert result.name == 'Base'
assert result.isUsingGenerics()
- assert 2 == result.genericsTypes.length
- assert 'java.lang.String' == result.genericsTypes[0].type.name
- assert 'java.util.List' == result.genericsTypes[1].type.name
- assert target === result.redirect()
+ assert result.genericsTypes.length == 2
+ assert result.genericsTypes[0].type.name == 'java.lang.String'
+ assert result.genericsTypes[1].type.name == 'java.util.List'
+ assert result.redirect() === target
}
@Test
@@ -169,12 +169,12 @@ final class GenericsUtilsTest {
ClassNode source = findClassNode('Derived', classNodeList)
ClassNode result = GenericsUtils.findParameterizedType(target, source)
- assert 'Base' == result.name
+ assert result.name == 'Base'
assert result.isUsingGenerics()
- assert 2 == result.genericsTypes.length
- assert 'java.lang.String' == result.genericsTypes[0].type.name
- assert 'java.util.List' == result.genericsTypes[1].type.name
- assert target === result.redirect()
+ assert result.genericsTypes.length == 2
+ assert result.genericsTypes[0].type.name == 'java.lang.String'
+ assert result.genericsTypes[1].type.name == 'java.util.List'
+ assert result.redirect() === target
}
@Test // GROOVY-9945
@@ -220,9 +220,9 @@ final class GenericsUtilsTest {
Map<GenericsType, GenericsType> m = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(target, source)
+ assert m.size() == 2
assert m.entrySet().find { it.key.name == 'T' }.value.type.name == 'java.lang.String'
assert m.entrySet().find { it.key.name == 'U' }.value.type.name == 'java.lang.Integer'
- assert m.size() == 2
}
@Test
@@ -237,14 +237,14 @@ final class GenericsUtilsTest {
Map<GenericsType, GenericsType> m = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(target, source)
+ assert m.size() == 3
assert m.entrySet().find { it.key.name == 'R' }.value.type.name == 'java.lang.Boolean'
assert m.entrySet().find { it.key.name == 'T' }.value.type.name == 'java.lang.Integer'
assert m.entrySet().find { it.key.name == 'U' }.value.type.name == 'java.lang.String'
- assert m.size() == 3
}
@Test
- void testParameterizeSAM() {
+ void testParameterizeSAM1() {
def classNodeList = compile '''
import java.util.function.*
interface T extends Function<String, Integer> {}
@@ -253,10 +253,10 @@ final class GenericsUtilsTest {
def typeInfo = GenericsUtils.parameterizeSAM(samType)
- assert 1 == typeInfo[0].length
- assert ClassHelper.STRING_TYPE == typeInfo[0][0]
+ assert typeInfo[0].length == 1
+ assert typeInfo[0][0] == ClassHelper.STRING_TYPE
- assert ClassHelper.Integer_TYPE == typeInfo[1]
+ assert typeInfo[1] == ClassHelper.Integer_TYPE
}
@Test
@@ -269,10 +269,65 @@ final class GenericsUtilsTest {
def typeInfo = GenericsUtils.parameterizeSAM(samType)
- assert 2 == typeInfo[0].length
- assert ClassHelper.Integer_TYPE == typeInfo[0][0]
- assert ClassHelper.Integer_TYPE == typeInfo[0][1]
+ assert typeInfo.v1.length == 2
+ assert typeInfo.v1[0] == ClassHelper.Integer_TYPE
+ assert typeInfo.v1[1] == ClassHelper.Integer_TYPE
+
+ assert typeInfo.v2 == ClassHelper.Integer_TYPE
+ }
+
+ @Test // GROOVY-10813
+ void testParameterizeSAMWithRawType() {
+ def classNodeList = compile '''
+ interface I extends java.util.function.BinaryOperator {
+ }
+ '''
+ ClassNode samType = findClassNode('I', classNodeList).interfaces.find { it.name == 'java.util.function.BinaryOperator' }
+
+ def typeInfo = GenericsUtils.parameterizeSAM(samType)
+
+ assert typeInfo.v1.length == 2
+ assert typeInfo.v1[0].toString(false) == 'java.lang.Object'
+ assert typeInfo.v1[1].toString(false) == 'java.lang.Object'
+
+ assert typeInfo.v2.toString(false) == 'java.lang.Object'
+ }
+
+ @Test
+ void testParameterizeSAMWithRawTypeWithUpperBound() {
+ def classNodeList = compile '''
+ interface I<T extends CharSequence> {
+ T apply(T input);
+ }
+ abstract class A implements I {
+ }
+ '''
+ ClassNode samType = findClassNode('A', classNodeList).interfaces.find { it.name == 'I' }
+
+ def typeInfo = GenericsUtils.parameterizeSAM(samType)
+
+ assert typeInfo.v1.length == 1
+ assert typeInfo.v1[0].toString(false) == 'java.lang.CharSequence'
+
+ assert typeInfo.v2.toString(false) == 'java.lang.CharSequence'
+ }
+
+ @Test
+ void testParameterizeSAMWithRawTypeWithUpperBounds() {
+ def classNodeList = compile '''
+ interface I<T extends CharSequence & Serializable> {
+ T apply(T input);
+ }
+ abstract class A implements I {
+ }
+ '''
+ ClassNode samType = findClassNode('A', classNodeList).interfaces.find { it.name == 'I' }
+
+ def typeInfo = GenericsUtils.parameterizeSAM(samType)
+
+ assert typeInfo.v1.length == 1
+ assert typeInfo.v1[0].toString(false) == 'java.lang.CharSequence'
- assert ClassHelper.Integer_TYPE == typeInfo[1]
+ assert typeInfo.v2.toString(false) == 'java.lang.CharSequence'
}
}