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/12/16 16:20:45 UTC
[groovy] branch master updated: STC: refactor closure/lambda/pointer/reference generics handling
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 06079d32ec STC: refactor closure/lambda/pointer/reference generics handling
06079d32ec is described below
commit 06079d32ecb26c17a3db6b0bc99ea01d1c7c58d1
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Dec 16 09:40:21 2022 -0600
STC: refactor closure/lambda/pointer/reference generics handling
---
.../transform/stc/StaticTypeCheckingSupport.java | 2 +-
.../transform/stc/StaticTypeCheckingVisitor.java | 188 ++++++++-------------
.../groovy/transform/stc/StaticTypesMarker.java | 10 +-
.../groovy/transform/stc/GenericsSTCTest.groovy | 37 ++--
.../transform/stc/MethodReferenceTest.groovy | 26 +--
5 files changed, 101 insertions(+), 162 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 16a797db4c..b96e37015b 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1495,7 +1495,7 @@ public abstract class StaticTypeCheckingSupport {
// the context we compare with in the end is the one of the callsite
// so far we specified the context of the method declaration only
// thus for each argument, we try to find the connected generics first
- Map<GenericsTypeName, GenericsType> connections = new LinkedHashMap<>();
+ Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
extractGenericsConnections(connections, wrappedArgument, type);
// each new connection must comply with previous connections
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 c833106456..5be61fd0cd 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -986,7 +986,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
inferParameterAndReturnTypesOfClosureOnRHS(target, lambda);
source.putNodeMetaData(PARAMETER_TYPE, lambda.getNodeMetaData(PARAMETER_TYPE));
- source.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(lambda.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
+ source.putNodeMetaData(CLOSURE_ARGUMENTS, extractTypesFromParameters(lambda.getParameters()));
}
}
}
@@ -2819,26 +2819,29 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
for (int i = 0; i < nExpressions; i += 1) {
Expression expression = expressions.get(i);
if (visitClosures == (expression instanceof ClosureExpression || expression instanceof MethodPointerExpression)) {
- ClassNode targetType = null;
if (visitClosures && nthParameter != -1) { // GROOVY-10636: vargs call
Parameter target = parameters[Math.min(i, nthParameter)];
- targetType = target.getType();
+ ClassNode targetType = target.getType();
if (targetType.isArray() && i >= nthParameter)
targetType = targetType.getComponentType();
-
+ boolean coerceToMethod = isSAMType(targetType);
+ if (coerceToMethod) { // resolve the target parameter's type
+ Map<GenericsTypeName, GenericsType> context = extractPlaceHoldersVisibleToDeclaration(receiver, selectedMethod, arguments);
+ targetType = applyGenericsContext(context, targetType);
+ expression.putNodeMetaData(PARAMETER_TYPE, targetType);
+ }
if (expression instanceof ClosureExpression) {
- ClosureExpression source = (ClosureExpression) expression;
- checkClosureWithDelegatesTo(receiver, selectedMethod, args(expressions), parameters, source, target);
+ checkClosureWithDelegatesTo(receiver, selectedMethod, args(expressions), parameters, expression, target);
if (i > 0 || !(selectedMethod instanceof ExtensionMethodNode)) {
- inferClosureParameterTypes(receiver, arguments, source, target, selectedMethod);
+ inferClosureParameterTypes(receiver, arguments, (ClosureExpression) expression, target, selectedMethod);
}
- if (isFunctionalInterface(targetType)) {
- storeInferredReturnType(source, GenericsUtils.parameterizeSAM(targetType).getV2());
+ if (coerceToMethod && targetType.isInterface()) { // @FunctionalInterface
+ storeInferredReturnType(expression, GenericsUtils.parameterizeSAM(targetType).getV2());
} else if (isClosureWithType(targetType)) {
- storeInferredReturnType(source, getCombinedBoundType(targetType.getGenericsTypes()[0]));
+ storeInferredReturnType(expression, getCombinedBoundType(targetType.getGenericsTypes()[0]));
}
} else if (expression instanceof MethodReferenceExpression) {
- if (isFunctionalInterface(targetType)) {
+ if (coerceToMethod && targetType.isInterface()) { // @FunctionalInterface
LambdaExpression lambda = constructLambdaExpressionForMethodReference(
targetType, (MethodReferenceExpression) expression);
inferClosureParameterTypes(receiver, arguments, lambda, target, selectedMethod);
@@ -2850,13 +2853,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
expression.visit(this);
expression.removeNodeMetaData(DELEGATION_METADATA);
-
- MethodNode sam = findSAM(targetType);
- if (sam != null) {
- Map<GenericsTypeName, GenericsType> context = extractPlaceHoldersVisibleToDeclaration(receiver, selectedMethod, arguments);
- targetType = applyGenericsContext(context, targetType);
- expression.putNodeMetaData(PARAMETER_TYPE, targetType);
- }
}
if (i == 0 && parameters.length > 0 && expression instanceof MapExpression) {
checkNamedParamsAnnotation(parameters[0], (MapExpression) expression);
@@ -2864,15 +2860,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
- private LambdaExpression constructLambdaExpressionForMethodReference(final ClassNode functionalInterface, final MethodReferenceExpression methodReference) {
+ private static LambdaExpression constructLambdaExpressionForMethodReference(final ClassNode functionalInterface, final MethodReferenceExpression methodReference) {
Parameter[] parameters = findSAM(functionalInterface).getParameters();
int nParameters = parameters.length;
if (nParameters > 0) {
- ClassNode firstParamType = dynamicType();
parameters = new Parameter[nParameters];
- for (int i = 0; i < nParameters; i += 1) {
- parameters[i] = new Parameter(i == 0 ? firstParamType : dynamicType(), "p" + i);
- }
+ for (int i = 0; i < nParameters; i += 1)
+ parameters[i] = new Parameter(dynamicType(), "p" + i);
}
return new LambdaExpression(parameters, GENERATED_EMPTY_STATEMENT);
}
@@ -4358,14 +4352,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
Expression rightExpression = expr.getRightExpression();
if (op == EQUAL || op == ELVIS_EQUAL) {
- if (rightRedirect.isDerivedFrom(CLOSURE_TYPE)) {
- MethodNode abstractMethod = findSAM(left);
- if (abstractMethod != null && (rightExpression instanceof ClosureExpression
- || rightExpression instanceof MethodPointerExpression)) {
- return convertClosureTypeToSAMType(rightExpression, right, abstractMethod, left);
- }
- }
-
if (leftExpression instanceof VariableExpression) {
ClassNode initialType = getOriginalDeclarationType(leftExpression);
@@ -4395,12 +4381,16 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
|| LinkedHashSet_TYPE.isDerivedFrom(leftRedirect)) { // GROOVY-6912
return getLiteralResultType(left, right, LinkedHashSet_TYPE); // GROOVY-7128
}
- }
- if (rightExpression instanceof MapExpression) {
+ } else if (rightExpression instanceof MapExpression) {
if (MAP_TYPE.equals(leftRedirect)
|| LinkedHashMap_TYPE.isDerivedFrom(leftRedirect)) {
return getLiteralResultType(left, right, LinkedHashMap_TYPE); // GROOVY-7128, GROOVY-9844
}
+ } else if (rightExpression instanceof ClosureExpression
+ || rightExpression instanceof MethodPointerExpression) {
+ if (isSAMType(leftRedirect)) {
+ return left; // coercion
+ }
}
}
@@ -5297,10 +5287,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (isVargs ? nArguments >= nParams - 1 : nArguments == nParams) {
for (int i = 0; i < nArguments; i += 1) {
- if (isNullConstant(expressions.get(i)))
- continue; // GROOVY-9984: skip null
+ Expression argument = expressions.get(i);
+ if (isNullConstant(argument)) continue; // GROOVY-9984: skip
+ ClassNode argumentType = getDeclaredOrInferredType(argument);
ClassNode paramType = parameters[Math.min(i, nParams - 1)].getType();
- ClassNode argumentType = getDeclaredOrInferredType(expressions.get(i));
if (GenericsUtils.hasUnresolvedGenerics(paramType)) {
// if supplying array param with multiple arguments or single non-array argument, infer using element type
@@ -5308,15 +5298,51 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
paramType = paramType.getComponentType();
}
- if (argumentType.equals(CLOSURE_TYPE)) {
- MethodNode sam = findSAM(paramType);
- if (sam != null) { // adapt closure to functional interface or other single-abstract-method class
- argumentType = convertClosureTypeToSAMType(expressions.get(i), argumentType, sam, paramType);
+ Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
+
+ if ((argument instanceof ClosureExpression || argument instanceof MethodPointerExpression) && isSAMType(paramType)) {
+ // target type information
+ Tuple2<ClassNode[], ClassNode> samParamsAndReturnType = GenericsUtils.parameterizeSAM(paramType);
+ ClassNode[] q = samParamsAndReturnType.getV1();
+
+ // source type information
+ ClassNode returnType = isClosureWithType(argumentType)
+ ? getCombinedBoundType(argumentType.getGenericsTypes()[0])
+ : wrapTypeIfNecessary(getInferredReturnType(argument));
+ ClassNode[] p;
+ if (argument instanceof ClosureExpression) {
+ ClosureExpression closure = (ClosureExpression) argument;
+ p = extractTypesFromParameters(getParametersSafe(closure));
+ } else { // argument instanceof MethodPointerExpression
+ List<MethodNode> candidates = argument.getNodeMetaData(MethodNode.class);
+ if (candidates != null && !candidates.isEmpty()) {
+ MethodPointerExpression methodPointer = (MethodPointerExpression) argument;
+ p = collateMethodReferenceParameterTypes(methodPointer, candidates.get(0));
+ if (p.length > 0) {
+ for (int j = 0; j < q.length; j += 1) {
+ // SAM parameters are like arguments in this case
+ extractGenericsConnections(connections, q[j], p[j]);
+ }
+ // convert the method's generics into the SAM's generics
+ returnType = applyGenericsContext(connections, returnType);
+
+ connections.clear();
+ }
+ } else {
+ p = ClassNode.EMPTY_ARRAY;
+ }
}
+
+ // parameters and return type correspond to the SAM's
+ for (int j = 0; j < p.length && j < q.length; j += 1) {
+ if (!isDynamicTyped(p[j]))
+ extractGenericsConnections(connections, wrapTypeIfNecessary(p[j]), q[j]);
+ }
+ extractGenericsConnections(connections, returnType, samParamsAndReturnType.getV2());
+ } else {
+ extractGenericsConnections(connections, wrapTypeIfNecessary(argumentType), paramType);
}
- Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
- extractGenericsConnections(connections, wrapTypeIfNecessary(argumentType), paramType);
connections.forEach((gtn, gt) -> resolvedPlaceholders.merge(gtn, gt, (gt1, gt2) -> {
// GROOVY-10339: incorporate another witness
return getCombinedGenericsType(gt1, gt2);
@@ -5456,67 +5482,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
- /**
- * Converts a Closure type to the appropriate SAM type, which can be used to
- * infer return type generics.
- *
- * @param expression the argument expression
- * @param closureType the inferred type of {@code expression}
- * @param samType the target type for the argument expression
- * @return SAM type augmented using information from the argument expression
- */
- private static ClassNode convertClosureTypeToSAMType(Expression expression, final ClassNode closureType, final MethodNode sam, final ClassNode samType) {
- Map<GenericsTypeName, GenericsType> samTypeConnections = GenericsUtils.extractPlaceholders(samType);
- samTypeConnections.replaceAll((xx, gt) -> // GROOVY-9762, GROOVY-9803: reduce "? super T" to "T"
- Optional.ofNullable(gt.getLowerBound()).map(GenericsType::new).orElse(gt)
- );
-
- ClassNode closureReturnType = isClosureWithType(closureType)
- ? getCombinedBoundType(closureType.getGenericsTypes()[0])
- : wrapTypeIfNecessary(expression.getNodeMetaData(INFERRED_RETURN_TYPE));
-
- Parameter[] parameters = sam.getParameters();
- if (parameters.length > 0 && expression instanceof MethodPointerExpression) {
- // try to resolve referenced method type parameters in return type
- MethodPointerExpression mp = (MethodPointerExpression) expression;
- List<MethodNode> candidates = mp.getNodeMetaData(MethodNode.class);
- if (candidates != null && !candidates.isEmpty()) {
- ClassNode[] paramTypes = applyGenericsContext(samTypeConnections, extractTypesFromParameters(parameters));
- ClassNode[] matchTypes = candidates.stream()
- .map(candidate -> collateMethodReferenceParameterTypes(mp, candidate))
- .filter(signature -> checkSignatureSuitability(signature, paramTypes))
- .findFirst().orElse(null); // TODO: order signatures by param distance
- if (matchTypes != null) {
- Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
- for (int i = 0, n = parameters.length; i < n; i += 1) {
- // SAM parameters should align with the referenced method's parameters
- extractGenericsConnections(connections, paramTypes[i], matchTypes[i]);
- }
- // convert the method reference's generics into the SAM's generics domain
- closureReturnType = applyGenericsContext(connections, closureReturnType);
- // apply known generics connections to the SAM's placeholders in the return type
- closureReturnType = applyGenericsContext(samTypeConnections, closureReturnType);
-
- expression = new ClosureExpression(Arrays.stream(matchTypes).map(t -> new Parameter(t,"")).toArray(Parameter[]::new), null);
- }
- }
- }
-
- // the SAM's return type exactly corresponds to the inferred closure return type
- extractGenericsConnections(samTypeConnections, closureReturnType, sam.getReturnType());
-
- // repeat the same for each parameter given in the ClosureExpression
- if (parameters.length > 0 && expression instanceof ClosureExpression) {
- ClassNode[] paramTypes = applyGenericsContext(samTypeConnections, extractTypesFromParameters(parameters));
- int i = 0;
- // GROOVY-10054, GROOVY-10699, GROOVY-10749, et al.
- for (Parameter p : getParametersSafe((ClosureExpression) expression))
- if (!p.isDynamicTyped()) extractGenericsConnections(samTypeConnections, p.getType(), paramTypes[i++]);
- }
-
- return applyGenericsContext(samTypeConnections, samType.redirect());
- }
-
private static ClassNode[] collateMethodReferenceParameterTypes(final MethodPointerExpression source, final MethodNode target) {
Parameter[] params;
@@ -5536,21 +5501,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return extractTypesFromParameters(params);
}
- private static boolean checkSignatureSuitability(final ClassNode[] receiverTypes, final ClassNode[] providerTypes) {
- int n = receiverTypes.length;
- if (n != providerTypes.length) {
- return false;
- }
- for (int i = 0; i < n; i += 1) {
- // for method closure SAM parameters act like arguments
- if (!isAssignableTo(providerTypes[i], receiverTypes[i])
- && !providerTypes[i].isGenericsPlaceHolder()) {
- return false;
- }
- }
- return true;
- }
-
private ClassNode getDeclaredOrInferredType(final Expression expression) {
ClassNode declaredOrInferred;
// in case of "T t = new ExtendsOrImplementsT()", return T for the expression type
@@ -5650,7 +5600,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
private static Map<GenericsTypeName, GenericsType> extractPlaceHoldersVisibleToDeclaration(final ClassNode receiver, final MethodNode method, final Expression argument) {
Map<GenericsTypeName, GenericsType> result;
- if (method.isStatic()) {
+ if (method.isStatic() || (method.isConstructor() && !asBoolean(receiver.getGenericsTypes()))) {
result = new HashMap<>();
} else {
ClassNode declaring = method.getDeclaringClass();
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypesMarker.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypesMarker.java
index fa66212a7f..8435b0fa5d 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypesMarker.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypesMarker.java
@@ -30,9 +30,9 @@ public enum StaticTypesMarker {
DECLARATION_INFERRED_TYPE,
/** used to store inferred return type for methods and closures */
INFERRED_RETURN_TYPE,
- /** used to store closure argument types on a variable expression */
+ /** used to store expected closure argument types on an expression */
CLOSURE_ARGUMENTS,
- /** used to tell that a property expression refers to a readonly property */
+ /** used to tell that a property expression refers to a read-only property */
READONLY_PROPERTY,
/** used to store the default expression for a parameter */
INITIAL_EXPRESSION,
@@ -52,12 +52,8 @@ public enum StaticTypesMarker {
DYNAMIC_RESOLUTION,
/** used to store the list of MOP methods that still have to be generated */
SUPER_MOP_METHOD_REQUIRED,
- /** used to store the parameter type information of method invocation on an expression */
+ /** used to store the parameter type of method invocation on an expression */
PARAMETER_TYPE,
- /** used to store the function interface type information on an expression */
- INFERRED_FUNCTIONAL_INTERFACE_TYPE,
- /** used to store the constructed lambda expression for method reference and constructor reference */
- CONSTRUCTED_LAMBDA_EXPRESSION,
/** used to store the condition expression type of the switch-case statement */
SWITCH_CONDITION_EXPRESSION_TYPE,
/** used to store the result of {@link StaticTypeCheckingVisitor#getType} */
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index b30d8e8749..5cd2d70534 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -302,7 +302,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
assert result == [ 42 ]
'''
- ['t::cast', 'n -> t.cast(n)', 'n -> (N) n', '{ n -> (N) n }'].each { cast ->
+ for (cast in ['t::cast', 'n -> t.cast(n)', 'n -> (N) n', '{ n -> (N) n }']) {
assertScript """
Set<Number> f() {
Collections.<Number>singleton(42)
@@ -458,7 +458,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-8409
void testReturnTypeInferenceWithMethodGenerics14() {
- ['R', 'S', 'T', 'U'].each { t -> // BiFunction uses R, T and U
+ for (t in ['R', 'S', 'T', 'U']) { // 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'))
@@ -874,7 +874,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-6232
void testDiamondInferrenceFromConstructor5() {
- ['"a",new Object()', 'new Object(),"b"', '"a","b"'].each { args ->
+ for (args in ['"a",new Object()', 'new Object(),"b"', '"a","b"']) {
assertScript """
class C<T> {
C(T x, T y) {
@@ -1402,9 +1402,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-10368
void testDiamondInferrenceFromConstructor25() {
- ['T', 'T extends Number', 'T extends Object'].each {
+ for (t in ['T', 'T extends Number', 'T extends Object']) {
assertScript """
- class C<$it> {
+ class C<$t> {
C(p) {
}
}
@@ -1564,7 +1564,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
def type = node.getNodeMetaData(INFERRED_TYPE)
assert type.toString(false) == 'C<java.lang.String>'
})
- def y = new C<>((String s) -> { print(s); }) // error: Expected type Object for lambda parameter: s
+ def y = new C<>((String s) -> { print(s) }) // error: Expected type Object for lambda parameter: s
'''
assertScript '''import java.util.function.Supplier
@@ -2265,7 +2265,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-8961, GROOVY-9915
void testShouldUseMethodGenericType3() {
- ['', 'static'].each { mods ->
+ for (mods in ['', 'static']) {
assertScript """
$mods void setX(List<String> strings) {
}
@@ -2304,7 +2304,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-9734, GROOVY-9915
void testShouldUseMethodGenericType4() {
- ['', 'static'].each { mods ->
+ for (mods in ['', 'static']) {
assertScript """
$mods void m(List<String> strings) {
}
@@ -2392,7 +2392,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
assert opt.get() == 42
'''
// same as above but with separate type parameter name for each location
- ['D.&wrap', 'Collections.&singleton', '{x -> [x].toSet()}', '{Collections.singleton(it)}'].each { toSet ->
+ for (toSet in ['D.&wrap', 'Collections.&singleton', '{x -> [x].toSet()}', '{Collections.singleton(it)}']) {
assertScript """
abstract class A<I,O> {
abstract O apply(I input)
@@ -3158,7 +3158,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-10482
void testCompatibleArgumentsForPlaceholders6() {
- ['', 'def', 'public', 'static', '@Deprecated'].each {
+ for (it in ['', 'def', 'public', 'static', '@Deprecated']) {
assertScript """
class Foo<X> {
Foo(X x) {
@@ -3176,7 +3176,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-10499
void testCompatibleArgumentsForPlaceholders7() {
- ['?', 'Y', '? extends Y'].each {
+ for (it in ['?', 'Y', '? extends Y']) {
assertScript """
class Foo<X> {
Foo(X x) {
@@ -3247,14 +3247,14 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-10153
void testCompatibleArgumentsForPlaceholders11() {
- ['A', 'B', 'C'].each { T ->
+ for (t in ['A', 'B', 'C']) {
assertScript """
class A {}
class B extends A {}
class C extends B {}
class Foo<T extends A> {}
- Foo<? super C> foo = new Foo<$T>()
+ Foo<? super C> foo = new Foo<$t>()
// ^ lower bound is C (explicit); upper bound is A (implicit)
"""
}
@@ -3268,7 +3268,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'#test(int, java.lang.String). Please check if the declared type is correct and if the method exists.'
}
- @NotYetImplemented // GROOVY-7720
+ // GROOVY-7720
+ @NotYetImplemented
void testIncompatibleArgumentsForPlaceholders2() {
shouldFailWithMessages '''
class Consumer<T> {
@@ -3803,7 +3804,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-5893
void testPlusInClosure() {
- ['def', 'var', 'Object', 'Number', 'Integer', 'Comparable'].each { type ->
+ for (type in ['def', 'var', 'Object', 'Number', 'Integer', 'Comparable']) {
assertScript """
List<Integer> list = [1, 2, 3]
@@ -4621,7 +4622,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
void testContravariantMethodResolutionWithImplicitCoercion2() {
- ['public', 'static'].each { modifier ->
+ for (modifier in ['public', 'static']) {
assertScript """
$modifier <I, O> void transform(java.util.function.Function<? super I, ? extends O> function) {
function.apply('')
@@ -4868,7 +4869,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
// GROOVY-9821
- ['.', '?.', '*.'].each { op ->
+ for (op in ['.', '?.', '*.']) {
File parentDir = File.createTempDir()
config.with {
targetDirectory = File.createTempDir()
@@ -5043,7 +5044,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-10556
void testSelfReferentialTypeParameter3() {
- ['(B) this', 'this as B'].each { self ->
+ for (self in ['(B) this', 'this as B']) {
assertScript """
abstract class A<B extends A<B,X>,X> {
B m() {
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index 29cc338a05..d9879ce7ed 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -643,14 +643,14 @@ final class MethodReferenceTest {
}
@CompileStatic
class X extends A {
- public X() {
- super(Y::new)
- }
- private static class Y extends B {
- Y(A a) {
- super(a)
+ public X() {
+ super(Y::new)
+ }
+ private static class Y extends B {
+ Y(A a) {
+ super(a)
+ }
}
- }
}
new X()
@@ -970,7 +970,7 @@ final class MethodReferenceTest {
}
}
- @Test // GROOVY-10742, GROOVY-10858
+ @Test // GROOVY-10742
void testIncompatibleReturnType() {
def err = shouldFail shell, '''
void foo(bar) {
@@ -980,15 +980,7 @@ final class MethodReferenceTest {
Function<Object,String> f = this::foo
}
'''
- assert err =~ /Cannot assign java.util.function.Function<java.lang.Object, java.lang.Void> to: java.util.function.Function<java.lang.Object, java.lang.String>/
-
- err = shouldFail shell, '''
- @CompileStatic
- void test() {
- Function<Object,Number> f = Object::toString
- }
- '''
- assert err =~ /Cannot assign java.util.function.Function<java.lang.Object, java.lang.String> to: java.util.function.Function<java.lang.Object, java.lang.Number>/
+ assert err =~ /Invalid return type: void is not convertible to java.lang.String/
}
@Test // GROOVY-10269