GROOVY-11068: closure shared variable inference
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java
index e83494f..65e9281 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java
@@ -39,7 +39,6 @@
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.tools.GenericsUtils;
 import org.codehaus.groovy.classgen.AsmClassGenerator;
-import org.codehaus.groovy.classgen.Verifier;
 import org.objectweb.asm.MethodVisitor;
 
 import java.util.HashMap;
@@ -53,8 +52,8 @@
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorSuperX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.fieldX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.getGetterName;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.nullX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
@@ -188,18 +187,19 @@
 
     protected ClassNode createClosureClass(final ClosureExpression expression, final int modifiers) {
         ClassNode classNode = controller.getClassNode();
-        ClassNode outerClass = controller.getOutermostClass();
-        String name = genClosureClassName();
+        ClassNode rootClass = controller.getOutermostClass();
+        MethodNode enclosingMethod = controller.getMethodNode();
+        String name = classNode.getName() + "$" + controller.getContext().getNextClosureInnerName(rootClass, classNode, enclosingMethod);
 
         Parameter[] parameters = expression.getParameters();
         if (parameters == null) {
             parameters = Parameter.EMPTY_ARRAY;
         } else if (parameters.length == 0) {
-            // let's create a default 'it' parameter
-            Parameter it = param(ClassHelper.OBJECT_TYPE, "it", nullX());
-            parameters = new Parameter[]{it};
-            Variable ref = expression.getVariableScope().getDeclaredVariable("it");
-            if (ref != null) it.setClosureSharedVariable(ref.isClosureSharedVariable());
+            // provide a default parameter
+            parameters = new Parameter[1];
+            parameters[0] = new Parameter(ClassHelper.OBJECT_TYPE, "it", nullX());
+            Variable decl = expression.getVariableScope().getDeclaredVariable("it");
+            if (decl != null) parameters[0].setClosureSharedVariable(decl.isClosureSharedVariable());
         }
 
         Parameter[] localVariableParams = getClosureSharedVariables(expression);
@@ -213,12 +213,12 @@
         else if (GenericsUtils.hasUnresolvedGenerics(returnType)) returnType = GenericsUtils.nonGeneric(returnType);
 
         InnerClassNode answer = new InnerClassNode(classNode, name, modifiers, ClassHelper.CLOSURE_TYPE.getPlainNodeReference());
-        answer.setEnclosingMethod(controller.getMethodNode());
+        answer.setEnclosingMethod(enclosingMethod);
         answer.setScriptBody(controller.isInScriptBody());
         answer.setSourcePosition(expression);
         answer.setStaticClass(controller.isStaticMethod() || classNode.isStaticClass());
         answer.setSynthetic(true);
-        answer.setUsingGenerics(outerClass.isUsingGenerics());
+        answer.setUsingGenerics(rootClass.isUsingGenerics());
 
         MethodNode method = answer.addMethod("doCall", ACC_PUBLIC, returnType, parameters, ClassNode.EMPTY_ARRAY, expression.getCode());
         method.setSourcePosition(expression);
@@ -248,7 +248,7 @@
         }
 
         // let's make the constructor
-        BlockStatement block = createBlockStatementForConstructor(expression, outerClass, classNode);
+        BlockStatement block = createBlockStatementForConstructor(expression, rootClass, classNode);
 
         // let's assign all the parameter fields from the outer context
         addFieldsAndGettersForLocalVariables(answer, localVariableParams);
@@ -262,8 +262,8 @@
 
     protected ConstructorNode addConstructor(final ClosureExpression expression, final Parameter[] localVariableParams, final InnerClassNode answer, final BlockStatement block) {
         Parameter[] params = new Parameter[2 + localVariableParams.length];
-        params[0] = param(ClassHelper.OBJECT_TYPE, OUTER_INSTANCE);
-        params[1] = param(ClassHelper.OBJECT_TYPE, THIS_OBJECT);
+        params[0] = new Parameter(ClassHelper.OBJECT_TYPE, OUTER_INSTANCE);
+        params[1] = new Parameter(ClassHelper.OBJECT_TYPE, THIS_OBJECT);
         System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
 
         ConstructorNode constructorNode = answer.addConstructor(ACC_PUBLIC, params, ClassNode.EMPTY_ARRAY, block);
@@ -272,32 +272,29 @@
         return constructorNode;
     }
 
