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/04 16:48:28 UTC
[groovy] branch master updated: GROOVY-10749: STC: closure/lambda/reference parameter(s) as type witness
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 3b9e31cce6 GROOVY-10749: STC: closure/lambda/reference parameter(s) as type witness
3b9e31cce6 is described below
commit 3b9e31cce6c1aa1aea1947afd6dd16abb77eaf13
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Sep 4 11:39:21 2022 -0500
GROOVY-10749: STC: closure/lambda/reference parameter(s) as type witness
---
.../java/org/codehaus/groovy/ast/Parameter.java | 2 +-
.../transform/stc/StaticTypeCheckingVisitor.java | 19 +++++++-----
.../groovy/transform/stc/GenericsSTCTest.groovy | 34 +++++++++++++++++++++-
3 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/Parameter.java b/src/main/java/org/codehaus/groovy/ast/Parameter.java
index 0ca914a07c..5c25900f2a 100644
--- a/src/main/java/org/codehaus/groovy/ast/Parameter.java
+++ b/src/main/java/org/codehaus/groovy/ast/Parameter.java
@@ -53,7 +53,7 @@ public class Parameter extends AnnotatedNode implements Variable {
@Override
public String toString() {
- return super.toString() + "[name:" + name + ((type == null) ? "" : " type: " + type.getName()) + ", hasDefaultValue: " + this.hasInitialExpression() + "]";
+ return super.toString() + "[name: " + name + (type == null ? "" : ", type: " + type.toString(false)) + ", hasDefaultValue: " + this.hasInitialExpression() + "]";
}
@Override
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 2fb02586d5..8511cdd36a 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5628,7 +5628,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
* @param samType the target type for the argument expression
* @return SAM type augmented using information from the argument expression
*/
- private static ClassNode convertClosureTypeToSAMType(final Expression expression, final ClassNode closureType, final MethodNode sam, final ClassNode samType) {
+ 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)
@@ -5636,9 +5636,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
ClassNode closureReturnType = closureType.getGenericsTypes()[0].getType();
Parameter[] parameters = sam.getParameters();
- if (parameters.length > 0
- && expression instanceof MethodPointerExpression
- && GenericsUtils.hasUnresolvedGenerics(closureReturnType)) {
+ 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);
@@ -5658,6 +5656,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
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);
}
}
}
@@ -5667,7 +5667,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
// repeat the same for each parameter given in the ClosureExpression
if (parameters.length > 0 && expression instanceof ClosureExpression) {
- return closureType; // TODO
+ 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());
@@ -5698,8 +5702,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return false;
}
for (int i = 0; i < n; i += 1) {
- // for method closure, SAM parameters act like arguments
- if (!isAssignableTo(providerTypes[i], receiverTypes[i])) {
+ // for method closure SAM parameters act like arguments
+ if (!isAssignableTo(providerTypes[i], receiverTypes[i])
+ && !providerTypes[i].isGenericsPlaceHolder()) {
return false;
}
}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 9727aa89e5..6b569a3e17 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -761,6 +761,38 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10749
+ void testReturnTypeInferenceWithMethodGenerics29() {
+ String named = 'class Named { String name }'
+
+ for (expr in ['Named.&getName', 'Named::getName', '{Named named -> named.getName()}', '(Named named) -> named.getName()']) {
+ assertScript named + """
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.toString(false) == 'java.util.stream.Collector<Named, ?, java.util.Map<java.lang.String, java.util.List<Named>>>'
+ })
+ def collector = java.util.stream.Collectors.groupingBy($expr)
+ """
+ }
+
+ // explicit type args
+ assertScript named + '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.toString(false) == 'java.util.stream.Collector<Named, ?, java.util.Map<java.lang.String, java.util.List<Named>>>'
+ })
+ def c1 = java.util.stream.Collectors.<Named,String>groupingBy(named -> named.getName())
+ // ^^^^^^^^^^^^^^
+
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.toString(false) == 'java.util.stream.Collector<Named, ?, java.util.Map<java.lang.String, Named>>'
+ })
+ def c2 = java.util.stream.Collectors.<Named,String,Named>toMap(named -> named.getName(), named -> named)
+ // ^^^^^^^^^^^^^^^^^^^^
+ '''
+ }
+
void testDiamondInferrenceFromConstructor1() {
assertScript '''
class Foo<U> {
@@ -1499,7 +1531,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
@ASTTest(phase=INSTRUCTION_SELECTION, value={
def type = node.getNodeMetaData(INFERRED_TYPE)
- assert type.toString(false) == 'C<java.lang.Object>' // TODO: String
+ assert type.toString(false) == 'C<java.lang.String>'
})
def y = new C<>((String s) -> { print(s); }) // error: Expected type Object for lambda parameter: s
'''