Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
2.5.6, 3.0.7
-
None
Description
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
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()