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 2024/01/12 20:42:56 UTC
(groovy) branch GROOVY_4_0_X updated: GROOVY-11276: STC: drop type args after applying generics connections
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
new c3f55d96cb GROOVY-11276: STC: drop type args after applying generics connections
c3f55d96cb is described below
commit c3f55d96cb23213a2d532a709c66471c5a021d15
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Jan 12 13:19:25 2024 -0600
GROOVY-11276: STC: drop type args after applying generics connections
GROOVY-5482, GROOVY-8609
---
.../codehaus/groovy/ast/tools/GenericsUtils.java | 3 +-
.../transform/stc/StaticTypeCheckingSupport.java | 83 +++++++++-------------
src/test/groovy/bugs/Groovy8609Bug.groovy | 6 +-
src/test/groovy/transform/stc/BugsSTCTest.groovy | 25 +++----
.../groovy/transform/stc/GenericsSTCTest.groovy | 45 +++++++-----
.../groovy/transform/stc/MethodCallsSTCTest.groovy | 2 +-
6 files changed, 75 insertions(+), 89 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 0192d3510d..c094dda188 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -303,8 +303,7 @@ public class GenericsUtils {
}
if (temp instanceof DecompiledClassNode // GROOVY-10461: check without resolving supers
? ((DecompiledClassNode) temp).isParameterized() : temp.isUsingGenerics()) {
- ClassNode result = ClassHelper.makeWithoutCaching(temp.getName());
- result.setRedirect(temp);
+ ClassNode result = temp.getPlainNodeReference();
result.setGenericsTypes(null);
result.setUsingGenerics(false);
while (dims > 0) { dims -= 1;
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index b875193285..63b986797f 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -60,7 +60,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@@ -1051,7 +1050,7 @@ public abstract class StaticTypeCheckingSupport {
Iterable<MethodNode> candidates = noCulling ? methods : removeCovariantsAndInterfaceEquivalents(methods, duckType);
for (MethodNode candidate : candidates) {
- MethodNode safeNode = candidate;
+ MethodNode safeNode = candidate;
ClassNode[] safeArgs = argumentTypes;
boolean isExtensionMethod = candidate instanceof ExtensionMethodNode;
if (isExtensionMethod) {
@@ -1062,35 +1061,11 @@ public abstract class StaticTypeCheckingSupport {
safeNode = ((ExtensionMethodNode) candidate).getExtensionMethodNode();
}
- /* TODO: corner case
- class B extends A {}
- Animal foo(A a) {}
- Person foo(B b) {}
-
- B b = new B()
- Person p = foo(b)
- */
-
ClassNode declaringClass = candidate.getDeclaringClass();
ClassNode actualReceiver = receiver != null ? receiver : declaringClass;
+ Parameter[] simpleParams = getSafeParameters(safeNode, declaringClass, actualReceiver);
- Map<GenericsType, GenericsType> spec;
- if (candidate.isStatic()) {
- spec = Collections.emptyMap(); // none visible
- } else {
- spec = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(declaringClass, actualReceiver);
- GenericsType[] methodGenerics = candidate.getGenericsTypes();
- if (methodGenerics != null) { // GROOVY-10322: remove hidden type parameters
- for (int i = 0, n = methodGenerics.length; i < n && !spec.isEmpty(); i += 1) {
- for (Iterator<GenericsType> it = spec.keySet().iterator(); it.hasNext(); ) {
- if (it.next().getName().equals(methodGenerics[i].getName())) it.remove();
- }
- }
- }
- }
-
- Parameter[] params = makeRawTypes(safeNode.getParameters(), spec);
- int dist = measureParametersAndArgumentsDistance(params, safeArgs);
+ int dist = measureParametersAndArgumentsDistance(simpleParams, safeArgs);
if (dist >= 0) {
dist += getClassDistance(declaringClass, actualReceiver);
dist += getExtensionDistance(isExtensionMethod);
@@ -1118,6 +1093,37 @@ public abstract class StaticTypeCheckingSupport {
return bestChoices;
}
+ private static Parameter[] getSafeParameters(final MethodNode methodNode, final ClassNode declaringClass, final ClassNode actualReceiver) {
+ Parameter[] params = methodNode.getParameters();
+ if (params.length > 0) {
+ Map<GenericsTypeName, GenericsType> spec;
+ if (methodNode.isStatic()) {
+ spec = Collections.emptyMap(); // not visible
+ } else {
+ extractGenericsConnections(spec = new HashMap<>(), actualReceiver, declaringClass);
+
+ GenericsType[] methodGenerics = methodNode.getGenericsTypes();
+ if (methodGenerics != null) { // GROOVY-10322: remove hidden type parameters
+ for (GenericsType tp : methodGenerics) spec.remove(new GenericsTypeName(tp.getName()));
+ }
+ }
+
+ params = params.clone();
+
+ for (int i = 0; i < params.length; i += 1) {
+ ClassNode t = params[i].getOriginType(), x=t;
+ while (x.isArray()) x = x.getComponentType();
+ if (x.isGenericsPlaceHolder()) {
+ // GROOVY-7204, GROOVY-8059, GROOVY-8609, GROOVY-10820, GROOVY-11276: "T" to "Foo" (via spec) or erasure
+ params[i] = new Parameter(GenericsUtils.nonGeneric(applyGenericsContext(spec, t)), params[i].getName());
+ } else if (x.getGenericsTypes() != null) { // reduce "List<Type>" to just "List"
+ params[i] = new Parameter(GenericsUtils.nonGeneric(t), params[i].getName());
+ }
+ }
+ }
+ return params;
+ }
+
private static int measureParametersAndArgumentsDistance(final Parameter[] parameters, final ClassNode[] argumentTypes) {
int dist = -1;
if (parameters.length == argumentTypes.length) {
@@ -1180,27 +1186,6 @@ public abstract class StaticTypeCheckingSupport {
return isExtensionMethodNode ? 0 : 1;
}
- private static Parameter[] makeRawTypes(final Parameter[] parameters, final Map<GenericsType, GenericsType> genericsPlaceholderAndTypeMap) {
- return Arrays.stream(parameters).map(param -> {
- String name = param.getType().getUnresolvedName();
- Optional<GenericsType> value = genericsPlaceholderAndTypeMap.entrySet().stream()
- .filter(e -> e.getKey().getName().equals(name)).findFirst().map(Map.Entry::getValue);
- ClassNode type = value.map(gt -> !gt.isPlaceholder() ? gt.getType() : makeRawType(gt.getType())).orElseGet(() -> makeRawType(param.getType()));
-
- return new Parameter(type, param.getName());
- }).toArray(Parameter[]::new);
- }
-
- private static ClassNode makeRawType(final ClassNode receiver) {
- if (receiver.isArray()) {
- return makeRawType(receiver.getComponentType()).makeArray();
- }
- ClassNode raw = receiver.getPlainNodeReference();
- raw.setUsingGenerics(false);
- raw.setGenericsTypes(null);
- return raw;
- }
-
private static List<MethodNode> removeCovariantsAndInterfaceEquivalents(final Collection<MethodNode> collection, final boolean disjoint) {
List<MethodNode> list = new ArrayList<>(new LinkedHashSet<>(collection)), toBeRemoved = new ArrayList<>();
for (int i = 0, n = list.size(); i < n - 1; i += 1) {
diff --git a/src/test/groovy/bugs/Groovy8609Bug.groovy b/src/test/groovy/bugs/Groovy8609Bug.groovy
index 28e6543b5b..28bb9232eb 100644
--- a/src/test/groovy/bugs/Groovy8609Bug.groovy
+++ b/src/test/groovy/bugs/Groovy8609Bug.groovy
@@ -98,7 +98,7 @@ final class Groovy8609Bug extends GroovyTestCase {
}
}
'''
- assert err.contains('Cannot find matching method A#getFirstRecord(java.util.ArrayList<java.util.TreeMap<java.lang.String, java.lang.Integer>>)')
+ assert err.contains('Cannot call A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Integer>>) with arguments [java.util.ArrayList<java.util.TreeMap<java.lang.String, java.lang.Integer>>]')
}
void testUpperBoundWithGenericsThroughWrongType2() {
@@ -118,7 +118,7 @@ final class Groovy8609Bug extends GroovyTestCase {
}
}
'''
- assert err.contains('Cannot find matching method A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Long>>)')
+ assert err.contains('Cannot call A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Integer>>) with arguments [java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Long>>]')
}
void testUpperBoundWithGenericsThroughWrongType3() {
@@ -138,6 +138,6 @@ final class Groovy8609Bug extends GroovyTestCase {
}
}
'''
- assert err.contains('Cannot find matching method A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.StringBuffer, java.lang.Integer>>)')
+ assert err.contains('Cannot call A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Integer>>) with arguments [java.util.ArrayList<java.util.HashMap<java.lang.StringBuffer, java.lang.Integer>>]')
}
}
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index 82f9895e80..41ded10f05 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -208,22 +208,15 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
}
void testGroovy5482ListsAndFlowTyping() {
- assertScript '''
- class StaticGroovy2 {
- def bar() {
-
- def foo = [new Date(), 1, new C()]
- foo.add( 2 ) // Compiles
- foo.add( new Date() )
- foo.add( new C() )
-
- foo = [new Date(), 1]
- foo.add( 2 ) // Does not compile
- }
- }
- class C{
- }
- new StaticGroovy2()'''
+ assertScript '''class C {}
+ def foo = [new Date(), 1, new C()]
+ foo.add(new Date())
+ foo.add(new C())
+ foo.add(2)
+
+ foo = [new Date(), 1]
+ foo.add(2) // STC err
+ '''
}
void testClosureThisObjectDelegateOwnerProperty() {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 1eb3b788d2..341c1cdf15 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -885,16 +885,13 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
assertScript '''
interface I<U> extends groovy.transform.stc.Groovy11257<U> {}
def <V> I<V> forge(V v) { return new I(){} }
- void test() {
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- def type = node.getNodeMetaData(INFERRED_TYPE)
- assert type.toString(false) == 'java.util.Optional<java.math.BigInteger>'
- })
- def opt = forge(1G).thing
- def num = opt.orElse(42G).intValue()
- }
- test()
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.toString(false) == 'java.util.Optional<java.math.BigInteger>'
+ })
+ def opt = forge(1G).thing
+ def num = opt.orElse(42G).intValue()
'''
}
@@ -2302,9 +2299,15 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
void testPutAtWithWrongValueType() {
+ shouldFailWithMessages '''
+ def map = new HashMap<Integer, Integer>()
+ map[123] = new Object()
+ ''',
+ 'Cannot call <K,V> org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.Map<K, V>, K, V) with arguments [java.util.HashMap<java.lang.Integer, java.lang.Integer>, int, java.lang.Object]'
+
shouldFailWithMessages '''
def map = new HashMap<String, Integer>()
- map['hello'] = new Object()
+ map['x'] = new Object()
''',
'Cannot call <K,V> org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.Map<K, V>, K, V) with arguments [java.util.HashMap<java.lang.String, java.lang.Integer>, java.lang.String, java.lang.Object]'
}
@@ -2322,18 +2325,15 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
''',
- 'Cannot find matching method java.util.Map#put(java.lang.String, java.util.LinkedHashMap<java.lang.String, java.util.List<ConfigAttribute>>)',
+ 'Cannot call java.util.Map#put(java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>) with arguments [java.lang.String, java.util.LinkedHashMap<java.lang.String, java.util.List<ConfigAttribute>>]',
'Cannot call <K,V> org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.Map<K, V>, K, V) with arguments [java.util.Map<java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>>, java.lang.String, java.util.LinkedHashMap<java.lang.String, java.util.List<ConfigAttribute>>]'
- }
- void testPutAtWithWrongValueType3() {
assertScript '''
void test(Map<String, Map<String, List<String>>> maps) {
maps.each { String key, Map<String, List<String>> map ->
Map<String, List<String>> value = [:]
- // populate value
- maps[key] = value
maps.put(key, value)
+ maps[key] = value
}
}
'''
@@ -2520,6 +2520,15 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
+ // GROOVY-11276
+ void testShouldUseMethodGenericType4a() {
+ assertScript '''
+ def map = new HashMap<String,List<String>>()
+ map.put('foo', Collections.emptyList())
+ map.put('bar', [])
+ '''
+ }
+
// GROOVY-9751
void testShouldUseMethodGenericType5() {
assertScript '''
@@ -4612,7 +4621,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
assert method.parameters[0].type == make(Collection)
})
def result = ['a','bb','ccc'].inject(0) { int acc, String str -> acc += str.length(); acc }
- assert result == 6
+ assert result == 6
'''
}
@@ -4624,8 +4633,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
assert method.name == 'inject'
assert method.parameters[0].type == make(Collection)
})
- def result = DefaultGroovyMethods.inject(['a','bb','ccc'],0, { int acc, String str -> acc += str.length(); acc })
- assert result == 6
+ def result = DefaultGroovyMethods.inject(['a','bb','ccc'], 0, { int acc, String str -> acc += str.length(); acc })
+ assert result == 6
'''
}
diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
index 907dcc4c6f..f4dd96cf9a 100644
--- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
@@ -209,7 +209,7 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
String[] args = ['a','b','c']
assert c.identity(args) == args
''',
- 'Cannot call groovy.transform.stc.MethodCallsSTCTest$MyMethodCallTestClass2#identity(java.lang.Integer[]) with arguments [java.lang.String[]]'
+ 'Cannot find matching method groovy.transform.stc.MethodCallsSTCTest$MyMethodCallTestClass2#identity(java.lang.String[])'
}
// GROOVY-8909