You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2016/11/12 05:10:48 UTC

groovy git commit: Refine safe index for array

Repository: groovy
Updated Branches:
  refs/heads/parrot ca21c32c9 -> 5550676f3


Refine safe index for array


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/5550676f
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/5550676f
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/5550676f

Branch: refs/heads/parrot
Commit: 5550676f31e67d6d96a6e1dbed7e02477c4170f6
Parents: ca21c32
Author: Daniel Sun <su...@apache.org>
Authored: Sat Nov 12 13:10:06 2016 +0800
Committer: Daniel Sun <su...@apache.org>
Committed: Sat Nov 12 13:10:06 2016 +0800

----------------------------------------------------------------------
 .../BinaryExpressionMultiTypeDispatcher.java    |  20 +-
 .../asm/sc/StaticTypesCallSiteWriter.java       |   2 +-
 .../stc/StaticTypeCheckingSupport.java          | 177 +++++++++++----
 .../parser/antlr4/GroovyParserTest.groovy       |   1 +
 .../test/resources/core/SafeIndex_03x.groovy    | 226 +++++++++++++++++++
 5 files changed, 377 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/5550676f/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionMultiTypeDispatcher.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionMultiTypeDispatcher.java b/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionMultiTypeDispatcher.java
index 98c2dc0..e011501 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionMultiTypeDispatcher.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionMultiTypeDispatcher.java
@@ -16,10 +16,8 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.codehaus.groovy.classgen.asm;
 
-import java.util.HashMap;
-import java.util.Map;
+package org.codehaus.groovy.classgen.asm;
 
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
@@ -32,10 +30,13 @@ import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.classgen.AsmClassGenerator;
 import org.codehaus.groovy.runtime.BytecodeInterface8;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import static org.codehaus.groovy.ast.ClassHelper.*;
+import static org.codehaus.groovy.ast.tools.WideningCategories.*;
 import static org.codehaus.groovy.syntax.TokenUtil.removeAssignment;
 import static org.codehaus.groovy.syntax.Types.*;
