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'
+ '''
+ }
}