[
https://issues.apache.org/jira/browse/GROOVY-9902?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17268806#comment-17268806
]
Eric Milles commented on GROOVY-9902:
-------------------------------------
As noted in your comment for "of", {{@DelegatesTo(value = Holder}} is missing
the generics necessary for the type checker to give you the warnings you are
looking for. In your case, the delegate is the implicit parameter "this" and
there is not a good way to indicate that fact in the annotation metadata.
Not sure what "of" does in your real code, but in this case, using the DGM
"tap" or "with" instead will carry forward the generics since the "self"
parameter is explicit in the extension method declarations.
> Generic typecheck in @DelegatesTo doesn't work
> ----------------------------------------------
>
> Key: GROOVY-9902
> URL: https://issues.apache.org/jira/browse/GROOVY-9902
> Project: Groovy
> Issue Type: Bug
> Components: Static compilation
> Affects Versions: 2.5.6, 3.0.7
> Reporter: Felix Scheinost
> Priority: Major
>
> I found an edge case where @CompileStatic doesn't raise an error when calling
> a method with incompatible types.
> Example code that reproduces the problem:
> [https://groovyconsole.appspot.com/script/5098548152500224]
> {code:java}
> import groovy.transform.CompileStatic
> /**
> * For the bug to be visible this class has to have a generic type
> * Even if in this case the generic seems pointless.
> */
> @CompileStatic
> class Holder<D> {
> TypedProperty<String, D> stringProperty = prop(String)
> TypedProperty<Long, D> longProperty = prop(Long)
> def <T> TypedProperty<T, D> prop(Class<T> clazz) {
> return new TypedProperty<T, D>(clazz: clazz)
> }
> /**
> * This method is also necessary to trigger the bug.
> * Seems like because of the missing <D> in the @DelegatesTo the
> typechecker is tripped up?
> * In the original method in our codebase the signature contains <D> as
> well.
> */
> def <T> T of(@DelegatesTo(value = Holder, strategy =
> Closure.DELEGATE_FIRST) Closure<T> c) {
> c.delegate = this
> c.resolveStrategy = Closure.DELEGATE_FIRST
> c()
> }
> }
> @CompileStatic
> class TypedProperty<T, D> {
> Class<T> clazz
> void eq(T t) {
> // The code fails here, expected String but got GString
> // This should have been catched by the typechecker
> // And/Or the typechecker should have automatically converted GString to
> String
> assert t.class == clazz, "t.class is ${t.class} not ${clazz}"
> }
> }
> @CompileStatic
> class Test {
> static void test() {
> Holder<Object> q = new Holder<Object>()
> // Works:
> // Typechecker catches this: Cannot call TypedProperty <String,
> Object>#eq(java.lang.String) with arguments [groovy.lang.GString]
> // q.stringProperty.eq("${0}")
>
> // Doesn't work because of delegation
> q.of {
> // Typechecker should be able to catch this as well
> // But instead it yields a runtime problem because TypedProperty is
> called with GString and assert fails
> stringProperty.eq("${0}")
>
> // Doesn't get catched by the typecherk as well - completely different
> types Long and String
> longProperty.eq("foo")
> }
> }
> }
> Test.test()
> {code}
>
--
This message was sent by Atlassian Jira
(v8.3.4#803005)