-import static org.codehaus.groovy.ast.tools.WideningCategories.*;
 
 /**
  * This class is for internal use only!
@@ -48,7 +49,7 @@ public class BinaryExpressionMultiTypeDispatcher extends BinaryExpressionHelper
         public BinaryCharExpressionHelper(WriterController wc) {
             super(wc, charArraySet, charArrayGet);
         }
-        private static final MethodCaller 
+        private static final MethodCaller
             charArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "cArrayGet"),
             charArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "cArraySet");
         @Override protected ClassNode getArrayGetResultType() { return ClassHelper.char_TYPE; }
@@ -58,7 +59,7 @@ public class BinaryExpressionMultiTypeDispatcher extends BinaryExpressionHelper
         public BinaryByteExpressionHelper(WriterController wc) {
             super(wc, byteArraySet, byteArrayGet);
         }
-        private static final MethodCaller 
+        private static final MethodCaller
             byteArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "bArrayGet"),
             byteArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "bArraySet");
         @Override protected ClassNode getArrayGetResultType() { return ClassHelper.byte_TYPE; }
@@ -68,7 +69,7 @@ public class BinaryExpressionMultiTypeDispatcher extends BinaryExpressionHelper
         public BinaryShortExpressionHelper(WriterController wc) {
             super(wc, shortArraySet, shortArrayGet);
         }
-        private static final MethodCaller 
+        private static final MethodCaller
             shortArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "sArrayGet"),
             shortArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "sArraySet");
         @Override protected ClassNode getArrayGetResultType() { return ClassHelper.short_TYPE; }
@@ -177,7 +178,8 @@ public class BinaryExpressionMultiTypeDispatcher extends BinaryExpressionHelper
             int operationType = getOperandType(leftType);
             BinaryExpressionWriter bew = binExpWriter[operationType];
             if (    leftTypeOrig.isArray() && isIntCastableType(rightExp) && 
-                    bew.arrayGet(operation, true)) 
+                    bew.arrayGet(operation, true) &&
+                    !binExp.isSafe())
             {
                 leftExp.visit(acg);
                 os.doGroovyCast(leftTypeOrig);
@@ -389,7 +391,7 @@ public class BinaryExpressionMultiTypeDispatcher extends BinaryExpressionHelper
     }
     
     @Override
-    protected void writePostOrPrefixMethod(int op, String method,  Expression expression, Expression orig) {
+    protected void writePostOrPrefixMethod(int op, String method, Expression expression, Expression orig) {
         ClassNode type = getController().getTypeChooser().resolveType(orig, getController().getClassNode());
         int operationType = getOperandType(type);
         BinaryExpressionWriter bew = binExpWriter[operationType];

http://git-wip-us.apache.org/repos/asf/groovy/blob/5550676f/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index a221c66..a1d18bf 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -660,7 +660,7 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
             writeStringPlusCall(receiver, message, arguments);
             return true;
         } else if ("getAt".equals(message)) {
-            if (rType.isArray() && getWrapper(aType).isDerivedFrom(Number_TYPE)) {
+            if (rType.isArray() && getWrapper(aType).isDerivedFrom(Number_TYPE) && !safe) {
                 writeArrayGet(receiver, arguments, rType, aType);
                 return true;
             } else {

http://git-wip-us.apache.org/repos/asf/groovy/blob/5550676f/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index e2d5d29..2eaf6b9 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -16,23 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
+
 package org.codehaus.groovy.transform.stc;
 
 import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.GenericsType;
-import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.Variable;
-import org.codehaus.groovy.ast.expr.ArgumentListExpression;
-import org.codehaus.groovy.ast.expr.ArrayExpression;
-import org.codehaus.groovy.ast.expr.BinaryExpression;
-import org.codehaus.groovy.ast.expr.ClosureExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.ListExpression;
-import org.codehaus.groovy.ast.expr.MapExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.*;
+import org.codehaus.groovy.ast.expr.*;
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
 import org.codehaus.groovy.ast.tools.GenericsUtils;
 import org.codehaus.groovy.ast.tools.ParameterUtils;
@@ -52,20 +41,8 @@ import org.objectweb.asm.Opcodes;
 
 import java.lang.ref.WeakReference;
 import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.UUID;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.regex.Matcher;
 
@@ -182,7 +159,7 @@ public abstract class StaticTypeCheckingSupport {
 
 
     /**
-     * @deprecated Use {@link #findDGMMethodsForClassNode(ClassLoader,ClassNode,String)} instead
+     * @deprecated Use {@link #findDGMMethodsForClassNode(ClassLoader, ClassNode,String)} instead
      */
     @Deprecated
     protected static Set<MethodNode> findDGMMethodsForClassNode(ClassNode clazz, String name) {
@@ -593,7 +570,7 @@ public abstract class StaticTypeCheckingSupport {
             return left==VOID_TYPE||left==void_WRAPPER_TYPE;
         }
 
-        if ((isNumberType(rightRedirect)||WideningCategories.isNumberCategory(rightRedirect))) {
+        if ((isNumberType(rightRedirect)|| WideningCategories.isNumberCategory(rightRedirect))) {
            if (BigDecimal_TYPE==leftRedirect) {
                // any number can be assigned to a big decimal
                return true;
@@ -899,7 +876,7 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     /**
-     * @deprecated Use {@link #findDGMMethodsByNameAndArguments(ClassLoader, org.codehaus.groovy.ast.ClassNode, String, org.codehaus.groovy.ast.ClassNode[], java.util.List)} instead
+     * @deprecated Use {@link #findDGMMethodsByNameAndArguments(ClassLoader, ClassNode, String, ClassNode[], List)} instead
      */
     @Deprecated
     public static List<MethodNode> findDGMMethodsByNameAndArguments(final ClassNode receiver, final String name, final ClassNode[] args) {
@@ -911,7 +888,7 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     /**
-     * @deprecated Use {@link #findDGMMethodsByNameAndArguments(ClassLoader, org.codehaus.groovy.ast.ClassNode, String, org.codehaus.groovy.ast.ClassNode[], List)} instead
+     * @deprecated Use {@link #findDGMMethodsByNameAndArguments(ClassLoader, ClassNode, String, ClassNode[], List)} instead
      */
     @Deprecated
     public static List<MethodNode> findDGMMethodsByNameAndArguments(final ClassNode receiver, final String name, final ClassNode[] args, final List<MethodNode> methods) {
@@ -1433,7 +1410,7 @@ public abstract class StaticTypeCheckingSupport {
     private static Set<String> extractResolvedPlaceHolders(Map<String, GenericsType> resolvedMethodGenerics) {
         if (resolvedMethodGenerics.isEmpty()) return Collections.EMPTY_SET;
         Set<String> result = new HashSet<String>();
-        for (Map.Entry<String, GenericsType> entry : resolvedMethodGenerics.entrySet()) {
+        for (Entry<String, GenericsType> entry : resolvedMethodGenerics.entrySet()) {
             GenericsType value = entry.getValue();
             if (value.isPlaceholder()) continue;
             result.add(entry.getKey());
@@ -1479,7 +1456,7 @@ public abstract class StaticTypeCheckingSupport {
 
     private static boolean compatibleConnections(Map<String, GenericsType> connections, Map<String, GenericsType> resolvedMethodGenerics, Set<String> fixedGenericsPlaceHolders)
     {
-        for (Map.Entry<String, GenericsType> entry : connections.entrySet()) {
+        for (Entry<String, GenericsType> entry : connections.entrySet()) {
             GenericsType resolved = resolvedMethodGenerics.get(entry.getKey());
             if (resolved==null) continue;
             GenericsType connection = entry.getValue();
@@ -1558,7 +1535,7 @@ public abstract class StaticTypeCheckingSupport {
         while (count<10000) {
             count++;
             boolean checkForMorePlaceHolders=false;
-            for (Map.Entry<String, GenericsType> entry: resolvedPlaceholders.entrySet()){
+            for (Entry<String, GenericsType> entry: resolvedPlaceholders.entrySet()){
                 String name = entry.getKey();
                 GenericsType replacement = connections.get(name);
                 if (replacement==null) {
@@ -1855,7 +1832,7 @@ public abstract class StaticTypeCheckingSupport {
 
     private static void applyContextGenerics(Map<String, GenericsType> resolvedPlaceholders, Map<String, GenericsType> placeholdersFromContext) {
         if (placeholdersFromContext==null) return;
-        for (Map.Entry<String, GenericsType> entry : resolvedPlaceholders.entrySet()) {
+        for (Entry<String, GenericsType> entry : resolvedPlaceholders.entrySet()) {
             GenericsType gt = entry.getValue();
             if (gt.isPlaceholder()) {
                 String name = gt.getName();
@@ -1948,11 +1925,124 @@ public abstract class StaticTypeCheckingSupport {
      * A DGM-like method which adds support for method calls which are handled
      * specifically by the Groovy compiler.
      */
-    private static class ObjectArrayStaticTypesHelper {
-        public static <T> T getAt(T[] arr, int index) { return null;}
-        public static <T,U extends T> void putAt(T[] arr, int index, U object) { }
+    public static class ObjectArrayStaticTypesHelper {
+        public static <T> T getAt(T[] arr, int index) {
+            return null == arr ? null : arr[index];
+        }
+        public static <T,U extends T> void putAt(T[] arr, int index, U object) {
+            if (null == arr) {
+                return;
+            }
+
+            arr[index] = object;
+        }
+    }
+
+    public static class BooleanArrayStaticTypesHelper {
+        public static Boolean getAt(boolean[] arr, int index) {
+            return null == arr ? null : arr[index];
+        }
+        public static void putAt(boolean[] arr, int index, boolean object) {
+            if (null == arr) {
+                return;
+            }
+
+            arr[index] = object;
+        }
+    }
+
+    public static class CharArrayStaticTypesHelper {
+        public static Character getAt(char[] arr, int index) {
+            return null == arr ? null : arr[index];
+        }
+        public static void putAt(char[] arr, int index, char object) {
+            if (null == arr) {
+                return;
+            }
+
+            arr[index] = object;
+        }
+    }
+
+    public static class ByteArrayStaticTypesHelper {
+        public static Byte getAt(byte[] arr, int index) {
+            return null == arr ? null : arr[index];
+        }
+        public static void putAt(byte[] arr, int index, byte object) {
+            if (null == arr) {
+                return;
+            }
+
+            arr[index] = object;
+        }
+    }
+
+    public static class ShortArrayStaticTypesHelper {
+        public static Short getAt(short[] arr, int index) {
+            return null == arr ? null : arr[index];
+        }
+        public static void putAt(short[] arr, int index, short object) {
+            if (null == arr) {
+                return;
+            }
+
+            arr[index] = object;
+        }
+    }
+
+    public static class IntArrayStaticTypesHelper {
+        public static Integer getAt(int[] arr, int index) {
+            return null == arr ? null : arr[index];
+        }
+        public static void putAt(int[] arr, int index, int object) {
+            if (null == arr) {
+                return;
+            }
+
+            arr[index] = object;
+        }
+    }
+
+    public static class LongArrayStaticTypesHelper {
+        public static Long getAt(long[] arr, int index) {
+            return null == arr ? null : arr[index];
+        }
+        public static void putAt(long[] arr, int index, long object) {
+            if (null == arr) {
+                return;
+            }
+
+            arr[index] = object;
+        }
     }
 
+    public static class FloatArrayStaticTypesHelper {
+        public static Float getAt(float[] arr, int index) {
+            return null == arr ? null : arr[index];
+        }
+        public static void putAt(float[] arr, int index, float object) {
+            if (null == arr) {
+                return;
+            }
+
+            arr[index] = object;
+        }
+    }
+
+    public static class DoubleArrayStaticTypesHelper {
+        public static Double getAt(double[] arr, int index) {
+            return null == arr ? null : arr[index];
+        }
+        public static void putAt(double[] arr, int index, double object) {
+            if (null == arr) {
+                return;
+            }
+
+            arr[index] = object;
+        }
+    }
+
+
     /**
      * This class is used to make extension methods lookup faster. Basically, it will only
      * collect the list of extension methods (see {@link ExtensionModule} if the list of
@@ -2020,7 +2110,16 @@ public abstract class StaticTypeCheckingSupport {
             Collections.addAll(instanceExtClasses, DefaultGroovyMethods.DGM_LIKE_CLASSES);
             Collections.addAll(instanceExtClasses, DefaultGroovyMethods.additionals);
             staticExtClasses.add(DefaultGroovyStaticMethods.class);
+
             instanceExtClasses.add(ObjectArrayStaticTypesHelper.class);
+            instanceExtClasses.add(BooleanArrayStaticTypesHelper.class);
+            instanceExtClasses.add(CharArrayStaticTypesHelper.class);
+            instanceExtClasses.add(ByteArrayStaticTypesHelper.class);
+            instanceExtClasses.add(ShortArrayStaticTypesHelper.class);
+            instanceExtClasses.add(IntArrayStaticTypesHelper.class);
+            instanceExtClasses.add(LongArrayStaticTypesHelper.class);
+            instanceExtClasses.add(FloatArrayStaticTypesHelper.class);
+            instanceExtClasses.add(DoubleArrayStaticTypesHelper.class);
 
             scanClassesForDGMMethods(methods, staticExtClasses, true);
             scanClassesForDGMMethods(methods, instanceExtClasses, false);
@@ -2133,7 +2232,7 @@ public abstract class StaticTypeCheckingSupport {
         String className = "Expression$" + UUID.randomUUID().toString().replace('-', '$');
         ClassNode node = new ClassNode(className, Opcodes.ACC_PUBLIC, OBJECT_TYPE);
         ReturnStatement code = new ReturnStatement(expr);
-        node.addMethod(new MethodNode("eval", Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC, OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code));
+        node.addMethod(new MethodNode("eval", Opcodes.ACC_PUBLIC+ Opcodes.ACC_STATIC, OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code));
         CompilerConfiguration copyConf = new CompilerConfiguration(config);
         CompilationUnit cu = new CompilationUnit(copyConf);
         cu.addClassNode(node);

http://git-wip-us.apache.org/repos/asf/groovy/blob/5550676f/subprojects/groovy-antlr4-grammar/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-antlr4-grammar/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy b/subprojects/groovy-antlr4-grammar/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
index 01f0767..43e46cd 100644
--- a/subprojects/groovy-antlr4-grammar/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
+++ b/subprojects/groovy-antlr4-grammar/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
@@ -223,6 +223,7 @@ class GroovyParserTest extends GroovyTestCase {
     void "test groovy core - SafeIndex"() {
         doRunAndTest('core/SafeIndex_01x.groovy');
         doRunAndTest('core/SafeIndex_02x.groovy');
+        doRunAndTest('core/SafeIndex_03x.groovy');
     }
 
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/5550676f/subprojects/groovy-antlr4-grammar/src/test/resources/core/SafeIndex_03x.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-antlr4-grammar/src/test/resources/core/SafeIndex_03x.groovy b/subprojects/groovy-antlr4-grammar/src/test/resources/core/SafeIndex_03x.groovy
new file mode 100644
index 0000000..ec800cd
--- /dev/null
+++ b/subprojects/groovy-antlr4-grammar/src/test/resources/core/SafeIndex_03x.groovy
@@ -0,0 +1,226 @@
+import groovy.transform.*
+
+@CompileStatic
+def csObjArray() {
+    String[] array = ['a', 'b'];
+    assert 'b' == array?[1];
+
+    array?[1] = 'c';
+    assert 'c' == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+csObjArray();
+
+def objArray() {
+    String[] array = ['a', 'b'];
+    assert 'b' == array?[1];
+
+    array?[1] = 'c';
+    assert 'c' == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+objArray();
+
+@CompileStatic
+def csBooleanArray() {
+    boolean[] array = [true, false];
+    assert false == array?[1];
+
+    array?[1] = true;
+    assert true == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+csBooleanArray();
+
+def booleanArray() {
+    boolean[] array = [true, false];
+    assert false == array?[1];
+
+    array?[1] = true;
+    assert true == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+booleanArray();
+
+@CompileStatic
+def csCharArray() {
+    char[] array = ['a' as char, 'b' as char];
+    assert ('b' as char) == array?[1];
+
+    array?[1] = 'c';
+    assert ('c' as char) == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+csCharArray();
+
+def charArray() {
+    char[] array = ['a' as char, 'b' as char];
+    assert ('b' as char) == array?[1];
+
+    array?[1] = 'c';
+    assert ('c' as char) == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+charArray();
+
+@CompileStatic
+def csByteArray() {
+    byte[] array = [1 as byte, 2 as byte];
+    assert (2 as byte) == array?[1];
+
+    array?[1] = 3 as byte;
+    assert (3 as byte) == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+csByteArray();
+
+def byteArray() {
+    byte[] array = [1 as byte, 2 as byte];
+    assert (2 as byte) == array?[1];
+
+    array?[1] = 3 as byte;
+    assert (3 as byte) == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+byteArray();
+
+@CompileStatic
+def csShortArray() {
+    short[] array = [1, 2];
+    assert 2 == array?[1];
+
+    array?[1] = 3;
+    assert 3 == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+csShortArray();
+
+def shortArray() {
+    short[] array = [1, 2];
+    assert 2 == array?[1];
+
+    array?[1] = 3;
+    assert 3 == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+shortArray();
+
+@CompileStatic
+def csIntArray() {
+    int[] array = [1, 2];
+    assert 2 == array?[1];
+
+    array?[1] = 3;
+    assert 3 == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+csIntArray();
+
+def intArray() {
+    int[] array = [1, 2];
+    assert 2 == array?[1];
+
+    array?[1] = 3;
+    assert 3 == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+intArray();
+
+@CompileStatic
+def csLongArray() {
+    long[] array = [1L, 2L];
+    assert 2L == array?[1];
+
+    array?[1] = 3L;
+    assert 3L == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+csLongArray();
+
+def longArray() {
+    long[] array = [1L, 2L];
+    assert 2L == array?[1];
+
+    array?[1] = 3L;
+    assert 3L == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+longArray();
+
+@CompileStatic
+def csFloatArray() {
+    float[] array = [1.1f, 2.2f];
+    assert 2.2f == array?[1];
+
+    array?[1] = 3.3f;
+    assert 3.3f == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+csFloatArray();
+
+def floatArray() {
+    float[] array = [1.1f, 2.2f];
+    assert 2.2f == array?[1];
+
+    array?[1] = 3.3f;
+    assert 3.3f == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+floatArray();
+
+@CompileStatic
+def csDoubleArray() {
+    double[] array = [1.1d, 2.2d];
+    assert 2.2d == array?[1];
+
+    array?[1] = 3.3d;
+    assert 3.3d == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+csDoubleArray();
+
+def doubleArray() {
+    double[] array = [1.1d, 2.2d];
+    assert 2.2d == array?[1];
+
+    array?[1] = 3.3d;
+    assert 3.3d == array?[1];
+
+    array = null;
+    assert null == array?[1];
+}
+doubleArray();
\ No newline at end of file