Paul King created GROOVY-11967:
----------------------------------

             Summary: VerifyError in @CompileStatic constructor with 
default-valued list parameter
                 Key: GROOVY-11967
                 URL: https://issues.apache.org/jira/browse/GROOVY-11967
             Project: Groovy
          Issue Type: Bug
            Reporter: Paul King


h3. Summary

A {{@CompileStatic}} class with a constructor that has a default-valued 
list-literal parameter triggers {{VerifyError}} when the synthesised 
lower-arity bridge constructor is loaded.

h3. Repro

{code:java}
@CompileStatic
class Foo {
    Foo(Class<?> a, MessageSource b, List<Class> targetTypes = [Object]) {
    }
}
new Foo(String, ms) // boom
{code}

h3. Symptom

{noformat}
java.lang.VerifyError: Bad type on operand stack
  Location: Foo.<init>(Ljava/lang/Class;LMessageSource;)V @20: invokevirtual
  Reason:   Type 'java/lang/Object' (current frame, stack[4]) is not assignable 
to 'java/util/ArrayList'
{noformat}

h3. Root cause

Introduced by GROOVY-8699 (commit {{7b18440c4f}}, master only). That change 
replaced the {{ScriptBytecodeAdapter.createList(Object[])}} call (returns 
{{List}}) with direct {{new ArrayList\(n) + .add(...)}} bytecode, generated by 
{{ListExpressionTransformer$NewListExpression.visit()}}.

In indy mode the constructor call lowers to {{invokedynamic 
init:(Class;I)Object}} -- the JVM stack value is typed as {{Object}}, so the 
subsequent {{INVOKEVIRTUAL java/util/ArrayList.add(Object)Z}} fails 
verification because its receiver is not an {{ArrayList}}. The {{CHECKCAST}} to 
{{List}} added later by the transformer happens after the {{add}} call, too 
late.

h3. Scope

Not specific to {{List<Class>}} -- any default {{[...]}} literal in a 
{{@CompileStatic}} constructor is affected ({{List<String>}}, 
{{List<Integer>}}, {{List<List<String>>}}, etc.). Map defaults go through a 
different transformer and are not affected.

h3. Fix

Insert {{CHECKCAST java/util/ArrayList}} immediately after the constructor call 
in {{ListExpressionTransformer$NewListExpression.visit()}}, before the loop 
that emits the per-element {{DUP / add / pop}}.

h3. Affects

Master only. Groovy 5.0.x and earlier are fine (used the 
{{createList(Object[])}} helper).




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to