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, '''

Reply via email to