You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Shil Sinha (JIRA)" <ji...@apache.org> on 2015/10/04 06:26:26 UTC

[jira] [Comment Edited] (GROOVY-7597) Static Compiler tries to cast delegate to target type of property accessor

    [ https://issues.apache.org/jira/browse/GROOVY-7597?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14942548#comment-14942548 ] 

Shil Sinha edited comment on GROOVY-7597 at 10/4/15 4:26 AM:
-------------------------------------------------------------

The problem seems to be in StaticInvocationWriter.tryImplicitReceiver, where the receiver of the {{getCalculation("whatever")}} call, implicitly {{this.delegate}}, has its INFERRED_TYPE metadata set to the PROPERTY_OWNER metadata of the getCalculation call. However, that metadata is set to {{Calculation}} earlier in StaticCompilationVisitor.existsProperty while visiting the .valid property expression. 

None of this causes the direct method call target to change, so the only strangeness that appears in the bytecode is the checkcast Calculation and the runtime cast to Entity (which should really be Feature) as you mentioned.

Another temporary workaround is to explicitly call delegate.getCalculation, in which case the checkcasts are for Feature and there are no runtime casts.


was (Author: shils):
The problem seems to be in StaticInvocationWriter.tryImplicitReceiver, where the INFERRED_TYPE metadata for the receiver of the {{getCalculation("whatever")}} call, implicitly {{this.delegate}}, is set to the PROPERTY_OWNER metadata of the getCalculation call. However, that metadata is set to {{Calculation}} earlier in StaticCompilationVisitor.existsProperty while visiting the .valid property expression. 

None of this causes the direct method call target to change, so the only strangeness that appears in the bytecode is the checkcast Calculation and the runtime cast to Entity (which should really be Feature) as you mentioned.

Another temporary workaround is to explicitly call delegate.getCalculation, in which case the checkcasts are for Feature and there are no runtime casts.

> Static Compiler tries to cast delegate to target type of property accessor
> --------------------------------------------------------------------------
>
>                 Key: GROOVY-7597
>                 URL: https://issues.apache.org/jira/browse/GROOVY-7597
>             Project: Groovy
>          Issue Type: Bug
>          Components: Static compilation, Static Type Checker
>    Affects Versions: 2.4.3, 2.4.4
>            Reporter: Jason Winnebeck
>            Assignee: Cédric Champeau
>
> I've been able to finally isolate a static compiler issue with accessing properties on delegates that occur within our projects:
> {code}
> class Calculation {
>   boolean isValid() { true }
> }
> class Entity {
>   Calculation getCalculation(String name) { new Calculation() }
> }
> class Feature extends Entity {
> }
> void DoWithFeature(@DelegatesTo(Feature) Closure c) {
>   new Feature().with(c)
> }
> @groovy.transform.CompileStatic
> void doIt() {
>   DoWithFeature() {
>     println getCalculation("whatever").valid
>   }
> }
> doIt()
> {code}
> The result is {{java.lang.ClassCastException: Feature cannot be cast to Calculation}}
> Workarounds:
> * change the property access into a method access "valid" -> "isValid()"
> * Remove CompileStatic annotation
> As seen in the following bytecode, the static compiler tries to cast the delegate to Calculation (which always fails), then tries to call ScriptBytecodeAdapter.castToType to try to cast the "Calculation" back to an Entity to properly call getCalculation("").isValid() on it.
> {code}
>   // access flags 0x1
>   public doCall(Ljava/lang/Object;)Ljava/lang/Object;
>    L0
>     LINENUMBER 19 L0
>     ALOAD 0
>     CHECKCAST script1442861431462$_doIt_closure1
>     INVOKEVIRTUAL script1442861431462$_doIt_closure1.getThisObject ()Ljava/lang/Object;
>     LDC Lgroovy/lang/Script;.class
>     INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
>     CHECKCAST groovy/lang/Script
>     ALOAD 0
>     CHECKCAST script1442861431462$_doIt_closure1
>     INVOKEVIRTUAL script1442861431462$_doIt_closure1.getDelegate ()Ljava/lang/Object;
>     CHECKCAST Calculation
>     LDC LEntity;.class
>     INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
>     CHECKCAST Entity
>     LDC "whatever"
>     INVOKEVIRTUAL Entity.getCalculation (Ljava/lang/String;)LCalculation;
>     INVOKEVIRTUAL Calculation.isValid ()Z
>     INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;
>     INVOKEVIRTUAL groovy/lang/Script.println (Ljava/lang/Object;)V
>     ACONST_NULL
>     ARETURN
>    L1
>     ACONST_NULL
>     ARETURN
>     LOCALVARIABLE this Lscript1442861431462$_doIt_closure1; L0 L1 0
>     LOCALVARIABLE it Ljava/lang/Object; L0 L1 1
>     MAXSTACK = 3
>     MAXLOCALS = 2
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)