[
https://issues.apache.org/jira/browse/GROOVY-12620?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18135658#comment-18135658
]
ASF GitHub Bot commented on GROOVY-12620:
-----------------------------------------
codeconsole opened a new pull request, #3146:
URL: https://github.com/apache/groovy/pull/3146
Static type checking rejected a closure or lambda that returns an int
constant for a byte, short or char SAM return type:
```groovy
interface S { short get() }
interface B { byte get() }
@groovy.transform.CompileStatic
void test() {
S s = () -> 1 // Cannot return value of type int for lambda
expecting short
B b = { -> 2 } // Cannot return value of type int for closure
expecting byte
assert s.get() == (short) 1 && b.get() == (byte) 2
}
```
Java accepts this. A lambda result expression is in an assignment context,
and JLS 5.2 allows narrowing an int constant that fits the target type there.
Groovy already accepts `short x = 1` and `short m() { 1 }`. 4.0.33, 5.0.8 and
6.0.0 reject it the same way.
`StaticTypeCheckingVisitor.checkReturnType` now accepts a return expression
that is an int `ConstantExpression` whose value fits the expected primitive
byte, short or char type. A constant that does not fit (`() -> 70000` for
short, `{ -> -1 }` for char) and a non-constant int are still rejected. Static
compilation already converts the value: a lambda body compiles to `iconst_1;
i2s; ireturn`, and a closure casts the value to the boxed return type.
This and #3142 (GROOVY-12616, widening) each add an `else if` after the
covariance branch of `checkReturnType` and a helper before `isClosureWithType`;
whichever lands second keeps both. No case matches both branches.
## Tests
`CoercionSTCTest.testCoerceNarrowingConstantReturnToFunctionalInterface`
fails without the change, under both `CoercionSTCTest` and
`CoercionStaticCompileTests`. It covers closures and lambdas for byte, short
and char, boundary and negative values, block lambdas with several returns,
method arguments, `as` coercion, static and instance contexts, and the cases
that must stay rejected. `groovy.transform.stc.*`,
`org.codehaus.groovy.classgen.asm.sc.*`, `gls.*` and `groovy.bugs.*` pass. The
Checkstyle and CodeNarc gates pass.
> STC rejects a closure or lambda returning an int constant for a byte, short
> or char SAM return type
> ---------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12620
> URL: https://issues.apache.org/jira/browse/GROOVY-12620
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 4.0.33, 5.0.8, 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> {code:groovy}
> interface S { short get() }
> interface B { byte get() }
> interface C { char get() }
> @groovy.transform.TypeChecked // or @CompileStatic
> void test() {
> S s = () -> 1
> B b = { -> 2 }
> C c = () -> 65
> assert s.get() == (short) 1 && b.get() == (byte) 2 && c.get() == (char) 65
> }
> test()
> {code}
> Actual:
> {noformat}
> [Static type checking] - Cannot return value of type int for lambda expecting
> short
> [Static type checking] - Cannot return value of type int for closure
> expecting byte
> [Static type checking] - Cannot return value of type int for lambda expecting
> char
> {noformat}
> Expected: the script compiles and runs. Java accepts these lambdas, because
> JLS 5.2 allows narrowing an int constant that fits the target type in an
> assignment context, and a lambda result expression is in an assignment
> context. Groovy already accepts a short variable or a short method return
> initialised from such a constant, and dynamic Groovy runs the script. A
> constant that does not fit, such as 70000 for short, or a non-constant int
> must still be rejected.
> The closure/lambda return check in StaticTypeCheckingVisitor.checkReturnType
> accepts only a return type that is compatible after wrapping, so int is never
> accepted where byte, short or char is expected.
> Seen in 4.0.33, 5.0.8 and 6.0.0.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)