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 f8663922b6 GROOVY-10602: fix dropped parameter detection
f8663922b6 is described below
commit f8663922b64e544011bc5c7b8684c76618fcc68f
Author: Eric Milles <[email protected]>
AuthorDate: Tue Aug 8 11:12:41 2023 -0500
GROOVY-10602: fix dropped parameter detection
4_0_X backport
---
.../groovy/classgen/VariableScopeVisitor.java | 34 ++++++++---------
.../org/codehaus/groovy/classgen/Verifier.java | 6 +--
.../stc/ClosureParamTypeInferenceSTCTest.groovy | 32 +++++++++++++---
.../stc/ClosureParamTypeResolverSTCTest.groovy | 43 ----------------------
.../groovy/transform/stc/ClosuresSTCTest.groovy | 25 +++++++++++--
5 files changed, 65 insertions(+), 75 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index 29d8517a07..53d3023378 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -130,15 +130,17 @@ public class VariableScopeVisitor extends
ClassCodeVisitorSupport {
}
private void declare(final Variable variable, final ASTNode context) {
- String scopeType = "scope";
+ 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";
+ variableType = "parameter";
}
StringBuilder msg = new StringBuilder();
@@ -339,15 +341,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()));
}
//--------------------------------------------------------------------------
@@ -478,20 +476,18 @@ 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);
+ if (parameter.hasInitialExpression())
+ parameter.getInitialExpression().visit(this);
}
} 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();
}
diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index db78827edf..986f29744c 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -908,16 +908,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) {
diff --git
a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index 74f02ee953..6366dceb81 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -230,15 +230,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() })
@@ -249,7 +250,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()
} }
@@ -259,7 +260,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()
} }
@@ -324,7 +325,7 @@ class ClosureParamTypeInferenceSTCTest extends
StaticTypeCheckingTestCase {
}
}
class Tor<D,U> {
- void foo(@ClosureParams(value=FromString,
options=["D,List<U>", "D"]) Closure c) {
+ void foo(@ClosureParams(value=FromString,
options=["D,List<U>","D"]) Closure c) {
if (c.maximumNumberOfParameters==2) {
c.call(3, [new Foo(), new Foo()])
} else {
@@ -338,6 +339,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
@NotYetImplemented
void testParamCountCheck1() {
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 59dcc42570..19785b01a2 100644
--- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -40,7 +40,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
void testCallClosure3() {
shouldFail MissingMethodException, '''
def c = { -> }
- c('')
+ c("")
'''
}
@@ -418,14 +418,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) }
@@ -433,7 +433,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testFibClosureCallAsAMethodFromWithinClass() {
+ void testFibClosureCallAsMethodFromWithinClass() {
assertScript '''
class FibUtil {
private Closure<Integer> fibo
@@ -821,4 +821,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'
+ '''
+ }
}