Felix Scheinost created GROOVY-9902:
---------------------------------------

             Summary: 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: 3.0.7, 2.5.6
            Reporter: Felix Scheinost


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