Shil Sinha created GROOVY-7656: ---------------------------------- Summary: Spread safe method calls on list literals result in the list expression being evaluated twice (SC) Key: GROOVY-7656 URL: https://issues.apache.org/jira/browse/GROOVY-7656 Project: Groovy Issue Type: Bug Components: Static compilation Affects Versions: 2.4.5 Reporter: Shil Sinha Assignee: Cédric Champeau Priority: Critical
When a list literal is the receiver for a statically compiled spread safe method call expression, the instructions to create the list are included twice. Example: {code} @groovy.transform.CompileStatic void test() { ['a']*.size() } {code} The bytecode for the method above is: {code} L0 LINENUMBER 3 L0 NEW java/util/ArrayList DUP INVOKESPECIAL java/util/ArrayList.<init> ()V ASTORE 1 L1 ALOAD 1 POP ICONST_1 ANEWARRAY java/lang/Object DUP ICONST_0 LDC "a" AASTORE INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List; IFNULL L2 ACONST_NULL ASTORE 2 L3 ICONST_1 ANEWARRAY java/lang/Object DUP ICONST_0 LDC "a" AASTORE INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List; INVOKEINTERFACE java/util/List.iterator ()Ljava/util/Iterator; ASTORE 3 L4 ALOAD 3 INVOKEINTERFACE java/util/Iterator.hasNext ()Z IFEQ L2 ALOAD 3 INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object; ASTORE 2 ALOAD 1 ALOAD 2 DUP ASTORE 4 IFNULL L5 ALOAD 4 INVOKESTATIC org/codehaus/groovy/runtime/typehandling/ShortTypeHandling.castToString (Ljava/lang/Object;)Ljava/lang/String; CHECKCAST java/lang/String INVOKESTATIC org/codehaus/groovy/runtime/StringGroovyMethods.size (Ljava/lang/String;)I INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer; GOTO L6 L5 ACONST_NULL L6 INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z POP GOTO L4 L2 ALOAD 1 POP {code} If the list expression contains method calls that have side effects, this can cause serious problems. The example below is trivial, but shows the general case: {code} @groovy.transform.CompileStatic void test() { def list = ['abc'] def lengths = [list.removeAt(0)]*.length() // throws IndexOutOfBoundsException } {code} -- This message was sent by Atlassian JIRA (v6.3.4#6332)