You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/09/09 01:48:44 UTC
[groovy] branch master updated: GROOVY-6939, GROOVY-8499, GROOVY-8816: STC: closure/lambda param count
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 ea34146709 GROOVY-6939, GROOVY-8499, GROOVY-8816: STC: closure/lambda param count
ea34146709 is described below
commit ea34146709b5f1afec9d84b00c2311f0bb5c8d89
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Sep 8 18:51:41 2022 -0500
GROOVY-6939, GROOVY-8499, GROOVY-8816: STC: closure/lambda param count
---
.../codehaus/groovy/ast/tools/GenericsUtils.java | 17 +--
.../groovy/runtime/DefaultGroovyMethods.java | 18 +--
.../transform/stc/StaticTypeCheckingVisitor.java | 80 ++++++------
src/test/groovy/bugs/Groovy8816.groovy | 39 ------
src/test/groovy/bugs/Groovy9413.groovy | 34 +++--
.../stc/ClosureParamTypeInferenceSTCTest.groovy | 145 ++++++++++++++++-----
src/test/groovy/transform/stc/Groovy8247Bug.groovy | 36 -----
.../groovy/console/ui/text/AutoIndentAction.groovy | 12 +-
.../provider/collection/runtime/NamedTuple.groovy | 21 +--
9 files changed, 208 insertions(+), 194 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 2c5fc7bac6..19926328ec 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -639,15 +639,16 @@ public class GenericsUtils {
// the returned node is DummyNode<Param1, Param2, Param3, ...)
ClassNode dummyNode = dummyDeclaration.getLeftExpression().getType();
GenericsType[] dummyNodeGenericsTypes = dummyNode.getGenericsTypes();
- if (dummyNodeGenericsTypes == null) {
- return null;
- }
- ClassNode[] signature = new ClassNode[dummyNodeGenericsTypes.length];
- for (int i = 0, n = dummyNodeGenericsTypes.length; i < n; i += 1) {
- final GenericsType genericsType = dummyNodeGenericsTypes[i];
- signature[i] = resolveClassNode(sourceUnit, compilationUnit, mn, usage, genericsType.getType());
+ if (dummyNodeGenericsTypes != null) {
+ int n = dummyNodeGenericsTypes.length;
+ ClassNode[] signature = new ClassNode[n];
+ for (int i = 0; i < n; i += 1) {
+ GenericsType genericsType = dummyNodeGenericsTypes[i];
+ signature[i] = genericsType.isWildcard() ? ClassHelper.dynamicType()
+ : resolveClassNode(sourceUnit, compilationUnit, mn, usage, genericsType.getType());
+ }
+ return signature;
}
- return signature;
} catch (Exception | LinkageError e) {
sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
}
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 8af9eb325d..6d31ecf1fe 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -2213,7 +2213,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* @return the self Object
* @since 1.0
*/
- public static <T> T each(T self, Closure closure) {
+ public static <T> T each(T self, @ClosureParams(value=FromString.class, options="?") Closure closure) {
each(InvokerHelper.asIterator(self), closure);
return self;
}
@@ -2260,10 +2260,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* @return the self Object
* @since 1.0
*/
- public static <T> T eachWithIndex(T self, /*@ClosureParams(value=FromString.class, options="?,Integer")*/ Closure closure) {
+ public static <T> T eachWithIndex(T self, @ClosureParams(value=FromString.class, options="?,Integer") Closure closure) {
final Object[] args = new Object[2];
int counter = 0;
- for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+ for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext(); ) {
args[0] = iter.next();
args[1] = counter++;
closure.call(args);
@@ -2281,7 +2281,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* @return the self Iterable
* @since 2.3.0
*/
- public static <T> Iterable<T> eachWithIndex(Iterable<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+ public static <T> Iterable<T> eachWithIndex(Iterable<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
eachWithIndex(self.iterator(), closure);
return self;
}
@@ -2296,7 +2296,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* @return the self Iterator (now exhausted)
* @since 2.3.0
*/
- public static <T> Iterator<T> eachWithIndex(Iterator<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+ public static <T> Iterator<T> eachWithIndex(Iterator<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
final Object[] args = new Object[2];
int counter = 0;
while (self.hasNext()) {
@@ -2317,7 +2317,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* @return the self Collection
* @since 2.4.0
*/
- public static <T> Collection<T> eachWithIndex(Collection<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+ public static <T> Collection<T> eachWithIndex(Collection<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
return (Collection<T>) eachWithIndex((Iterable<T>) self, closure);
}
@@ -2331,7 +2331,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* @return the self List
* @since 2.4.0
*/
- public static <T> List<T> eachWithIndex(List<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+ public static <T> List<T> eachWithIndex(List<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
return (List<T>) eachWithIndex((Iterable<T>) self, closure);
}
@@ -2345,7 +2345,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* @return the self Set
* @since 2.4.0
*/
- public static <T> Set<T> eachWithIndex(Set<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+ public static <T> Set<T> eachWithIndex(Set<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
return (Set<T>) eachWithIndex((Iterable<T>) self, closure);
}
@@ -2359,7 +2359,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* @return the self SortedSet
* @since 2.4.0
*/
- public static <T> SortedSet<T> eachWithIndex(SortedSet<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+ public static <T> SortedSet<T> eachWithIndex(SortedSet<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
return (SortedSet<T>) eachWithIndex((Iterable<T>) self, closure);
}
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 f0af7aab95..464c41043c 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -136,6 +136,7 @@ import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -3018,6 +3019,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
expression.putNodeMetaData(CLOSURE_ARGUMENTS, paramTypes);
+ if (paramTypes.length != samParamTypes.length) { // GROOVY-8499
+ addError("Incorrect number of parameters. Expected " + samParamTypes.length + " but found " + paramTypes.length, expression);
+ }
}
}
}
@@ -3065,41 +3069,33 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
private void doInferClosureParameterTypes(final ClassNode receiver, final Expression arguments, final ClosureExpression expression, final MethodNode selectedMethod, final Expression hintClass, final Expression resolverClass, final Expression options) {
- Parameter[] closureParams = expression.getParameters();
- if (closureParams == null) return; // no-arg closure
+ Parameter[] closureParams = hasImplicitParameter(expression) ? new Parameter[]{new Parameter(dynamicType(),"it")} : getParametersSafe(expression);
List<ClassNode[]> closureSignatures = getSignaturesFromHint(selectedMethod, hintClass, options, expression);
List<ClassNode[]> candidates = new LinkedList<>();
for (ClassNode[] signature : closureSignatures) {
resolveGenericsFromTypeHint(receiver, arguments, selectedMethod, signature);
- if (signature.length == closureParams.length // same number of arguments
- || (signature.length == 1 && closureParams.length == 0) // implicit it
+ if (signature.length == closureParams.length // matching number of parameters
|| (closureParams.length > signature.length && last(signature).isArray())) { // vargs
candidates.add(signature);
}
}
+
+ if (candidates.isEmpty() && !closureSignatures.isEmpty()) {
+ String spec = closureSignatures.stream().mapToInt(sig -> sig.length).distinct()
+ .sorted().mapToObj(Integer::toString).collect(Collectors.joining(" or "));
+ addError("Incorrect number of parameters. Expected " + spec + " but found " + closureParams.length, expression);
+ }
+
if (candidates.size() > 1) {
for (Iterator<ClassNode[]> candIt = candidates.iterator(); candIt.hasNext(); ) {
ClassNode[] inferred = candIt.next();
- for (int i = 0, n = closureParams.length; i < n; i += 1) {
- Parameter closureParam = closureParams[i];
+ checkClosureSignature(closureParams, inferred, (closureParam, inferredType) -> {
ClassNode declaredType = closureParam.getOriginType();
- ClassNode inferredType;
- if (i < inferred.length - 1 || inferred.length == n) {
- inferredType = inferred[i];
- } else {
- ClassNode lastInferred = inferred[inferred.length - 1];
- if (lastInferred.isArray()) {
- inferredType = lastInferred.getComponentType();
- } else {
- candIt.remove();
- continue;
- }
- }
- if (!typeCheckMethodArgumentWithGenerics(declaredType, inferredType, i == (n - 1))) {
- candIt.remove();
- }
- }
+ if (!typeCheckMethodArgumentWithGenerics(declaredType, inferredType, false)) candIt.remove();
+ }, () -> {
+ candIt.remove();
+ });
}
if (candidates.size() > 1 && resolverClass instanceof ClassExpression) {
candidates = resolveWithResolver(candidates, receiver, arguments, expression, selectedMethod, resolverClass, options);
@@ -3108,28 +3104,38 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
addError("Ambiguous prototypes for closure. More than one target method matches. Please use explicit argument types.", expression);
}
}
+
if (candidates.size() == 1) {
ClassNode[] inferred = candidates.get(0);
- if (closureParams.length == 0 && inferred.length == 1) {
+ if (hasImplicitParameter(expression) && inferred.length == 1) {
expression.putNodeMetaData(CLOSURE_ARGUMENTS, inferred);
} else {
- for (int i = 0, n = closureParams.length; i < n; i += 1) {
- Parameter closureParam = closureParams[i];
- ClassNode inferredType = OBJECT_TYPE;
- if (i < inferred.length - 1 || inferred.length == n) {
- inferredType = inferred[i];
- } else {
- ClassNode lastInferred = inferred[inferred.length - 1];
- if (lastInferred.isArray()) {
- inferredType = lastInferred.getComponentType();
- } else {
- addError("Incorrect number of parameters. Expected " + inferred.length + " but found " + n, expression);
- }
- }
- checkParamType(closureParam, inferredType, i == n-1, false);
+ checkClosureSignature(closureParams, inferred, (closureParam, inferredType) -> {
+ checkParamType(closureParam, inferredType, false, false);
typeCheckingContext.controlStructureVariables.put(closureParam, inferredType);
+ }, () -> {
+ addError("Incorrect number of parameters. Expected " + inferred.length + " but found " + closureParams.length, expression);
+ });
+ }
+ }
+ }
+
+ private static void checkClosureSignature(final Parameter[] declared, final ClassNode[] inferred, final BiConsumer<Parameter,ClassNode> consumer, final Runnable reject) {
+ for (int i = 0, j = inferred.length-1, n = declared.length; i < n; i += 1) {
+ ClassNode declaredType = declared[i].getOriginType();
+ ClassNode inferredType = inferred[Math.min(i, j)];
+ if (isDynamicTyped(inferredType)) continue;
+ if (i >= j) { // at or past end
+ if (inferredType.isArray()) {
+ if (n > inferred.length || !declaredType.isArray() && !isObjectType(declaredType)) {
+ inferredType = inferredType.getComponentType(); // spread array out
+ }
+ } else if (i > j) {
+ reject.run();
+ continue;
}
}
+ consumer.accept(declared[i], inferredType);
}
}
diff --git a/src/test/groovy/bugs/Groovy8816.groovy b/src/test/groovy/bugs/Groovy8816.groovy
deleted file mode 100644
index 0bd56e4e04..0000000000
--- a/src/test/groovy/bugs/Groovy8816.groovy
+++ /dev/null
@@ -1,39 +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.bugs
-
-import org.junit.Test
-
-import static groovy.test.GroovyAssert.shouldFail
-
-final class Groovy8816 {
-
- @Test
- void testCallNoArgClosureWithArg() {
- def err = shouldFail MissingMethodException, '''
- @groovy.transform.CompileStatic
- void test() {
- [0].each { -> }
- }
- test()
- '''
-
- assert err =~ /No signature of method: .*\.doCall\(\) is applicable for argument types: \(Integer\) values: \[0\]/
- }
-}
diff --git a/src/test/groovy/bugs/Groovy9413.groovy b/src/test/groovy/bugs/Groovy9413.groovy
index 03f026c7c9..789decc90e 100644
--- a/src/test/groovy/bugs/Groovy9413.groovy
+++ b/src/test/groovy/bugs/Groovy9413.groovy
@@ -23,7 +23,6 @@ import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
import org.junit.Test
final class Groovy9413 {
-// .\gradlew --no-daemon --max-workers 2 :test --tests groovy.bugs.Groovy9413 --debug-jvm
@Test
void testInterfaceGenerics() {
def config = new CompilerConfiguration(
@@ -38,49 +37,48 @@ final class Groovy9413 {
import java.util.Map;
interface APSBus {
- void send(String target, Map<String, Object> message, APSHandler<APSResult<?>> resultHandler);
+ void send(String target, Map<String, Object> message, APSHandler<APSResult<?>> resultHandler);
}
interface APSBusRouter {
- boolean send(String target, Map<String, Object> message, APSHandler<APSResult<?>> resultHandler);
+ boolean send(String target, Map<String, Object> message, APSHandler<APSResult<?>> resultHandler);
}
interface APSHandler<T> {
- void handle(T value);
+ void handle(T value);
}
interface APSResult<T> {
}
class APSServiceTracker<Service> {
- void withService(WithService<Service> withService, Object... args) throws Exception {
- }
+ void withService(WithService<Service> withService, Object... args) throws Exception {
+ }
}
interface WithService<Service> {
- void withService(Service service, Object... args) throws Exception;
+ void withService(Service service, Object... args) throws Exception;
}
'''
def b = new File(parentDir, 'B.groovy')
b.write '''
@groovy.transform.CompileStatic
class One9413 implements APSBus {
+ private APSServiceTracker<APSBusRouter> busRouterTracker
- private APSServiceTracker<APSBusRouter> busRouterTracker
-
- @Override
- void send(String target, Map<String, Object> message, APSHandler<APSResult<?>> resultHandler) {
- busRouterTracker.withService() { APSBusRouter busRouter ->
- busRouter.send(target, message, resultHandler)
+ @Override
+ void send(String target, Map<String, Object> message, APSHandler<APSResult<?>> resultHandler) {
+ busRouterTracker.withService({ APSBusRouter busRouter, Object[] arguments ->
+ busRouter.send(target, message, resultHandler)
+ })
}
- }
}
@groovy.transform.CompileStatic
class Two9413 implements APSBusRouter {
- @Override
- boolean send(String target, Map<String, Object> payload, APSHandler<APSResult<?>> resultHandler) {
- }
+ @Override
+ boolean send(String target, Map<String, Object> payload, APSHandler<APSResult<?>> resultHandler) {
+ }
}
'''
@@ -89,8 +87,8 @@ final class Groovy9413 {
cu.addSources(a, b)
cu.compile()
} finally {
- parentDir.deleteDir()
config.targetDirectory.deleteDir()
+ parentDir.deleteDir()
}
}
}
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index 1f6bd95af2..e1e889f7e4 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -620,10 +620,27 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ void testInferenceForDGM_eachMatch() {
+ assertScript '''
+ 'foo bar baz'.eachMatch(~/(?m)^(\s*).*\n$/) { all, ws ->
+ all.trim(); ws.length()
+ }
+ '''
+ }
+
void testInferenceForDGM_eachWithIndexOnMap() {
assertScript '''
- [a:'A',bb:'B',ccc:'C'].eachWithIndex { k,v,i -> assert k.toUpperCase() == v*(1+i) }
[a:'A',bb:'B',ccc:'C'].eachWithIndex { e,i -> assert e.key.toUpperCase() == e.value*(1+i) }
+ [a:'A',bb:'B',ccc:'C'].eachWithIndex { k,v,i -> assert k.toUpperCase() == v*(1+i) }
+ '''
+ }
+ void testInferenceForDGM_eachWithIndexOnObject() {
+ assertScript '''
+ def foo(object) {
+ object.eachWithIndex { Map<String,String> map, i -> map.ccc.toLowerCase() + (1+i) }
+ // ^^^^^^^^^^^^^^^^^^ each/eachWithIndex are flexible
+ }
+ foo([ [a:'A',bb:'B',ccc:'C'] ])
'''
}
void testInferenceForDGM_eachWithIndexOnIterable() {
@@ -1192,34 +1209,112 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-6939
+ void testParamCountCheck1() {
+ shouldFailWithMessages '''
+ def m(o) {
+ o.each { x, y -> }
+ }
+ ''',
+ 'Incorrect number of parameters. Expected 1 but found 2'
+ }
+
+ // GROOVY-6939
+ void testParamCountCheck2() {
+ shouldFailWithMessages '''
+ def m(o) {
+ o.eachWithIndex { x, y, z -> }
+ }
+ ''',
+ 'Incorrect number of parameters. Expected 2 but found 3'
+ }
+
+ // GROOVY-6939
+ void testParamCountCheck3() {
+ shouldFailWithMessages '''
+ def m(o) {
+ o.eachWithIndex { print it }
+ }
+ ''',
+ 'Incorrect number of parameters. Expected 2 but found 1'
+ }
+
+ // GROOVY-6939
+ void testParamCountCheck4() {
+ shouldFailWithMessages '''
+ def m(... array) {
+ array.each { x, y -> }
+ }
+ ''',
+ 'Incorrect number of parameters. Expected 1 but found 2'
+ }
+
+ // GROOVY-6939
+ void testParamCountCheck5() {
+ shouldFailWithMessages '''
+ def m() {
+ [:].each { -> }
+ }
+ ''',
+ 'Incorrect number of parameters. Expected 1 or 2 but found 0'
+ }
+
+ // GROOVY-8816
+ void testParamCountCheck6() {
+ shouldFailWithMessages '''
+ def m() {
+ [].each { -> }
+ }
+ ''',
+ 'Incorrect number of parameters. Expected 1 but found 0'
+ }
+
+ // GROOVY-9854
+ void testParamCountCheck7() {
+ shouldFailWithMessages '''
+ switch (42) { case { -> }: break; }
+ ''',
+ 'Incorrect number of parameters. Expected 1 but found 0'
+ }
+
+ // GROOVY-9854
+ void testParamCountCheck8() {
+ shouldFailWithMessages '''
+ switch (42) { case { i, j -> }: break; }
+ ''',
+ 'Incorrect number of parameters. Expected 1 but found 2'
+ }
+
+ // GROOVY-8499: SAM type
+ void testParamCountCheck9() {
+ shouldFailWithMessages '''
+ ['ab'.chars, '12'.chars].combinations().stream().map((x, y) -> "$x$y")
+ ''',
+ 'Incorrect number of parameters. Expected 1 but found 2'
+ }
+
void testInferenceWithSAMTypeCoercion() {
- assertScript '''import java.util.concurrent.Callable
+ assertScript '''
interface Action<T> {
void execute(T thing)
}
class Wrapper<T> {
-
private final T thing
-
Wrapper(T thing) {
this.thing = thing
}
-
void contravariantTake(Action<? super T> action) {
action.execute(thing)
}
-
void invariantTake(Action<T> action) {
action.execute(thing)
}
-
}
- static <T> Wrapper<T> wrap(Callable<T> callable) {
+ static <T> Wrapper<T> wrap(java.util.concurrent.Callable<T> callable) {
new Wrapper(callable.call())
}
-
static Integer dub(Integer integer) {
integer * 2
}
@@ -1238,6 +1333,8 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ //--------------------------------------------------------------------------
+
void testGroovy6022() {
assertScript '''import groovy.transform.stc.SimpleType
class Item {
@@ -1296,27 +1393,25 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
assert extractInfo(" ab 12 cdef 34 jhg ") == [[144, 1156], [14, 38], [14, 38]]
'''
assertScript '''
- def method() {
+ def foo() {
assert "foobarbaz".findAll('b(a)([rz])') { full, a, b -> assert "BA"=="B" + a.toUpperCase() }.size() == 2
assert "foobarbaz".findAll('ba') { String found -> assert "BA" == found.toUpperCase() }.size() == 2
}
-
- method()
+ foo()
'''
}
void testGroovy9058() {
assertScript '''
- List<Object[]> bar() { [['fee', 'fi'] as Object[], ['fo', 'fum'] as Object[]] }
-
+ List<Object[]> table() {
+ [ ['fee', 'fi'] as Object[], ['fo', 'fum'] as Object[] ]
+ }
def foo() {
- def result = []
- List<Object[]> bar = bar()
- bar.each { row -> result << row[0].toString().toUpperCase() }
- result
+ List<String> result = []
+ table().each { row -> result << row[0].toString().toUpperCase() }
+ assert result == ['FEE', 'FO']
}
-
- assert foo() == ['FEE', 'FO']
+ foo()
'''
}
@@ -1468,16 +1563,6 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
assert result == 'positive'
'''
- shouldFailWithMessages '''
- switch (42) { case { -> }: break; }
- ''',
- 'Incorrect number of parameters. Expected 1 but found 0'
-
- shouldFailWithMessages '''
- switch (42) { case { i, j -> }: break; }
- ''',
- 'Incorrect number of parameters. Expected 1 but found 2'
-
shouldFailWithMessages '''
switch (42) { case { String s -> }: break; }
''',
diff --git a/src/test/groovy/transform/stc/Groovy8247Bug.groovy b/src/test/groovy/transform/stc/Groovy8247Bug.groovy
deleted file mode 100644
index 7488352b8b..0000000000
--- a/src/test/groovy/transform/stc/Groovy8247Bug.groovy
+++ /dev/null
@@ -1,36 +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
-
-class Groovy8247Bug extends StaticTypeCheckingTestCase {
- void testClosureWithExplicitParamNoInferrableArguments() {
- assertScript '''
- def runnable(Runnable r) {
- r.run()
- }
- def foo() {
- runnable { it -> // note explicit it
- println it
- }
- }
- foo()
- '''
- }
-}
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/AutoIndentAction.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/AutoIndentAction.groovy
index e7bd67bde6..f8fec3da00 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/AutoIndentAction.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/AutoIndentAction.groovy
@@ -36,16 +36,14 @@ class AutoIndentAction extends AbstractAction {
def cursorPos = inputArea.getCaretPosition()
int rowNum = rootElement.getElementIndex(cursorPos)
def rowElement = rootElement.getElement(rowNum)
- int startOffset = rowElement.getStartOffset()
- int endOffset = rowElement.getEndOffset()
- String rowContent = inputArea.document.getText(startOffset, endOffset - startOffset);
- String contentBeforeCursor = inputArea.document.getText(startOffset, cursorPos - startOffset);
+ int startOffset = rowElement.startOffset, endOffset = rowElement.endOffset
+ String rowContent = inputArea.document.getText(startOffset, endOffset - startOffset)
+ String contentBeforeCursor = inputArea.document.getText(startOffset, cursorPos - startOffset)
+
String whitespaceStr = ''
- def matcher = (rowContent =~ /(?m)^(\s*).*\n$/)
- matcher.each { all, ws ->
+ rowContent.eachMatch(~/(?m)^(\s*).*\n$/) { all, ws ->
whitespaceStr = ws
}
-
if (contentBeforeCursor ==~ /(\s)*/) {
whitespaceStr = contentBeforeCursor
}
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedTuple.groovy b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedTuple.groovy
index b906279e6d..86206edf03 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedTuple.groovy
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedTuple.groovy
@@ -18,7 +18,6 @@
*/
package org.apache.groovy.ginq.provider.collection.runtime
-
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import groovy.transform.stc.POJO
@@ -28,9 +27,9 @@ import groovy.transform.stc.POJO
*
* @since 4.0.0
*/
+@CompileStatic
@PackageScope
@POJO
-@CompileStatic
class NamedTuple<E> extends Tuple<E> {
private static final long serialVersionUID = -5067092453136522209L
private final Map<String, E> data = new LinkedHashMap<>()
@@ -43,19 +42,19 @@ class NamedTuple<E> extends Tuple<E> {
throw new IllegalArgumentException("names should be unique: $nameList")
}
- for (int i = 0, n = nameListSize; i < n; i++) {
+ for (int i = 0, n = nameListSize; i < n; i += 1) {
data.put(nameList.get(i), elementList.get(i))
}
}
- def getAt(String name) {
- return data.get(name)
- }
-
def get(String name) {
return getAt(name)
}
+ def getAt(String name) {
+ return data.get(name)
+ }
+
boolean exists(String name) {
return data.containsKey(name)
}
@@ -66,8 +65,10 @@ class NamedTuple<E> extends Tuple<E> {
@Override
String toString() {
- '(' + nameList.withIndex()
- .collect((String n, int i) -> { "${n}:${this[i]}" })
- .join(', ') + ')'
+ StringJoiner sj = new StringJoiner(', ', '(', ')')
+ for (String name : getNameList()) {
+ sj.add(name + ':' + this[name])
+ }
+ sj.toString()
}
}