Search code examples
groovytype-conversiontypechecking

Groovy - Type checking in script not working as expected


I have a Groovy application in which I allow the user to add custom behavior via Groovy scripts. I include those scripts via GroovyShell and type check them via Type Checking Extensions. The full code of how I include the script in my application is:

def config = new CompilerConfiguration()
config.addCompilationCustomizers(
    new ASTTransformationCustomizer(TypeChecked)
)
def shell = new GroovyShell(config)
shell.evaluate(new File("path/to/some/file.groovy"))

This works fine. However, type checking in the script seems to be seriously broken. For example, I can include the following scripts without any complaint from the compiler:

String test = getTestValue() // automatic conversion from Integer to String. But WHY?
println "The value is $test" // shows as "The value is 0" on the console

private Integer getTestValue(){
    return 0
}

I can even go further than that. When creating a class inside the script, I can assign it to a String without any error:

String y = new Test()
println y // shows Test@somenr on the console

class Test { }

Other type checks do work. I have not discovered any logic behind it yet, so any pointers in the right direction are greatly appreciated.


Solution

  • If in doubt, disasm. This is the bit around a call similar to yours: String x = new T():

       0: invokestatic  #17                 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
       3: astore_1
       4: aload_1
       5: ldc           #40                 // int 1
       7: aaload
       8: ldc           #42                 // class T
      10: invokeinterface #46,  2           // InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callConstructor:(Ljava/lang/Object;)Ljava/lang/Object;
      15: invokestatic  #52                 // Method org/codehaus/groovy/runtime/typehandling/ShortTypeHandling.castToString:(Ljava/lang/Object;)Ljava/lang/String;
      18: checkcast     #54                 // class java/lang/String
    

    So this is the culprit for that cast. This seems also to hold true for @TypeChecked/@CompileStatic.