[ 
https://issues.apache.org/jira/browse/GROOVY-9902?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17268830#comment-17268830
 ] 

Felix Scheinost commented on GROOVY-9902:
-----------------------------------------

Hmm, ideally the signature of "of" should look like this:

{code:java}
SomeOtherType<D> of(@DelegatesTo(value = Holder<D>, strategy = 
Closure.DELEGATE_FIRST) Closure<SomeOtherType<T>> c) {
{code}

But Holder<D> is not possible with @DelegatesTo, right?

I agree that the code isn't ideal.

But still I think that the typechecker should catch that because even if "D" is 
unknown T is safely known to be String/Long in TypedProperty. So the 
typechecker should be able to infer that the method call is always wrong, 
irrespective of the value of D.

I personally place a lot of trust on pieces of code annotated with 
"@CompileStatic" and I think that a typechecker that is too strict is 
preferably over a too lax one. In this case I was surprised with a runtime 
error when I thought that would be prevented by the typechecker.

> 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)

Reply via email to