GROOVY-11364: STC: propagate receiver generics to candidate return types
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 5b04334..7d609f5 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2584,8 +2584,17 @@
                     receiverType = GenericsUtils.parameterizeType(arguments[0], receiverType); // GROOVY-11241
                 }
 
-                Map<GenericsTypeName, GenericsType> gts = GenericsUtils.extractPlaceholders(receiverType);
-                candidates.stream().map(candidate -> applyGenericsContext(gts, candidate.getReturnType()))
+                ClassNode ownerType = receiverType;
+                candidates.stream()
+                        .map(candidate -> {
+                            ClassNode returnType = candidate.getReturnType();
+                            if (!candidate.isStatic() && GenericsUtils.hasUnresolvedGenerics(returnType)) {
+                                Map<GenericsTypeName, GenericsType> spec = new HashMap<>(); // GROOVY-11364
+                                extractGenericsConnections(spec, ownerType, candidate.getDeclaringClass());
+                                returnType = applyGenericsContext(spec, returnType);
+                            }
+                            return returnType;
+                        })
                         .reduce(WideningCategories::lowestUpperBound).ifPresent(returnType -> {
                             ClassNode closureType = wrapClosureType(returnType);
                             storeType(expression, closureType);
@@ -2603,7 +2612,7 @@
                     ClassNode[] parameters = collateMethodReferenceParameterTypes(expression, candidates.get(0));
                     for (int i = 0; i < arguments.length; i += 1) {
                         ClassNode at = arguments[i];
-                        ClassNode pt = applyGenericsContext(gts, parameters[Math.min(i, parameters.length - 1)]);
+                        ClassNode pt = parameters[Math.min(i, parameters.length - 1)];
                         if (!pt.equals(at) && (at.isInterface() ? pt.implementsInterface(at) : pt.isDerivedFrom(at)))
                             arguments[i] = pt; // GROOVY-10734, GROOVY-10807, GROPOVY-11026: expected type is refined
                     }
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index a75a3f5..1fc2833 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -38,7 +38,7 @@
     void testFunction() {
         assertScript shell, '''
             def f() {
-                [1, 2, 3].stream().map(e -> e + 1).collect(Collectors.toList())
+                [1, 2, 3].stream().map(i -> i + 1).toList()
             }
             assert f() == [2, 3, 4]
         '''
@@ -48,27 +48,50 @@
     void testFunction2() {
         assertScript shell, '''
             def f() {
-                [1, 2, 3].stream().map(e -> e.plus(1)).collect(Collectors.toList())
+                [1, 2, 3].stream().map(i -> i.plus(1)).toList()
             }
             assert f() == [2, 3, 4]
         '''
     }
 
     @Test
-    void testFunctionWithTypeArgument() {
+    void testFunction3() {
         assertScript shell, '''
             def f() {
-                [1, 2, 3].stream().<String>map(i -> null).collect(Collectors.toList())
+                [1, 2, 3].stream().<String>map(i -> null).toList()
             }
             assert f() == [null, null, null]
         '''
     }
 
+    // GROOVY-11364
+    @Test
+    void testFunction4() {
+        assertScript shell, '''
+            abstract class A<N extends Number> {
+                protected N process(N n) { n }
+            }
+
+            class C extends A<Integer> {
+                static void consume(Optional<Integer> option) {
+                    def result = option.orElse(null)
+                    assert result instanceof Integer
+                    assert result == 42
+                }
+                void test() {
+                    consume(Optional.of(42).map(i -> process(i)))
+                }
+            }
+
+            new C().test()
+        '''
+    }
+
     @Test
     void testBinaryOperator() {
         assertScript shell, '''
             def f() {
-                [1, 2, 3].stream().reduce(7, (Integer r, Integer e) -> r + e)
+                [1, 2, 3].stream().reduce(7, (Integer r, Integer i) -> r + i)
             }
             assert f() == 13
         '''
@@ -79,7 +102,7 @@
     void testBinaryOperatorWithoutExplicitTypes() {
         assertScript shell, '''
             def f() {
-                [1, 2, 3].stream().reduce(7, (r, e) -> r + e)
+                [1, 2, 3].stream().reduce(7, (r, i) -> r + i)
             }
             assert f() == 13
         '''
@@ -89,7 +112,7 @@
     void testBinaryOperatorWithoutExplicitTypes2() {
         assertScript shell, '''
             def f() {
-                BinaryOperator<Integer> accumulator = (r, e) -> r + e
+                BinaryOperator<Integer> accumulator = (r, i) -> r + i
                 return [1, 2, 3].stream().reduce(7, accumulator)
             }
             assert f() == 13
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index 1ebe929..3aac78c 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -613,6 +613,29 @@
         '''
     }
 
+    @Test // instance::instanceMethod -- GROOVY-11364
+    void testFunctionII5() {
+        assertScript shell, '''
+            abstract class A<N extends Number> {
+                protected N process(N n) { n }
+            }
+
+            @CompileStatic
+            class C extends A<Integer> {
+                static void consume(Optional<Integer> option) {
+                    def result = option.orElse(null)
+                    assert result instanceof Integer
+                    assert result == 42
+                }
+                void test() {
+                    consume(Optional.of(42).map(this::process))
+                }
+            }
+
+            new C().test()
+        '''
+    }
+
     @Test // instance::instanceMethod -- GROOVY-10057
     void testPredicateII() {
         assertScript shell, '''