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 05a116688d GROOVY-10602: fix dropped parameter detection
05a116688d is described below

commit 05a116688df321a187966b0e7234edd024bd40f4
Author: Eric Milles <[email protected]>
AuthorDate: Tue Aug 8 11:12:41 2023 -0500

    GROOVY-10602: fix dropped parameter detection
---
 .../codehaus/groovy/ast/CodeVisitorSupport.java    |  8 +++-
 .../groovy/classgen/VariableScopeVisitor.java      | 49 +++++++++-------------
 .../org/codehaus/groovy/classgen/Verifier.java     | 15 ++++---
 .../groovy/classgen/asm/ClosureWriter.java         |  4 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   | 12 +++---
 .../stc/ClosureParamTypeInferenceSTCTest.groovy    | 40 +++++++++++++-----
 .../stc/ClosureParamTypeResolverSTCTest.groovy     | 43 -------------------
 .../groovy/transform/stc/ClosuresSTCTest.groovy    | 25 +++++++++--
 8 files changed, 93 insertions(+), 103 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java 
b/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
index f0e17fd460..44b238f723 100644
--- a/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
+++ b/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
@@ -141,7 +141,7 @@ public abstract class CodeVisitorSupport implements 
GroovyCodeVisitor {
     }
 
     @Override
-    public void visitCatchStatement(CatchStatement statement) {
+    public void visitCatchStatement(final CatchStatement statement) {
         statement.getCode().visit(this);
     }
 
@@ -257,6 +257,12 @@ public abstract class CodeVisitorSupport implements 
GroovyCodeVisitor {
 
     @Override
     public void visitClosureExpression(ClosureExpression expression) {
+        if (expression.isParameterSpecified()) {
+            for (Parameter parameter : expression.getParameters()) {
+                if (parameter.hasInitialExpression())
+                    parameter.getInitialExpression().visit(this);
+            }
+        }
         expression.getCode().visit(this);
     }
 
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java 
b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index a81c8f28c7..67338d8809 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -131,17 +131,20 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
     }
 
     private void declare(final Variable variable, final ASTNode context) {
-        String scopeType = "scope";
-        String variableType = "variable";
+        if (PlaceholderVisitor.isPlaceholder((ASTNode) variable)) {
+            return;
+        }
 
+        String scopeType    = "scope";
+        String variableType = "variable";
         if (context.getClass() == FieldNode.class) {
-            scopeType = "class";
+            scopeType    = "class";
             variableType = "field";
         } else if (context.getClass() == PropertyNode.class) {
-            scopeType = "class";
+            scopeType    = "class";
             variableType = "property";
         } else if (context.getClass() == ClosureExpression.class) {
-            scopeType = "parameter list";
+            scopeType    = "parameter list";
             variableType = "parameter";
         }
 
@@ -150,11 +153,6 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
         msg.append(" already contains a ").append(variableType);
         msg.append(" of the name ").append(variable.getName());
 
-        if (PlaceholderVisitor.isPlaceholder(context) ||
-            (variable instanceof Parameter && 
PlaceholderVisitor.isPlaceholder((Parameter) variable))) {
-            return;
-        }
-
         if (currentScope.getDeclaredVariable(variable.getName()) != null) {
             addError(msg.toString(), context);
             return;
@@ -348,15 +346,11 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
                     addError("Cannot refer to the static enum field '" + 
variable.getName() + "' within an initializer", expression);
                 }
             }
-            return;
+        } else if (currentScope.isInStaticContext()) {
+            // declare a static variable to be able to continue the check
+            currentScope.putDeclaredVariable(new 
DynamicVariable(variable.getName(), currentScope.isInStaticContext()));
+            addError(variable.getName() + " is declared in a dynamic context, 
but you tried to access it from a static context.", expression);
         }
-
-        if (!currentScope.isInStaticContext()) return;
-
-        addError(variable.getName() + " is declared in a dynamic context, but 
you tried to access it from a static context.", expression);
-
-        // declare a static variable to be able to continue the check
-        currentScope.putDeclaredVariable(new 
DynamicVariable(variable.getName(), currentScope.isInStaticContext()));
     }
 
     
//--------------------------------------------------------------------------
@@ -487,20 +481,16 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
         if (expression.isParameterSpecified()) {
             for (Parameter parameter : expression.getParameters()) {
                 parameter.setInStaticContext(currentScope.isInStaticContext());
-                if (parameter.hasInitialExpression()) {
-                    parameter.getInitialExpression().visit(this);
-                }
                 declare(parameter, expression);
             }
         } else if (expression.getParameters() != null) {
-            Parameter var = new Parameter(ClassHelper.dynamicType(), "it");
-            var.setInStaticContext(currentScope.isInStaticContext());
-            currentScope.putDeclaredVariable(var);
+            Parameter implicit = new Parameter(ClassHelper.dynamicType(), 
"it");
+            implicit.setInStaticContext(currentScope.isInStaticContext());
+            currentScope.putDeclaredVariable(implicit);
         }
 
         super.visitClosureExpression(expression);
         markClosureSharedVariables();
-
         popState();
     }
 
