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/05/19 15:54:52 UTC
[groovy] branch master updated: GROOVY-10342: STC: type parameter can accept parameterized return values
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 006b5987a7 GROOVY-10342: STC: type parameter can accept parameterized return values
006b5987a7 is described below
commit 006b5987a7d91c4a4754d9e4a1191484e43f9868
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu May 19 10:41:43 2022 -0500
GROOVY-10342: STC: type parameter can accept parameterized return values
---
.../transform/stc/StaticTypeCheckingSupport.java | 38 +++++++++++++---------
.../transform/stc/StaticTypeCheckingVisitor.java | 11 +++++--
.../groovy/transform/stc/GenericsSTCTest.groovy | 31 +++++++++++++++++-
3 files changed, 60 insertions(+), 20 deletions(-)
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 b4a76624a8..819da3e79d 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -121,6 +121,7 @@ import static org.codehaus.groovy.ast.ClassHelper.make;
import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching;
import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.void_WRAPPER_TYPE;
+import static org.codehaus.groovy.ast.tools.WideningCategories.implementsInterfaceOrSubclassOf;
import static org.codehaus.groovy.ast.tools.WideningCategories.isFloatingCategory;
import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
import static org.codehaus.groovy.ast.tools.WideningCategories.lowestUpperBound;
@@ -698,11 +699,21 @@ public abstract class StaticTypeCheckingSupport {
if (isNumberType(rightRedirect) /*|| rightRedirect == char_TYPE*/) {
return true;
}
+ if (leftRedirect == char_TYPE && rightRedirect == Character_TYPE) return true;
+ if (leftRedirect == Character_TYPE && rightRedirect == char_TYPE) return true;
+ if ((leftRedirect == char_TYPE || leftRedirect == Character_TYPE) && rightRedirect == STRING_TYPE) {
+ return rightExpression instanceof ConstantExpression && rightExpression.getText().length() == 1;
+ }
} else if (isFloatingCategory(getUnwrapper(leftRedirect))) {
// float or double can be assigned any base number type or BigDecimal
if (isNumberType(rightRedirect) || isBigDecimalType(rightRedirect)) {
return true;
}
+ } else if (left.isGenericsPlaceHolder()) { // must precede non-final types
+ return right.getUnresolvedName().charAt(0) != '#' // RHS not adaptable
+ ? left.getGenericsTypes()[0].isCompatibleWith(right) // GROOVY-7307, GROOVY-9952, et al.
+ : implementsInterfaceOrSubclassOf(leftRedirect, rightRedirect); // GROOVY-10067, GROOVY-10342
+
} else if (isBigDecimalType(leftRedirect) || Number_TYPE.equals(leftRedirect)) {
// BigDecimal or Number can be assigned any derivitave of java.lang.Number
if (isNumberType(rightRedirect) || rightRedirect.isDerivedFrom(Number_TYPE)) {
@@ -713,22 +724,16 @@ public abstract class StaticTypeCheckingSupport {
if (isLongCategory(getUnwrapper(rightRedirect)) || rightRedirect.isDerivedFrom(BigInteger_TYPE)) {
return true;
}
+ } else if (leftRedirect.isDerivedFrom(Enum_Type)) {
+ // Enum types can be assigned String or GString (triggers `valueOf` call)
+ if (rightRedirect == STRING_TYPE || isGStringOrGStringStringLUB(rightRedirect)) {
+ return true;
+ }
} else if (isWildcardLeftHandSide(leftRedirect)) {
// Object, String, [Bb]oolean or Class can be assigned anything (except null to boolean)
return !(leftRedirect == boolean_TYPE && isNullConstant(rightExpression));
}
- if (leftRedirect == char_TYPE && rightRedirect == Character_TYPE) return true;
- if (leftRedirect == Character_TYPE && rightRedirect == char_TYPE) return true;
- if ((leftRedirect == char_TYPE || leftRedirect == Character_TYPE) && rightRedirect == STRING_TYPE) {
- return rightExpression instanceof ConstantExpression && rightExpression.getText().length() == 1;
- }
-
- // if left is an enum and right is String or GString we do valueOf
- if (leftRedirect.isDerivedFrom(Enum_Type) && (rightRedirect == STRING_TYPE || isGStringType(rightRedirect))) {
- return true;
- }
-
// if right is array, map or collection we try invoking the constructor
if (allowConstructorCoercion && isGroovyConstructorCompatible(rightExpression)) {
// TODO: in case of the array we could maybe make a partial check
@@ -738,16 +743,14 @@ public abstract class StaticTypeCheckingSupport {
return true;
}
- // simple sub-type check
- if (!left.isInterface() ? right.isDerivedFrom(left) : GeneralUtils.isOrImplements(right, left)) return true;
+ if (implementsInterfaceOrSubclassOf(right, left)) {
+ return true;
+ }
if (right.isDerivedFrom(CLOSURE_TYPE) && isSAMType(left)) {
return true;
}
- if (left.isGenericsPlaceHolder()) {
- return left.getGenericsTypes()[0].isCompatibleWith(right);
- }
// GROOVY-7316, GROOVY-10256: "Type x = m()" given "def <T> T m()"; T adapts to target
return right.isGenericsPlaceHolder() && right.asGenericsType().isCompatibleWith(left);
}
@@ -865,6 +868,9 @@ public abstract class StaticTypeCheckingSupport {
* with trailing "[]".
*/
static String prettyPrintType(final ClassNode type) {
+ if (type.getUnresolvedName().charAt(0) == '#') {
+ return type.redirect().toString(false);
+ }
return type.toString(false);
}
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 1b8fbb45ec..88df814abb 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -848,7 +848,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (rightExpression instanceof ConstructorCallExpression)
inferDiamondType((ConstructorCallExpression) rightExpression, lType);
- if (lType.isUsingGenerics() && missesGenericsTypes(resultType)) {
+ if (lType.isUsingGenerics()
+ && missesGenericsTypes(resultType)
+ // GROOVY-10324, GROOVY-10342, et al.
+ && !resultType.isGenericsPlaceHolder()) {
// unchecked assignment
// List<Type> list = new LinkedList()
// Iterable<Type> iter = new LinkedList()
@@ -858,8 +861,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
// the inferred type of the binary expression is the type of the RHS
// "completed" with generics type information available from the LHS
if (lType.equals(resultType)) {
+ // GROOVY-6126, GROOVY-6558, GROOVY-6564, et al.
if (!lType.isGenericsPlaceHolder()) resultType = lType;
- } else if (!resultType.isGenericsPlaceHolder()) { // GROOVY-10324
+ } else {
+ // GROOVY-5640, GROOVY-9033, GROOVY-10220, GROOVY-10235, et al.
Map<GenericsTypeName, GenericsType> gt = new HashMap<>();
extractGenericsConnections(gt, resultType, resultType.redirect());
ClassNode sc = resultType;
@@ -867,7 +872,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
} while (sc != null && !sc.equals(lType));
extractGenericsConnections(gt, lType, sc);
- resultType = applyGenericsContext(gt, resultType.redirect());// GROOVY-10235, et al.
+ resultType = applyGenericsContext(gt, resultType.redirect());
}
}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index b330ad771d..7c579b4751 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -500,7 +500,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
chars()
}
''',
- 'Cannot return value of type #T for method returning java.util.List'
+ 'Cannot return value of type java.lang.CharSequence for method returning java.util.List'
}
// GROOVY-10098
@@ -1471,6 +1471,35 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10342
+ void testAssignmentShouldWorkForParameterizedType2() {
+ assertScript '''
+ class C<T> {
+ T t
+ }
+ def <X> X m() {
+ 123
+ }
+ def <N extends Number> void test() {
+ int x = m()
+ Integer y = m()
+ C<Integer> z = new C<>(); z.t = m()
+
+ C<N> c_of_n = new C<N>(); c_of_n.t = m() // Cannot assign value of type #X to variable of type N
+ }
+ test()
+ '''
+
+ shouldFailWithMessages '''
+ def <X extends CharSequence> X m() {
+ }
+ def <N extends Number> void test() {
+ N n = m()
+ }
+ ''',
+ 'Cannot assign value of type java.lang.CharSequence to variable of type N'
+ }
+
// GROOVY-9555
void testAssignmentShouldWorkForProperUpperBound() {
assertScript '''