You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Paul King (Jira)" <ji...@apache.org> on 2021/03/15 07:24:00 UTC

[jira] [Updated] (GROOVY-9902) Generic typecheck in @DelegatesTo doesn't work

     [ https://issues.apache.org/jira/browse/GROOVY-9902?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Paul King updated GROOVY-9902:
------------------------------
    Fix Version/s: 3.0.8

> 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
>            Assignee: Eric Milles
>            Priority: Major
>             Fix For: 3.0.8, 4.0.0-alpha-3
>
>          Time Spent: 1h
>  Remaining Estimate: 0h
>
> 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)