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 2021/11/17 16:03:35 UTC
[groovy] branch master updated: GROOVY-10372: STC: check param types for functional interface conversion
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 fdb2fc5 GROOVY-10372: STC: check param types for functional interface conversion
fdb2fc5 is described below
commit fdb2fc5089ed2c1ae6b000082dfea41d86d77577
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Nov 17 09:16:19 2021 -0600
GROOVY-10372: STC: check param types for functional interface conversion
---
.../transform/stc/StaticTypeCheckingVisitor.java | 56 +--
src/test/groovy/bugs/Groovy9790.groovy | 3 +-
.../stc/ClosureParamTypeInferenceSTCTest.groovy | 397 +++++++++------------
src/test/groovy/transform/stc/LambdaTest.groovy | 28 +-
.../transform/stc/TypeInferenceSTCTest.groovy | 5 +-
.../asm/sc/StaticCompilationTestSupport.groovy | 1 +
.../stc/StaticTypeCheckingTestCase.groovy | 16 +-
7 files changed, 239 insertions(+), 267 deletions(-)
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 1743b31..cab64fe 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -965,16 +965,22 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (parameter.isDynamicTyped()) {
parameter.setType(samParameterTypes[i]);
parameter.setOriginType(samParameterTypes[i]);
+ } else {
+ checkParamType(parameter, samParameterTypes[i], i == n-1, rhsExpression instanceof LambdaExpression);
}
}
} else {
- String descriptor = toMethodParametersString(findSAM(lhsType).getName(), samParameterTypes);
- addStaticTypeError("Wrong number of parameters for method target " + descriptor, rhsExpression);
+ addStaticTypeError("Wrong number of parameters for method target " + toMethodParametersString(findSAM(lhsType).getName(), samParameterTypes), rhsExpression);
}
storeInferredReturnType(rhsExpression, typeInfo.getV2());
}
+ private void checkParamType(final Parameter source, final ClassNode target, final boolean isLast, final boolean lambda) {
+ if (/*lambda ? !source.getOriginType().equals(target) :*/!typeCheckMethodArgumentWithGenerics(source.getOriginType(), target, isLast))
+ addStaticTypeError("Expected type " + prettyPrintType(target) + " for " + (lambda ? "lambda" : "closure") + " parameter: " + source.getName(), source);
+ }
+
/**
* Given a binary expression corresponding to an assignment, will check that
* the type of the RHS matches one of the possible setters and if not, throw
@@ -2954,10 +2960,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
} else if ((n = p.length) == 0) {
// implicit parameter(s)
paramTypes = samParamTypes;
- } else {
- paramTypes = new ClassNode[n];
- for (int i = 0; i < n; i += 1) {
- paramTypes[i] = i < samParamTypes.length ? samParamTypes[i] : null;
+ } else { // TODO: error for length mismatch
+ paramTypes = Arrays.copyOf(samParamTypes, n);
+ for (int i = 0; i < Math.min(n, samParamTypes.length); i += 1) {
+ checkParamType(p[i], paramTypes[i], i == n-1, expression instanceof LambdaExpression);
}
}
expression.putNodeMetaData(CLOSURE_ARGUMENTS, paramTypes);
@@ -3030,25 +3036,24 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
if (candidates.size() > 1) {
- Iterator<ClassNode[]> candIt = candidates.iterator();
- while (candIt.hasNext()) {
+ 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];
- ClassNode originType = closureParam.getOriginType();
+ ClassNode declaredType = closureParam.getOriginType();
ClassNode inferredType;
- if (i < inferred.length - 1 || inferred.length == closureParams.length) {
+ if (i < inferred.length - 1 || inferred.length == n) {
inferredType = inferred[i];
- } else { // vargs?
- ClassNode lastArgInferred = inferred[inferred.length - 1];
- if (lastArgInferred.isArray()) {
- inferredType = lastArgInferred.getComponentType();
+ } else {
+ ClassNode lastInferred = inferred[inferred.length - 1];
+ if (lastInferred.isArray()) {
+ inferredType = lastInferred.getComponentType();
} else {
candIt.remove();
continue;
}
}
- if (!typeCheckMethodArgumentWithGenerics(originType, inferredType, i == (n - 1))) {
+ if (!typeCheckMethodArgumentWithGenerics(declaredType, inferredType, i == (n - 1))) {
candIt.remove();
}
}
@@ -3067,24 +3072,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
} else {
for (int i = 0, n = closureParams.length; i < n; i += 1) {
Parameter closureParam = closureParams[i];
- ClassNode originType = closureParam.getOriginType();
+ ClassNode declaredType = closureParam.getOriginType();
ClassNode inferredType = OBJECT_TYPE;
- if (i < inferred.length - 1 || inferred.length == closureParams.length) {
+ if (i < inferred.length - 1 || inferred.length == n) {
inferredType = inferred[i];
- } else { // vargs?
- ClassNode lastArgInferred = inferred[inferred.length - 1];
- if (lastArgInferred.isArray()) {
- inferredType = lastArgInferred.getComponentType();
+ } else {
+ ClassNode lastInferred = inferred[inferred.length - 1];
+ if (lastInferred.isArray()) {
+ inferredType = lastInferred.getComponentType();
} else {
- addError("Incorrect number of parameters. Expected " + inferred.length + " but found " + closureParams.length, expression);
+ addError("Incorrect number of parameters. Expected " + inferred.length + " but found " + n, expression);
}
}
- boolean lastArg = i == (n - 1);
-
- if (!typeCheckMethodArgumentWithGenerics(originType, inferredType, lastArg)) {
- addError("Expected parameter of type " + prettyPrintType(inferredType) + " but got " + prettyPrintType(originType), closureParam.getType());
- }
-
+ checkParamType(closureParam, inferredType, i == n-1, false);
typeCheckingContext.controlStructureVariables.put(closureParam, inferredType);
}
}
diff --git a/src/test/groovy/bugs/Groovy9790.groovy b/src/test/groovy/bugs/Groovy9790.groovy
index ca04ddd..61fa822 100644
--- a/src/test/groovy/bugs/Groovy9790.groovy
+++ b/src/test/groovy/bugs/Groovy9790.groovy
@@ -81,7 +81,6 @@ final class Groovy9790 {
test()
'''
-
- assert err.toString().contains('The inferred type[int] is not compatible with the parameter type[java.lang.String]')
+ assert err =~ /Expected type int for lambda parameter: s/
}
}
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index 5cb1930..bf2e779 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -29,7 +29,8 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
shouldFailWithMessages '''
['a','b'].collect { Date it -> it.toUpperCase() }
- ''', 'Expected parameter of type java.lang.String but got java.util.Date'
+ ''',
+ 'Expected type java.lang.String for closure parameter: it'
}
void testInferenceForDGM_collectUsingImplicitIt() {
@@ -228,193 +229,169 @@ assert result == ['b', 'r', 'e', 'a', 'd', 'b', 'u', 't', 't', 'e', 'r']
}
void testInferenceOnNonExtensionMethod() {
- assertScript '''import groovy.transform.stc.ClosureParams
- import groovy.transform.stc.FirstParam
- public <T> T foo(T arg, @ClosureParams(FirstParam) Closure c) { c.call(arg) }
+ assertScript '''import groovy.transform.stc.FirstParam
+ def <T> T foo(T arg, @ClosureParams(FirstParam) Closure c) { c.call(arg) }
assert foo('a') { it.toUpperCase() } == 'A'
-'''
+ '''
}
void testFromStringWithSimpleType() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
-foo { String str -> println str.toUpperCase()}
-'''
+ void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
+ foo { String str -> println str.toUpperCase()}
+ '''
shouldFailWithMessages '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
-foo { Date str -> println str}
-''', 'Expected parameter of type java.lang.String but got java.util.Date'
+ void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
+ foo { Date str -> println str}
+ ''',
+ 'Expected type java.lang.String for closure parameter: str'
}
void testFromStringWithGenericType() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
-foo { List<String> str -> str.each { println it.toUpperCase() } }
-'''
+ void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
+ foo { List<String> str -> str.each { println it.toUpperCase() } }
+ '''
shouldFailWithMessages '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
-foo { List<Date> d -> d.each { println it } }
-''', 'Expected parameter of type java.util.List<java.lang.String> but got java.util.List<java.util.Date>'
+ void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
+ foo { List<Date> d -> d.each { println it } }
+ ''',
+ 'Expected type java.util.List<java.lang.String> for closure parameter: d'
}
void testFromStringWithDirectGenericPlaceholder() {
-
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-public <T> void foo(T t, @ClosureParams(value=FromString,options="T") Closure cl) { cl.call(t) }
-foo('hey') { println it.toUpperCase() }
-'''
-
+ def <T> void foo(T t, @ClosureParams(value=FromString,options="T") Closure cl) { cl.call(t) }
+ foo('hey') { println it.toUpperCase() }
+ '''
}
void testFromStringWithGenericPlaceholder() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-public <T> void foo(T t, @ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call([t,t]) }
-foo('hey') { List<String> str -> str.each { println it.toUpperCase() } }
-'''
-
+ def <T> void foo(T t, @ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call([t,t]) }
+ foo('hey') { List<String> str -> str.each { println it.toUpperCase() } }
+ '''
}
void testFromStringWithGenericPlaceholderFromClass() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
- class Foo<T> {
- public 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() } }
-'''
+ class Foo<T> {
+ 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() } }
+ '''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenerics() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
- class Foo<T,U> {
- 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 { List<String> str -> str.each { println it.toUpperCase() } }
-'''
+ class Foo<T,U> {
+ 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() } }
+ '''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignature() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
- class Foo<T,U> {
- 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() } }
-'''
+ class Foo<T,U> {
+ 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() } }
+ '''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQN() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
- class Foo<T,U> {
- 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() } }
-'''
+ class Foo<T,U> {
+ 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() } }
+ '''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClass() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
- class Foo {
- void bar() {
- println 'Haha!'
- }
- }
-
- class Tor<D,U> {
- 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() } }
-'''
+ class Foo {
+ void bar() {
+ println 'Haha!'
+ }
+ }
+ class Tor<D,U> {
+ 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() } }
+ '''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClassAndTwoArgs() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
- class Foo {
- void bar() {
- println 'Haha!'
- }
- }
-
- class Tor<D,U> {
- 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() } } }
-'''
+ class Foo {
+ void bar() {
+ println 'Haha!'
+ }
+ }
+ class Tor<D,U> {
+ 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() } } }
+ '''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndPolymorphicSignature() {
assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
- class Foo {
- void bar() {
- println 'Haha!'
- }
- }
-
- class Tor<D,U> {
- 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 {
- cl.call(3)
+ class Foo {
+ void bar() {
+ println 'Haha!'
+ }
}
- }
- }
- def tor = new Tor<Integer,Foo>()
-
- tor.foo { r, e -> r.times { e.each { it.bar() } } }
- tor.foo { it.times { println 'polymorphic' } }
-'''
+ class Tor<D,U> {
+ 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 {
+ cl.call(3)
+ }
+ }
+ }
+ def tor = new Tor<Integer,Foo>()
+ tor.foo { r, e -> r.times { e.each { it.bar() } } }
+ tor.foo { it.times { println 'polymorphic' } }
+ '''
}
void testStringGroovyMethodsFindMethodWithVargs() {
assertScript '''
"75001 Paris".find(/(\\d{5}\\s(\\w+))/) { all, zip, city -> println all.toUpperCase() }
-'''
-
+ '''
assertScript '''
"75001 Paris".find(/(\\d{5}\\s(\\w+))/) { String all, String zip, String city -> println all.toUpperCase() }
-'''
+ '''
shouldFailWithMessages '''
"75001 Paris".find(/(\\d{5}\\s(\\w+))/) { String all, Date zip, String city -> println all.toUpperCase() }
-''', 'Expected parameter of type java.lang.String but got java.util.Date'
+ ''',
+ 'Expected type java.lang.String for closure parameter: zip'
+ }
+
+ void testFromStringInSameSourceUnit() {
+ assertScript '''import groovy.transform.stc.FromString
+ public <T> void doSomething(T val, @ClosureParams(value=FromString, options="T") Closure cl) {
+ cl(val)
+ }
+ doSomething('foo') {
+ println it.toUpperCase()
+ }
+ doSomething(new Date()) {
+ println it.time
+ }
+ '''
}
void testStringGroovyMethodsFindMethodWithList() {
@@ -1199,120 +1176,94 @@ import groovy.transform.stc.ClosureParams
'''
}
- void testFromStringInSameSourceUnit() {
- assertScript '''import groovy.transform.stc.ClosureParams
-import groovy.transform.stc.FromString
-
-public <T> void doSomething(T val, @ClosureParams(value=FromString, options="T") Closure cl) {
- cl(val)
-}
-
-doSomething('foo') {
- println it.toUpperCase()
-}
-
-doSomething(new Date()) {
- println it.time
-}
-'''
-
- }
-
void testInferenceWithSAMTypeCoercion() {
assertScript '''import java.util.concurrent.Callable
+ interface Action<T> {
+ void execute(T thing)
+ }
-interface Action<T> {
- void execute(T thing)
-}
-
-class Wrapper<T> {
-
- private final T thing
+ class Wrapper<T> {
- Wrapper(T thing) {
- this.thing = thing
- }
+ private final T thing
- void contravariantTake(Action<? super T> action) {
- action.execute(thing)
- }
+ Wrapper(T thing) {
+ this.thing = thing
+ }
- void invariantTake(Action<T> action) {
- action.execute(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) {
- new Wrapper(callable.call())
-}
+ }
-static Integer dub(Integer integer) {
- integer * 2
-}
+ static <T> Wrapper<T> wrap(Callable<T> callable) {
+ new Wrapper(callable.call())
+ }
-wrap {
- 1
-} contravariantTake {
- dub(it) // fails static compile, 'it' is not known to be Integer
-}
+ static Integer dub(Integer integer) {
+ integer * 2
+ }
-wrap {
- 1
-} invariantTake {
- dub(it) // passes static compile, 'it' is known to be Integer
-}
+ wrap {
+ 1
+ } contravariantTake {
+ dub(it) // fails static compile, 'it' is not known to be Integer
+ }
-'''
+ wrap {
+ 1
+ } invariantTake {
+ dub(it) // passes static compile, 'it' is known to be Integer
+ }
+ '''
}
void testGroovy6602() {
- shouldFailWithMessages '''import groovy.transform.stc.ClosureParams
-import groovy.transform.stc.FromString
-
-void foo(@ClosureParams(value = FromString, options = "java.lang.Number")
- Closure cl) {
- cl.call(4.5)
-}
-
-foo { Integer i -> println i }
-''', 'Expected parameter of type java.lang.Number but got java.lang.Integer'
+ shouldFailWithMessages '''import groovy.transform.stc.FromString
+ void foo(@ClosureParams(value=FromString, options="java.lang.Number") Closure cl) {
+ cl.call(4.5)
+ }
+ foo { Integer i -> println i }
+ ''',
+ 'Expected type java.lang.Number for closure parameter: i'
}
void testGroovy6729() {
- assertScript '''import groovy.transform.stc.ClosureParams
-import groovy.transform.stc.FirstParam
-
- static <T> List<T> callee01(List<T>self, @ClosureParams(FirstParam.FirstGenericType) Closure c) {
- self.each {
- c.call(it)
- }
- return self
- }
- callee01(["a","b","c"]) { a ->
- println(a.toUpperCase()) // [Static type checking] - Cannot find matching method java.lang.Object#toUpperCase(). Please check if the declared type is correct and if the method exists.
- }
- '''
+ assertScript '''import groovy.transform.stc.FirstParam
+ static <T> List<T> callee01(List<T>self, @ClosureParams(FirstParam.FirstGenericType) Closure c) {
+ self.each {
+ c.call(it)
+ }
+ return self
+ }
+ callee01(["a","b","c"]) { a ->
+ println(a.toUpperCase()) // [Static type checking] - Cannot find matching method java.lang.Object#toUpperCase(). Please check if the declared type is correct and if the method exists.
+ }
+ '''
}
void testGroovy6735() {
assertScript '''
-def extractInfo(String s) {
- def squareNums = s.findAll(/\\d+/) { String num -> num.toInteger() }.collect{ Integer num -> num ** 2 }
- def wordSizePlusNum = s.findAll(/\\s*(\\w+)\\s*(\\d+)/) { _, String word, String num -> word.size() + num.toInteger() }
- def numPlusWordSize = s.findAll(/\\s*(\\w+)\\s*(\\d+)/) { _, word, num -> num.toInteger() + word.size() }
- [squareNums, wordSizePlusNum, numPlusWordSize]
-}
-assert extractInfo(" ab 12 cdef 34 jhg ") == [[144, 1156], [14, 38], [14, 38]]
-'''
+ def extractInfo(String s) {
+ def squareNums = s.findAll(/\\d+/) { String num -> num.toInteger() }.collect{ Integer num -> num ** 2 }
+ def wordSizePlusNum = s.findAll(/\\s*(\\w+)\\s*(\\d+)/) { _, String word, String num -> word.size() + num.toInteger() }
+ def numPlusWordSize = s.findAll(/\\s*(\\w+)\\s*(\\d+)/) { _, word, num -> num.toInteger() + word.size() }
+ [squareNums, wordSizePlusNum, numPlusWordSize]
+ }
+ assert extractInfo(" ab 12 cdef 34 jhg ") == [[144, 1156], [14, 38], [14, 38]]
+ '''
assertScript '''
-def method() {
- 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
-}
+ def method() {
+ 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()
-'''
+ method()
+ '''
}
void testGroovy9058() {
@@ -1354,7 +1305,7 @@ method()
void testGroovy9518b() {
assertScript '''
- import groovy.transform.stc.*
+ import groovy.transform.stc.SimpleType
class C {
C(String s, @ClosureParams(value=SimpleType, options='java.util.List') Closure<Integer> c) {
@@ -1391,7 +1342,7 @@ method()
void testGroovy9735() {
assertScript '''
- import groovy.transform.stc.*
+ import groovy.transform.stc.FirstParam
class C<I extends Item> {
Queue<I> queue
@@ -1420,7 +1371,7 @@ method()
void testGroovy9597a() {
assertScript '''
- import groovy.transform.stc.*
+ import groovy.transform.stc.FirstParam
class A {
def <T> void proc(Collection<T> values, @ClosureParams(FirstParam.FirstGenericType) Closure<String> block) {
@@ -1443,7 +1394,7 @@ method()
void testGroovy9597b() {
assertScript '''
- import groovy.transform.stc.*
+ import groovy.transform.stc.FirstParam
class A {
static A of(@DelegatesTo(A) Closure x) {
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index 6c9b0fd..7d0dedc 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -240,14 +240,14 @@ final class LambdaTest {
'''
}
- //TODO: GROOVY-10277
+ @Test // GROOVY-10372
void testComparator2() {
def err = shouldFail '''
@groovy.transform.CompileStatic class T {
- Comparator<Integer> c = (int a, int b) -> Integer.compare(a, b)
+ Comparator<Integer> c = (int a, String b) -> 42
}
'''
- assert err =~ /Cannot assign java.util.Comparator<int> to: java.util.Comparator<java.lang.Integer>/
+ assert err =~ /Expected type java.lang.Integer for lambda parameter: b/
}
@Test // GROOVY-9977
@@ -894,19 +894,35 @@ final class LambdaTest {
new Value<>(supplier.get())
}
def <T> Value<T> replace(Function<? super V, ? extends T> function) {
- new Value(function.apply(val))
+ new Value<>(function.apply(val))
}
}
@groovy.transform.CompileStatic
void test() {
- assert new Value(123).replace(() -> 'foo').toString() == 'foo'
- assert new Value(123).replace((Integer v) -> 'bar').toString() == 'bar'
+ assert new Value<>(123).replace(() -> 'foo').toString() == 'foo'
+ assert new Value<>(123).replace((Integer v) -> 'bar').toString() == 'bar'
}
test()
'''
}
+ @Test // GROOVY-10372
+ void testFunctionalInterface5() {
+ def err = shouldFail '''
+ interface I {
+ def m(List<String> strings)
+ }
+
+ @groovy.transform.CompileStatic
+ void test() {
+ I face = (List<Object> list) -> null
+ }
+ test()
+ '''
+ assert err =~ /Expected type java.util.List<java.lang.String> for lambda parameter: list/
+ }
+
@Test
void testFunctionWithUpdatingLocalVariable() {
assertScript '''
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 032fe5a..5f4e75f 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -574,7 +574,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testShouldNotFailWithWithAndExplicitTypedIt() {
+ void testShouldFailWithWithAndWrongExplicitIt() {
shouldFailWithMessages '''
class A {
int x
@@ -583,7 +583,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
a.with { String it ->
it.x = 2 // should be recognized as a.x at compile time
}
- ''', 'Expected parameter of type A but got java.lang.String'
+ ''',
+ 'Expected type A for closure parameter: it'
}
void testShouldNotFailWithInheritanceAndWith() {
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
index 4f1e62b..0f9a644 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
@@ -56,6 +56,7 @@ trait StaticCompilationTestSupport {
new ImportCustomizer().tap {
addImports(
'groovy.transform.ASTTest',
+ 'groovy.transform.stc.ClosureParams',
'org.codehaus.groovy.ast.ClassHelper',
'org.codehaus.groovy.transform.stc.StaticTypesMarker')
addStaticStars(
diff --git a/src/testFixtures/groovy/groovy/transform/stc/StaticTypeCheckingTestCase.groovy b/src/testFixtures/groovy/groovy/transform/stc/StaticTypeCheckingTestCase.groovy
index d47038a..1bd6ff9 100644
--- a/src/testFixtures/groovy/groovy/transform/stc/StaticTypeCheckingTestCase.groovy
+++ b/src/testFixtures/groovy/groovy/transform/stc/StaticTypeCheckingTestCase.groovy
@@ -42,12 +42,16 @@ abstract class StaticTypeCheckingTestCase extends GroovyTestCase {
config = new CompilerConfiguration()
def imports = new ImportCustomizer()
imports.addImports(
- 'groovy.transform.ASTTest', 'org.codehaus.groovy.transform.stc.StaticTypesMarker',
- 'org.codehaus.groovy.ast.ClassHelper'
- )
- imports.addStaticStars('org.codehaus.groovy.control.CompilePhase')
- imports.addStaticStars('org.codehaus.groovy.transform.stc.StaticTypesMarker')
- imports.addStaticStars('org.codehaus.groovy.ast.ClassHelper')
+ 'groovy.transform.ASTTest',
+ 'groovy.transform.stc.ClosureParams',
+ 'org.codehaus.groovy.ast.ClassHelper',
+ 'org.codehaus.groovy.transform.stc.StaticTypesMarker'
+ )
+ imports.addStaticStars(
+ 'org.codehaus.groovy.ast.ClassHelper',
+ 'org.codehaus.groovy.control.CompilePhase',
+ 'org.codehaus.groovy.transform.stc.StaticTypesMarker'
+ )
config.addCompilationCustomizers(new ASTTransformationCustomizer(TypeChecked), imports)
configure()
shell = new GroovyShell(config)