-    protected void addFieldsAndGettersForLocalVariables(final InnerClassNode answer, final Parameter[] localVariableParams) {
+    protected void addFieldsAndGettersForLocalVariables(final InnerClassNode closureClass, final Parameter[] localVariableParams) {
         for (Parameter param : localVariableParams) {
-            String paramName = param.getName();
-            ClassNode type = param.getType();
+            String     paramName = param.getName();
+            ClassNode  paramType = param.getType();
+
             VariableExpression initialValue = varX(paramName);
             initialValue.setAccessedVariable(param);
             initialValue.setUseReferenceDirectly(true);
-            ClassNode realType = type;
-            type = ClassHelper.makeReference();
             param.setType(ClassHelper.makeReference());
-            FieldNode paramField = answer.addField(paramName, ACC_PRIVATE | ACC_SYNTHETIC, type, initialValue);
+
+            FieldNode paramField = closureClass.addField(paramName, ACC_PRIVATE | ACC_SYNTHETIC, param.getType(), initialValue);
             paramField.setOriginType(ClassHelper.getWrapper(param.getOriginType()));
             paramField.setHolder(true);
-            String methodName = Verifier.capitalize(paramName);
 
-            // let's add a getter & setter
-            Expression fieldExp = fieldX(paramField);
-            markAsGenerated(answer,
-                    answer.addMethod(
-                            "get" + methodName,
-                            ACC_PUBLIC,
-                            realType.getPlainNodeReference(),
-                            Parameter.EMPTY_ARRAY,
-                            ClassNode.EMPTY_ARRAY,
-                            returnS(fieldExp)),
-                    true);
+            MethodNode getMethod = closureClass.addMethod(
+                getGetterName(paramName),
+                ACC_PUBLIC,
+                paramType.getPlainNodeReference(),
+                Parameter.EMPTY_ARRAY,
+                ClassNode.EMPTY_ARRAY,
+                returnS(fieldX(paramField))
+            );
+            markAsGenerated(closureClass, getMethod, true);
         }
     }
 
@@ -316,15 +313,6 @@
         return block;
     }
 
-    private String genClosureClassName() {
-        ClassNode classNode = controller.getClassNode();
-        ClassNode outerClass = controller.getOutermostClass();
-        MethodNode methodNode = controller.getMethodNode();
-
-        return classNode.getName() + "$"
-                + controller.getContext().getNextClosureInnerName(outerClass, classNode, methodNode);
-    }
-
     protected static class CorrectAccessedVariableVisitor extends CodeVisitorSupport {
         private InnerClassNode icn;
 
@@ -359,7 +347,7 @@
     protected static void removeInitialValues(final Parameter[] params) {
         for (int i = 0; i < params.length; i++) {
             if (params[i].hasInitialExpression()) {
-                Parameter p = param(params[i].getType(), params[i].getName());
+                Parameter p = new Parameter(params[i].getType(), params[i].getName());
                 p.setOriginType(p.getOriginType());
                 params[i] = p;
             }
@@ -384,26 +372,29 @@
         arguments.getExpression(1).visit(acg);
         operandStack.box();
         //TODO: replace with normal String, p not needed
-        Parameter p = param(ClassHelper.OBJECT_TYPE, "_p");
+        Parameter p = new Parameter(ClassHelper.OBJECT_TYPE, "_p");
         String descriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, new Parameter[]{p, p});
         mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor, false);
         operandStack.remove(2);
         return true;
     }
 
-    protected Parameter[] getClosureSharedVariables(final ClosureExpression ce) {
-        VariableScope scope = ce.getVariableScope();
-        Parameter[] ret = new Parameter[scope.getReferencedLocalVariablesCount()];
-        int index = 0;
-        for (Iterator<Variable> iter = scope.getReferencedLocalVariablesIterator(); iter.hasNext(); ) {
-            Variable element = iter.next();
-            Parameter p = param(element.getType(), element.getName());
-            p.setOriginType(element.getOriginType());
-            p.setClosureSharedVariable(element.isClosureSharedVariable());
-            ret[index] = p;
-            index++;
+    protected Parameter[] getClosureSharedVariables(final ClosureExpression expression) {
+        ClassNode classNode = controller.getClassNode();
+        TypeChooser typeChooser = controller.getTypeChooser();
+        VariableScope variableScope = expression.getVariableScope();
+
+        Parameter[] refs = new Parameter[variableScope.getReferencedLocalVariablesCount()]; int index = 0;
+        for (Iterator<Variable> iter = variableScope.getReferencedLocalVariablesIterator(); iter.hasNext(); ) {
+            Variable variable = iter.next();
+
+            ClassNode inferenceType = typeChooser.resolveType(varX(variable), classNode); // GROOVY-11068
+            Parameter p = new Parameter(inferenceType, variable.getName());
+            p.setClosureSharedVariable(variable.isClosureSharedVariable());
+
+            refs[index++] = p;
         }
-        return ret;
+        return refs;
     }
 
     protected void loadThis() {
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index 0d3eead..58ecb3d 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -356,6 +356,31 @@
         '''
     }
 
+    @Test // instance::instanceMethod -- GROOVY-11068
+    void testConsumerII4() {
+        assertScript shell, '''
+            @Grab('org.apache.pdfbox:pdfbox:2.0.28')
+            import org.apache.pdfbox.pdmodel.*
+            @Grab('io.vavr:vavr:0.10.4')
+            import io.vavr.control.Try
+
+            @CompileStatic
+            def test(List<PDDocument> docs) {
+                docs.each { doc ->
+                    extraPages().forEach {
+                        it.forEach(doc::addPage) // expect operand PDDocument
+                    }
+                }
+            }
+
+            Try<Iterable<PDPage>> extraPages() {
+                Try.success([new PDPage()])
+            }
+
+            test([new PDDocument()])
+        '''
+    }
+
     @Test // instance::instanceMethod -- GROOVY-9813
     void testFunctionII() {
         String asList = '''