@@ -610,9 +600,10 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
 
     @Override
     public void visitVariableExpression(final VariableExpression expression) {
-        Variable variable = findVariableDeclaration(expression.getName());
-        if (variable == null) return;
-        expression.setAccessedVariable(variable);
-        checkVariableContextAccess(variable, expression);
+        var variable = findVariableDeclaration(expression.getName());
+        if (variable != null) {
+            expression.setAccessedVariable(variable);
+            checkVariableContextAccess(variable, expression);
+        }
     }
 }
diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java 
b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index 404f49fd56..2b017ab41b 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -581,12 +581,12 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
         }
     }
 
-    // for binary compatibility only, don't use or override this
+    @Deprecated // for binary compatibility only; do not use or override
     protected void addMethod$$bridge(final ClassNode node, final boolean 
shouldBeSynthetic, final String name, final int modifiers, final ClassNode 
returnType, final Parameter[] parameters, final ClassNode[] exceptions, final 
Statement code) {
         addMethod(node, shouldBeSynthetic, name, modifiers, returnType, 
parameters, exceptions, code);
     }
 
-    @Deprecated
+    @Deprecated(since = "2.4.0")
     protected void addTimeStamp(final ClassNode node) {
     }
 
@@ -881,16 +881,16 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
 
                 @Override
                 public void visitClosureExpression(final ClosureExpression e) {
-                    boolean prev = inClosure; inClosure = true;
+                    boolean saved = inClosure; inClosure = true;
                     super.visitClosureExpression(e);
-                    inClosure = prev;
+                    inClosure = saved;
                 }
 
                 @Override
                 public void visitVariableExpression(final VariableExpression 
e) {
                     if (e.getAccessedVariable() instanceof Parameter) {
                         Parameter p = (Parameter) e.getAccessedVariable();
-                        if (p.hasInitialExpression() && 
!Arrays.asList(params).contains(p)) {
+                        if (!Arrays.asList(params).contains(p) && 
Arrays.asList(method.getParameters()).contains(p)) { // GROOVY-10602
                             VariableScope blockScope = 
block.getVariableScope();
                             VariableExpression localVariable = 
(VariableExpression) blockScope.getDeclaredVariable(p.getName());
                             if (localVariable == null) {
@@ -1039,9 +1039,9 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
 
     protected void addDefaultParameters(final DefaultArgsAction action, final 
MethodNode method) {
         Parameter[] parameters = method.getParameters();
-        long n = 
Arrays.stream(parameters).filter(Parameter::hasInitialExpression).count();
 
-        for (int i = 1; i <= n; i += 1) {
+        var n = 
Arrays.stream(parameters).filter(Parameter::hasInitialExpression).count();
+        for (int i = 1; i <= n; i += 1) { // drop parameters with value from 
right to left
             Parameter[] newParams = new Parameter[parameters.length - i];
             ArgumentListExpression arguments = new ArgumentListExpression();
             int index = 0;
@@ -1057,7 +1057,6 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
                         newParams[index++] = parameter;
                         e = varX(parameter);
                     }
-
                     arguments.addExpression(castX(parameter.getType(), e));
 
                     if (parameter.hasInitialExpression()) j += 1;
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 65e9281071..eb9e2fc613 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java
@@ -107,8 +107,8 @@ public class ClosureWriter {
         mv.visitTypeInsn(NEW, closureClassinternalName);
         mv.visitInsn(DUP);
         if (controller.isStaticMethod() || 
compileStack.isInSpecialConstructorCall()) {
-            (new ClassExpression(classNode)).visit(acg);
-            (new ClassExpression(controller.getOutermostClass())).visit(acg);
+            new ClassExpression(classNode).visit(acg);
+            new ClassExpression(controller.getOutermostClass()).visit(acg);
         } else {
             mv.visitVarInsn(ALOAD, 0);
             controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
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 021a2e31be..7a82c4a98c 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -239,8 +239,8 @@ import static 
org.codehaus.groovy.ast.tools.WideningCategories.isIntCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
 import static 
org.codehaus.groovy.ast.tools.WideningCategories.isNumberCategory;
 import static 
org.codehaus.groovy.ast.tools.WideningCategories.lowestUpperBound;
-import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
-import static org.codehaus.groovy.runtime.DefaultGroovyMethods.init;
+import static org.codehaus.groovy.runtime.ArrayGroovyMethods.asBoolean;
+import static org.codehaus.groovy.runtime.ArrayGroovyMethods.init;
 import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last;
 import static org.codehaus.groovy.syntax.Types.ASSIGN;
 import static org.codehaus.groovy.syntax.Types.COMPARE_EQUAL;
@@ -2438,7 +2438,7 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
         } else {
             typeCheckingContext.delegationMetadata = 
newDelegationMetadata(typeCheckingContext.getEnclosingClassNode(), 
Closure.OWNER_FIRST);
         }
-        super.visitClosureExpression(expression);
+        expression.getCode().visit(this);
         typeCheckingContext.delegationMetadata = 
typeCheckingContext.delegationMetadata.getParent();
 
         returnAdder.visitMethod(new MethodNode("dummy", 0, OBJECT_TYPE, 
Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, expression.getCode()));
@@ -2932,6 +2932,7 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
                             LambdaExpression lambda = 
constructLambdaExpressionForMethodReference(
                                                         targetType, 
(MethodReferenceExpression) expression);
                             inferClosureParameterTypes(receiver, arguments, 
lambda, target, selectedMethod);
+                            expression.putNodeMetaData(PARAMETER_TYPE, 
lambda.getNodeMetaData(PARAMETER_TYPE));
                             expression.putNodeMetaData(CLOSURE_ARGUMENTS, 
lambda.getNodeMetaData(CLOSURE_ARGUMENTS));
                         } else {
                             addError("The argument is a method reference, but 
the parameter type is not a functional interface", expression);
@@ -3084,8 +3085,7 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
                     Expression emc = 
typeCheckingContext.getEnclosingMethodCall();
                     if (emc instanceof MethodCallExpression) {
                         MethodCallExpression mce = (MethodCallExpression) emc;
-                        if (mce.getArguments() == arguments // GROOVY-10807 ::
-                            || expression.getCode() == 
GENERATED_EMPTY_STATEMENT){
+                        if (mce.getArguments() == arguments) {
                             GenericsType[] typeArguments = 
mce.getGenericsTypes();
                             if (typeArguments != null) {
                                 int n = typeParameters.length;
@@ -4395,7 +4395,7 @@ out:                if (mn.size() != 1) {
                 assignedTypes.add(cn);
             }
             List<ClassNode> temporaryTypesForExpression = 
getTemporaryTypesForExpression(var);
-            if (asBoolean(temporaryTypesForExpression)) {
+            if (temporaryTypesForExpression != null) {
                 // a type inference has been made on a variable whose type was 
defined in an instanceof block
                 // erase available information with the new type
                 temporaryTypesForExpression.clear();
diff --git 
a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy 
b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index d120383055..b99bdd63c1 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -228,15 +228,16 @@ class ClosureParamTypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
     // GROOVY-7789
     void testFromStringWithTypeParameter4() {
         assertScript '''
-            class Monad<T> {  private final Closure c
-                Monad(@ClosureParams(value=FromString, options='T') Closure c) 
{
+            class Monad<T> {
+                private final Closure c
+                Monad(@ClosureParams(value=FromString, options="T") Closure c) 
{
                     this.c = c
                 }
                 def call(T t) {
                     c.call(t)
                 }
             }
-            def <U> Monad<U> wrap(@ClosureParams(value=FromString, 
options='U') Closure c) {
+            def <U> Monad<U> wrap(@ClosureParams(value=FromString, 
options="U") Closure c) {
                 new Monad<>(c)
             }
             def list_size = this.<List>wrap({ list -> list.size() })
@@ -247,7 +248,7 @@ class ClosureParamTypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
     void testFromStringWithTypeParameterFromClass() {
         assertScript '''
             class Foo<T> {
-                void 
foo(@ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { 
cl.call(['hey','ya']) }
+                void foo(@ClosureParams(value=FromString, 
options="java.util.List<T>") Closure cl) { cl.call(['hey','ya']) }
             }
             def foo = new Foo<String>()
             foo.foo { List<String> str -> str.each { println it.toUpperCase() 
} }
@@ -257,7 +258,7 @@ class ClosureParamTypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
     void testFromStringWithTypeParameterFromClassWithTwoGenerics() {
         assertScript '''
             class Foo<T,U> {
-                void 
foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { 
cl.call(['hey','ya']) }
+                void foo(@ClosureParams(value=FromString, 
options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) }
             }
             def foo = new Foo<Integer,String>()
             foo.foo { List<String> str -> str.each { println it.toUpperCase() 
} }
@@ -267,7 +268,7 @@ class ClosureParamTypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
     void 
testFromStringWithTypeParameterFromClassWithTwoGenericsAndNoExplicitSignature() 
{
         assertScript '''
             class Foo<T,U> {
-                public void 
foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { 
cl.call(['hey','ya']) }
+                public void foo(@ClosureParams(value=FromString, 
options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) }
             }
             def foo = new Foo<Integer,String>()
             foo.foo { it.each { println it.toUpperCase() } }
@@ -277,7 +278,7 @@ class ClosureParamTypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
     void 
testFromStringWithTypeParameterFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQN()
 {
         assertScript '''
             class Foo<T,U> {
-                public void 
foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { 
cl.call(['hey','ya']) }
+                public void foo(@ClosureParams(value=FromString, 
options="List<U>") Closure cl) { cl.call(['hey','ya']) }
             }
             def foo = new Foo<Integer,String>()
             foo.foo { it.each { println it.toUpperCase() } }
@@ -292,7 +293,7 @@ class ClosureParamTypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
                 }
             }
             class Tor<D,U> {
-                public void 
foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { 
cl.call([new Foo(), new Foo()]) }
+                public void foo(@ClosureParams(value=FromString, 
options="List<U>") Closure cl) { cl.call([new Foo(), new Foo()]) }
             }
             def tor = new Tor<Integer,Foo>()
             tor.foo { it.each { it.bar() } }
@@ -307,7 +308,7 @@ class ClosureParamTypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
                 }
             }
             class Tor<D,U> {
-                public void 
foo(@ClosureParams(value=FromString,options=["D,List<U>"]) Closure cl) { 
cl.call(3, [new Foo(), new Foo()]) }
+                public void foo(@ClosureParams(value=FromString, 
options=["D,List<U>"]) Closure cl) { cl.call(3, [new Foo(), new Foo()]) }
             }
             def tor = new Tor<Integer,Foo>()
             tor.foo { r, e -> r.times { e.each { it.bar() } } }
@@ -322,7 +323,7 @@ class ClosureParamTypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
                 }
             }
             class Tor<D,U> {
-                public void 
foo(@ClosureParams(value=FromString,options=["D,List<U>", "D"]) Closure cl) {
+                public void foo(@ClosureParams(value=FromString, 
options=["D,List<U>","D"]) Closure cl) {
                     if (cl.maximumNumberOfParameters==2) {
                         cl.call(3, [new Foo(), new Foo()])
                     } else {
@@ -336,6 +337,25 @@ class ClosureParamTypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
         '''
     }
 
+    void testFromStringWithConflictResolutionStrategy() {
+        assertScript '''
+            def transform(value, @ClosureParams(value=FromString, 
options=["Integer","String"], conflictResolutionStrategy=PickFirstResolver) 
Closure condition) {
+                if (condition.parameterTypes[0].simpleName == 'String') {
+                    condition(value.toString())
+                } else {
+                    condition(value instanceof Integer ? value : 
value.toString().size())
+                }
+            }
+
+            assert transform('dog') { String s -> s * 2 } == 'dogdog'
+            assert transform('dog') { Integer i -> i * 2 } == 6
+            assert transform('dog') { it.class.simpleName[0..it] } == 'Inte'
+            assert transform(35) { String s -> s * 2 } == '3535'
+            assert transform(35) { Integer i -> i * 2 } == 70
+            assert transform(35) { it * 2 } == 70
+        '''
+    }
+
     // GROOVY-6939
     void testParamCountCheck1() {
         shouldFailWithMessages '''
diff --git 
a/src/test/groovy/transform/stc/ClosureParamTypeResolverSTCTest.groovy 
b/src/test/groovy/transform/stc/ClosureParamTypeResolverSTCTest.groovy
deleted file mode 100644
index 7cc2e3bfc1..0000000000
--- a/src/test/groovy/transform/stc/ClosureParamTypeResolverSTCTest.groovy
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.transform.stc
-/**
- * Unit tests for static type checking : closure parameter type resolution
- */
-class ClosureParamTypeResolverSTCTest extends StaticTypeCheckingTestCase {
-    void testInferenceForDGM_CollectUsingExplicitIt() {
-        assertScript '''
-            import groovy.transform.stc.*
-
-            def transform(item, @ClosureParams(value=FromString, 
conflictResolutionStrategy=PickFirstResolver, options=["Integer", "String"]) 
Closure condition) {
-              if (condition.parameterTypes[0].simpleName == 'String')
-                condition(item instanceof String ? item : item.toString())
-              else
-                condition(item instanceof Integer ? item : 
item.toString().size())
-            }
-
-            assert transform('dog') { String s -> s * 2 } == 'dogdog'
-            assert transform('dog') { Integer i -> i * 2 } == 6
-            assert transform('dog') { it.class.simpleName[0..it] } == 'Inte'
-            assert transform(35) { String s -> s * 2 } == '3535'
-            assert transform(35) { Integer i -> i * 2 } == 70
-            assert transform(35) { it * 2 } == 70
-        '''
-    }
-}
diff --git a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy 
b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
index 8ced1aad5d..5cf52fca22 100644
--- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -43,7 +43,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
     void testCallClosure3() {
         shouldFailWithMessages '''
             def c = { -> }
-            c('')
+            c("")
         ''',
         'Cannot call closure that accepts [] with [java.lang.String]'
     }
@@ -443,14 +443,14 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testRecurseClosureCallAsAMethod() {
+    void testRecurseClosureCallAsMethod() {
         assertScript '''
             Closure<Integer> cl
             cl = { int x -> x == 0 ? x : 1+cl(x-1) }
         '''
     }
 
-    void testFibClosureCallAsAMethod() {
+    void testFibClosureCallAsMethod() {
         assertScript '''
             Closure<Integer> fib
             fib = { int x-> x<1?x:fib(x-1)+fib(x-2) }
@@ -458,7 +458,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testFibClosureCallAsAMethodFromWithinClass() {
+    void testFibClosureCallAsMethodFromWithinClass() {
         assertScript '''
             class FibUtil {
                 private Closure<Integer> fibo
@@ -846,4 +846,21 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         'Cannot assign value of type java.lang.Class<java.lang.Integer> to 
variable of type int',
         "named param 'bar' has type 'java.lang.Class<java.lang.Number>' but 
expected 'java.lang.Number'"
     }
+
+    // GROOVY-10602
+    void testMethodAndClosureParametersDefaultArguments() {
+        assertScript '''import java.util.function.*
+            String test(Closure one = { p ->
+                Closure two = { Supplier s = { -> p } ->
+                    s.get()
+                }
+                two()
+            }) {
+                one('foo')
+            }
+
+            String result = test()
+            assert result == 'foo'
+        '''
+    }
 }

Reply via email to