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 c5cee21bd6 GROOVY-11241: STC: type variable isolation for
`class::instanceMethod`
c5cee21bd6 is described below
commit c5cee21bd66909fc8ca800198c001d63849d8a77
Author: Eric Milles <[email protected]>
AuthorDate: Thu Dec 7 08:54:43 2023 -0600
GROOVY-11241: STC: type variable isolation for `class::instanceMethod`
---
.../transform/stc/StaticTypeCheckingVisitor.java | 45 ++++++++++++++--------
.../transform/stc/MethodReferenceTest.groovy | 42 ++++++++++++++++++++
2 files changed, 70 insertions(+), 17 deletions(-)
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 6cf46e2bf4..d16a333be9 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2326,6 +2326,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
: new Parameter[]{new
Parameter(receiver.redirect().getOuterClass(), "$p$"), new Parameter(MAP_TYPE,
"map")};
node = new ConstructorNode(Opcodes.ACC_PUBLIC, params,
ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
node.setDeclaringClass(receiver);
+ node.setSynthetic(true);
}
}
}
@@ -2454,6 +2455,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
if (!candidates.isEmpty()) {
int nParameters = candidates.stream().mapToInt(m ->
m.getParameters().length).reduce((i,j) -> i == j ? i : -1).getAsInt();
Map<GenericsTypeName, GenericsType> gts =
GenericsUtils.extractPlaceholders(receiverType);
+
stubMissingTypeVariables(receiverType.redirect().getGenericsTypes(), gts); //
GROOVY-11241
candidates.stream().map(candidate -> applyGenericsContext(gts,
candidate.getReturnType()))
.reduce(WideningCategories::lowestUpperBound).ifPresent(returnType -> {
ClassNode closureType =
wrapClosureType(returnType);
@@ -3672,9 +3674,10 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
visitMethodCallArguments(receiver, args(newArgumentExpressions), true,
selectedMethod);
for (int index : methodReferencePositions) {
- Expression lambdaExpression = newArgumentExpressions.get(index);
- Expression methodReferenceExpression =
argumentExpressions.get(index);
- methodReferenceExpression.putNodeMetaData(CLOSURE_ARGUMENTS,
lambdaExpression.getNodeMetaData(CLOSURE_ARGUMENTS));
+ Expression lambda = newArgumentExpressions.get(index);
+ Expression methodReference = argumentExpressions.get(index);
+ methodReference.putNodeMetaData(PARAMETER_TYPE,
lambda.getNodeMetaData(PARAMETER_TYPE));
+ methodReference.putNodeMetaData(CLOSURE_ARGUMENTS,
lambda.getNodeMetaData(CLOSURE_ARGUMENTS));
}
}
@@ -3696,7 +3699,9 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
parameters[i] = new Parameter(i == 0 ? firstParamType :
dynamicType(), "p" + i);
}
}
- return new LambdaExpression(parameters, GENERATED_EMPTY_STATEMENT);
+ LambdaExpression lambda = new LambdaExpression(parameters,
GENERATED_EMPTY_STATEMENT);
+ lambda.putNodeMetaData(INFERRED_TYPE,
methodReference.getNodeMetaData(INFERRED_TYPE));
+ return lambda;
}
/**
@@ -5510,23 +5515,29 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
extractGenericsConnectionsForBoundTypes(methodGenericTypes,
resolvedPlaceholders);
}
- for (GenericsType gt : methodGenericTypes) {
- // GROOVY-8409, GROOVY-10067, et al.: provide "no type witness"
mapping for param
- resolvedPlaceholders.computeIfAbsent(new
GenericsTypeName(gt.getName()), gtn -> {
- ClassNode hash = ClassHelper.makeWithoutCaching("#" +
gt.getName());
- hash.setRedirect(getCombinedBoundType(gt));
- hash.setGenericsPlaceHolder(true);
-
- GenericsType gtx = new GenericsType(hash,
applyGenericsContext(resolvedPlaceholders, gt.getUpperBounds()), null);
- gtx.putNodeMetaData(GenericsType.class, gt);
- gtx.setResolved(true);
- return gtx;
- });
- }
+ // GROOVY-8409, GROOVY-10067, et al.: provide "no type witness"
mappings
+ stubMissingTypeVariables(methodGenericTypes, resolvedPlaceholders);
return resolvedPlaceholders;
}
+ private static void stubMissingTypeVariables(final GenericsType[]
typeParameters, final Map<GenericsTypeName, GenericsType> resolvedPlaceholders)
{
+ if (asBoolean(typeParameters)) {
+ for (GenericsType tp : typeParameters) {
+ resolvedPlaceholders.computeIfAbsent(new
GenericsTypeName(tp.getName()), name -> {
+ ClassNode hash = ClassHelper.makeWithoutCaching("#" +
tp.getName());
+ hash.setRedirect(getCombinedBoundType(tp));
+ hash.setGenericsPlaceHolder(true);
+
+ GenericsType gtx = new GenericsType(hash,
applyGenericsContext(resolvedPlaceholders, tp.getUpperBounds()), null);
+ gtx.putNodeMetaData(GenericsType.class, tp);
+ gtx.setResolved(true);
+ return gtx;
+ });
+ }
+ }
+ }
+
/**
* Given method call like "m(Collections.emptyList())", the type of the
call
* argument is {@code List<T>} without explicit type arguments. Knowing the
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index 04ee404cf2..afebfec1a7 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -238,6 +238,48 @@ final class MethodReferenceTest {
'''
}
+ @Test // class::instanceMethod -- GROOVY-11241
+ void testFunctionCI9() {
+ assertScript shell, '''
+ @Grab('io.vavr:vavr:0.10.4')
+ import io.vavr.control.*
+
+ Option<Integer> option() { Option.of(42) }
+
+ @CompileStatic
+ Try<Integer> test() {
+ Try.of{ option() }.<Integer>mapTry(Option::get)
+ // ^^^^^^^^^
+ }
+
+ assert test().get() == 42
+ '''
+
+ def err = shouldFail shell, '''
+ @Grab('io.vavr:vavr:0.10.4')
+ import io.vavr.control.Try
+
+ class Option<X> {
+ private final X x
+ def X get() { x }
+ static <Y> Option<Y> of(Y y) {
+ new Option(x: y)
+ }
+ }
+
+ Option<Integer> option() { Option.of(666) }
+
+ @CompileStatic
+ Try<Integer> test() {
+ //Try.of { option() }.mapTry(Option::get)
+ def try_of = Try.of { option() }
+ def result = try_of.mapTry(Option::get)
+ result
+ }
+ '''
+ assert err =~ /Cannot (assign|return)
io.vavr.control.Try<java.lang.Object> / // not <X> or <Option<Integer>>
+ }
+
@Test // class::instanceMethod -- GROOVY-9974
void testPredicateCI() {
assertScript shell, '''