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