Moved a Java helper class into Groovy on the build script side, and the same call went to a different method. Laid out in order.
class Printer {
void show(Object o) { println 'object' }
void show(String s) { println 'string' }
void run(Object x) { show(x) }
}
new Printer().run('hi')
In Java the declared type of x is Object, so show(Object) is chosen at compile time and it prints object. Groovy picks the method at run time from the actual argument type, so the same code prints string. The docs describe it under the name multi-methods, so it isn't a bug.
The confusing one is the third case. Put @CompileStatic on the class and it prints object again. So the same source calls a different method depending on one annotation. I have a few more helpers with overloads split by type, and I'd like to know whether people put @CompileStatic per file or per class, or whether the right move is to get rid of the overloads altogether.