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/09/12 22:37:51 UTC
[groovy] branch GROOVY_2_5_X updated: GROOVY-5692, GROOVY-10006, GROOVY-10339: STC: multiple witnesses in call
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
new f96f6513ab GROOVY-5692, GROOVY-10006, GROOVY-10339: STC: multiple witnesses in call
f96f6513ab is described below
commit f96f6513abec4624042952abbd3d09ba9ffd83f9
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Sep 12 16:51:44 2022 -0500
GROOVY-5692, GROOVY-10006, GROOVY-10339: STC: multiple witnesses in call
---
.../groovy/ast/tools/WideningCategories.java | 14 ++++++
.../transform/stc/StaticTypeCheckingSupport.java | 43 ++++++++----------
.../groovy/transform/stc/GenericsSTCTest.groovy | 51 ++++++++++++----------
3 files changed, 62 insertions(+), 46 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
index 5137bd8584..a4ea1aef6a 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
@@ -673,6 +673,20 @@ public class WideningCategories {
return text;
}
+ @Override
+ public GenericsType asGenericsType() {
+ ClassNode[] ubs;
+ if (upper.equals(OBJECT_TYPE)) {
+ ubs = interfaces; // Object is implicit
+ } else {
+ ubs = new ClassNode[interfaces.length + 1]; ubs[0] = upper;
+ System.arraycopy(interfaces, 0, ubs, 1, interfaces.length);
+ }
+ GenericsType gt = new GenericsType(ClassHelper.makeWithoutCaching("?"), ubs, null);
+ gt.setWildcard(true);
+ return gt;
+ }
+
@Override
public ClassNode getPlainNodeReference() {
ClassNode[] intf = interfaces==null?null:new ClassNode[interfaces.length];
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 2e38604bbc..45ecca7e51 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -462,9 +462,6 @@ public abstract class StaticTypeCheckingSupport {
static boolean isAssignableTo(ClassNode type, ClassNode toBeAssignedTo) {
if (UNKNOWN_PARAMETER_TYPE == type) return true;
if (type == toBeAssignedTo) return true;
- if (toBeAssignedTo.redirect() == STRING_TYPE && type.redirect() == GSTRING_TYPE) {
- return true;
- }
if (isPrimitiveType(toBeAssignedTo)) toBeAssignedTo = getWrapper(toBeAssignedTo);
if (isPrimitiveType(type)) type = getWrapper(type);
if (NUMBER_TYPES.containsKey(type.redirect()) && NUMBER_TYPES.containsKey(toBeAssignedTo.redirect())) {
@@ -481,7 +478,7 @@ public abstract class StaticTypeCheckingSupport {
return true;
}
if (implementsInterfaceOrIsSubclassOf(type, toBeAssignedTo)) {
- if (OBJECT_TYPE.equals(toBeAssignedTo)) return true;
+ if (toBeAssignedTo.equals(OBJECT_TYPE)) return true;
if (toBeAssignedTo.isUsingGenerics()) {
// perform additional check on generics
// ? extends toBeAssignedTo
@@ -490,12 +487,9 @@ public abstract class StaticTypeCheckingSupport {
}
return true;
}
-
- //SAM check
if (type.isDerivedFrom(CLOSURE_TYPE) && isSAMType(toBeAssignedTo)) {
return true;
}
-
return false;
}
@@ -1601,17 +1595,21 @@ public abstract class StaticTypeCheckingSupport {
continue;
}
if (!compatibleConnection(resolved, connection)) {
- if (!(resolved.isPlaceholder() || resolved.isWildcard()) &&
- !fixedGenericsPlaceHolders.contains(entry.getKey()) &&
- compatibleConnection(connection, resolved)) {
- // we did for example find T=String and now check against
- // T=Object, which fails the first compatibleConnection check
- // but since T=Object works for both, the second one will pass
- // and we need to change the type for T to the more general one
- resolvedMethodGenerics.put(entry.getKey(), connection);
- } else {
- return false;
+ if (!resolved.isPlaceholder() && !resolved.isWildcard()
+ && !fixedGenericsPlaceHolders.contains(entry.getKey())) {
+ // GROOVY-5692, GROOVY-10006: multiple witnesses
+ if (compatibleConnection(connection, resolved)) {
+ // was "T=Integer" and now is "T=Number" or "T=Object"
+ resolvedMethodGenerics.put(entry.getKey(), connection);
+ continue;
+ } else if (!connection.isPlaceholder() && !connection.isWildcard()) {
+ // combine "T=Integer" and "T=String" to produce "T=? extends Serializable & Comparable<...>"
+ ClassNode lub = WideningCategories.lowestUpperBound(connection.getType(), resolved.getType());
+ resolvedMethodGenerics.put(entry.getKey(), lub.asGenericsType());
+ continue;
+ }
}
+ return false; // incompatible
}
}
return true;
@@ -1656,13 +1654,10 @@ public abstract class StaticTypeCheckingSupport {
return type;
}
- static void applyGenericsConnections(
- Map<GenericsTypeName, GenericsType> connections,
- Map<GenericsTypeName, GenericsType> resolvedPlaceholders
- ) {
- if (connections == null) return;
- int count = 0;
+ static void applyGenericsConnections(final Map<GenericsTypeName, GenericsType> connections, final Map<GenericsTypeName, GenericsType> resolvedPlaceholders) {
+ if (!asBoolean(connections)) return;
+ int count = 0;
while (count++ < 10000) {
boolean checkForMorePlaceholders = false;
for (Map.Entry<GenericsTypeName, GenericsType> entry : resolvedPlaceholders.entrySet()) {
@@ -2081,11 +2076,11 @@ public abstract class StaticTypeCheckingSupport {
* A DGM-like method which adds support for method calls which are handled
* specifically by the Groovy compiler.
*/
+ @SuppressWarnings("unused")
private static class ObjectArrayStaticTypesHelper {
public static <T> T getAt(T[] arr, int index) {
return null;
}
-
public static <T, U extends T> void putAt(T[] arr, int index, U object) {
}
}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index cc6a225b0e..991dd48adf 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -323,6 +323,33 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ @NotYetImplemented // GROOVY-10339
+ void testReturnTypeInferenceWithMethodGenerics21() {
+ for (type in ['Character', 'Integer']) {
+ shouldFailWithMessages """
+ Character foo() {
+ }
+ def <T> T bar(T x, T y) {
+ }
+ $type z = bar(foo(), 1)
+ """,
+ 'Cannot assign value of type'
+ }
+ }
+
+ // 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-10749
void testReturnTypeInferenceWithMethodGenerics29() {
if (!GroovyAssert.isAtLeastJdk('1.8')) return
@@ -2348,7 +2375,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- @NotYetImplemented // GROOVY-5692, GROOVY-10006
+ // GROOVY-5692, GROOVY-10006
void testCompatibleArgumentsForPlaceholders1() {
assertScript '''
def <T> T test(T one, T two) { }
@@ -2364,7 +2391,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- @NotYetImplemented // GROOVY-5692
+ // GROOVY-5692
void testCompatibleArgumentsForPlaceholders2() {
assertScript '''
def <T> boolean test(T one, List<T> many) { }
@@ -2520,26 +2547,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
- void testIncompatibleGenericsForTwoArguments() {
- shouldFailWithMessages '''
- public <T> void printEqual(T arg1, T arg2) {
- println arg1 == arg2
- }
- printEqual(1, 'foo')
- ''',
- '#printEqual(T, T) with arguments [int, java.lang.String]'
- }
-
- void testIncompatibleGenericsForTwoArgumentsUsingEmbeddedPlaceholder() {
- shouldFailWithMessages '''
- public <T> void printEqual(T arg1, List<T> arg2) {
- println arg1 == arg2
- }
- printEqual(1, ['foo'])
- ''',
- '#printEqual(T, java.util.List <T>) with arguments [int, java.util.List <java.lang.String>]'
- }
-
// GROOVY-9902: incomplete generics should not stop type checking
void testIncompatibleArgumentsForPlaceholders3() {
shouldFailWithMessages '''