From 1678808d2ed934cf0c2a6b63af753ba1d9aa0022 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 5 Mar 2019 15:33:43 -0800 Subject: [PATCH 1/2] Start to fix def char casts. --- .../src/main/java/org/elasticsearch/painless/Def.java | 4 +++- .../test/java/org/elasticsearch/painless/DefCastTests.java | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java index c672956cb0719..5754dc7c73207 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java @@ -767,7 +767,9 @@ public static short defToshortExplicit(final Object value) { } public static char defTocharExplicit(final Object value) { - if (value instanceof Character) { + if (value instanceof String) { + return Utility.StringTochar((String)value); + } else if (value instanceof Character) { return (char)value; } else if ( value instanceof Byte || diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefCastTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefCastTests.java index 015176a43c33e..d114baa6adb35 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefCastTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefCastTests.java @@ -232,6 +232,7 @@ public void testdefToshortExplicit() { } public void testdefTocharExplicit() { + assertEquals('s', exec("def d = 's'; char b = (char)d; b")); expectScriptThrows(ClassCastException.class, () -> exec("def d = 'string'; char b = (char)d;")); expectScriptThrows(ClassCastException.class, () -> exec("def d = true; char b = (char)d;")); assertEquals((char)0, exec("def d = (byte)0; char b = (char)d; b")); From b8588999265cb9a746c65a5bc0503cf2381d7e8c Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 6 Mar 2019 10:08:34 -0800 Subject: [PATCH 2/2] Fix def char to String casts --- .../java/org/elasticsearch/painless/Def.java | 113 +++++++++++++----- .../elasticsearch/painless/MethodWriter.java | 4 + .../painless/WriterConstants.java | 3 + .../elasticsearch/painless/DefCastTests.java | 11 ++ 4 files changed, 103 insertions(+), 28 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java index 5754dc7c73207..8516a96a05c00 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java @@ -625,8 +625,9 @@ public static boolean defToboolean(final Object value) { if (value instanceof Boolean) { return (boolean)value; } else { - throw new ClassCastException( - "cannot cast def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to boolean"); + throw new ClassCastException("cannot cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + boolean.class.getCanonicalName()); } } @@ -635,7 +636,8 @@ public static byte defTobyteImplicit(final Object value) { return (byte)value; } else { throw new ClassCastException("cannot implicitly cast " + - "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to byte"); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + byte.class.getCanonicalName()); } } @@ -646,7 +648,8 @@ public static short defToshortImplicit(final Object value) { return (short)value; } else { throw new ClassCastException("cannot implicitly cast " + - "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to short"); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + short.class.getCanonicalName()); } } @@ -655,7 +658,8 @@ public static char defTocharImplicit(final Object value) { return (char)value; } else { throw new ClassCastException("cannot implicitly cast " + - "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to char"); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + char.class.getCanonicalName()); } } @@ -670,7 +674,8 @@ public static int defTointImplicit(final Object value) { return (int)value; } else { throw new ClassCastException("cannot implicitly cast " + - "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to int"); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + int.class.getCanonicalName()); } } @@ -686,9 +691,9 @@ public static long defTolongImplicit(final Object value) { } else if (value instanceof Long) { return (long)value; } else { - throw new ClassCastException( - "cannot implicitly cast " + - "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to long"); + throw new ClassCastException("cannot implicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + long.class.getCanonicalName()); } } @@ -706,9 +711,9 @@ public static float defTofloatImplicit(final Object value) { } else if (value instanceof Float) { return (float)value; } else { - throw new ClassCastException( - "cannot implicitly cast " + - "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to float"); + throw new ClassCastException("cannot implicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + float.class.getCanonicalName()); } } @@ -728,7 +733,9 @@ public static double defTodoubleImplicit(final Object value) { } else if (value instanceof Double) { return (double)value; } else { - throw new ClassCastException("cannot implicitly cast def [" + value.getClass().getCanonicalName() + "] to double"); + throw new ClassCastException("cannot implicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + double.class.getCanonicalName()); } } @@ -745,7 +752,9 @@ public static byte defTobyteExplicit(final Object value) { ) { return ((Number)value).byteValue(); } else { - throw new ClassCastException("cannot explicitly cast def [" + value.getClass().getCanonicalName() + "] to byte"); + throw new ClassCastException("cannot explicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + byte.class.getCanonicalName()); } } @@ -762,7 +771,9 @@ public static short defToshortExplicit(final Object value) { ) { return ((Number)value).shortValue(); } else { - throw new ClassCastException("cannot explicitly cast def [" + value.getClass().getCanonicalName() + "] to short"); + throw new ClassCastException("cannot explicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + short.class.getCanonicalName()); } } @@ -781,7 +792,9 @@ public static char defTocharExplicit(final Object value) { ) { return (char)((Number)value).intValue(); } else { - throw new ClassCastException("cannot explicitly cast def [" + value.getClass().getCanonicalName() + "] to char"); + throw new ClassCastException("cannot explicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + char.class.getCanonicalName()); } } @@ -798,7 +811,9 @@ public static int defTointExplicit(final Object value) { ) { return ((Number)value).intValue(); } else { - throw new ClassCastException("cannot explicitly cast def [" + value.getClass().getCanonicalName() + "] to int"); + throw new ClassCastException("cannot explicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + int.class.getCanonicalName()); } } @@ -815,7 +830,9 @@ public static long defTolongExplicit(final Object value) { ) { return ((Number)value).longValue(); } else { - throw new ClassCastException("cannot explicitly cast def [" + value.getClass().getCanonicalName() + "] to long"); + throw new ClassCastException("cannot explicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + long.class.getCanonicalName()); } } @@ -832,7 +849,9 @@ public static float defTofloatExplicit(final Object value) { ) { return ((Number)value).floatValue(); } else { - throw new ClassCastException("cannot explicitly cast def [" + value.getClass().getCanonicalName() + "] to float"); + throw new ClassCastException("cannot explicitly cast " + + "float [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + byte.class.getCanonicalName()); } } @@ -849,7 +868,9 @@ public static double defTodoubleExplicit(final Object value) { ) { return ((Number)value).doubleValue(); } else { - throw new ClassCastException("cannot explicitly cast def [" + value.getClass().getCanonicalName() + "] to double"); + throw new ClassCastException("cannot explicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + byte.class.getCanonicalName()); } } @@ -984,7 +1005,8 @@ public static Double defToDoubleImplicit(final Object value) { return (Double)value; } else { throw new ClassCastException("cannot implicitly cast " + - "def [" + value.getClass().getCanonicalName() + "] to " + Double.class.getCanonicalName()); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + Double.class.getCanonicalName()); } } @@ -1004,7 +1026,8 @@ public static Byte defToByteExplicit(final Object value) { return ((Number)value).byteValue(); } else { throw new ClassCastException("cannot explicitly cast " + - "def [" + value.getClass().getCanonicalName() + "] to " + Byte.class.getCanonicalName()); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + Byte.class.getCanonicalName()); } } @@ -1024,13 +1047,16 @@ public static Short defToShortExplicit(final Object value) { return ((Number)value).shortValue(); } else { throw new ClassCastException("cannot explicitly cast " + - "def [" + value.getClass().getCanonicalName() + "] to " + Short.class.getCanonicalName()); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + Short.class.getCanonicalName()); } } public static Character defToCharacterExplicit(final Object value) { if (value == null) { return null; + } else if (value instanceof String) { + return Utility.StringTochar((String)value); } else if (value instanceof Character) { return (Character)value; } else if ( @@ -1044,7 +1070,8 @@ public static Character defToCharacterExplicit(final Object value) { return (char)((Number)value).intValue(); } else { throw new ClassCastException("cannot explicitly cast " + - "def [" + value.getClass().getCanonicalName() + "] to " + Character.class.getCanonicalName()); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + Character.class.getCanonicalName()); } } @@ -1064,7 +1091,8 @@ public static Integer defToIntegerExplicit(final Object value) { return ((Number)value).intValue(); } else { throw new ClassCastException("cannot explicitly cast " + - "def [" + value.getClass().getCanonicalName() + "] to " + Integer.class.getCanonicalName()); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + Integer.class.getCanonicalName()); } } @@ -1084,7 +1112,8 @@ public static Long defToLongExplicit(final Object value) { return ((Number)value).longValue(); } else { throw new ClassCastException("cannot explicitly cast " + - "def [" + value.getClass().getCanonicalName() + "] to " + Long.class.getCanonicalName()); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + Long.class.getCanonicalName()); } } @@ -1104,7 +1133,8 @@ public static Float defToFloatExplicit(final Object value) { return ((Number)value).floatValue(); } else { throw new ClassCastException("cannot explicitly cast " + - "def [" + value.getClass().getCanonicalName() + "] to " + Float.class.getCanonicalName()); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + Float.class.getCanonicalName()); } } @@ -1124,7 +1154,34 @@ public static Double defToDoubleExplicit(final Object value) { return ((Number)value).doubleValue(); } else { throw new ClassCastException("cannot explicitly cast " + - "def [" + value.getClass().getCanonicalName() + "] to " + Double.class.getCanonicalName()); + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + Double.class.getCanonicalName()); + } + } + + public static String defToStringImplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof String) { + return (String)value; + } else { + throw new ClassCastException("cannot implicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + String.class.getCanonicalName()); + } + } + + public static String defToStringExplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Character) { + return Utility.charToString((char)value); + } else if (value instanceof String) { + return (String)value; + } else { + throw new ClassCastException("cannot explicitly cast " + + "def [" + PainlessLookupUtility.typeToUnboxedType(value.getClass()).getCanonicalName() + "] to " + + String.class.getCanonicalName()); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java index ea58e7df7b4da..ed4cce5ddda2e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java @@ -69,6 +69,8 @@ import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_LONG_IMPLICIT; import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_SHORT_EXPLICIT; import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_SHORT_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_STRING_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_STRING_IMPLICIT; import static org.elasticsearch.painless.WriterConstants.DEF_UTIL_TYPE; import static org.elasticsearch.painless.WriterConstants.INDY_STRING_CONCAT_BOOTSTRAP_HANDLE; import static org.elasticsearch.painless.WriterConstants.LAMBDA_BOOTSTRAP_HANDLE; @@ -188,6 +190,7 @@ public void writeCast(PainlessCast cast) { else if (cast.targetType == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_LONG_EXPLICIT); else if (cast.targetType == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_FLOAT_EXPLICIT); else if (cast.targetType == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_DOUBLE_EXPLICIT); + else if (cast.targetType == String.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_STRING_EXPLICIT); else { writeCast(cast.originalType, cast.targetType); } @@ -208,6 +211,7 @@ public void writeCast(PainlessCast cast) { else if (cast.targetType == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_LONG_IMPLICIT); else if (cast.targetType == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_FLOAT_IMPLICIT); else if (cast.targetType == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_DOUBLE_IMPLICIT); + else if (cast.targetType == String.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_STRING_IMPLICIT); else { writeCast(cast.originalType, cast.targetType); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java index 12112684f2736..7979f29cb2ec3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java @@ -158,6 +158,9 @@ public final class WriterConstants { public static final Method DEF_TO_B_FLOAT_EXPLICIT = getAsmMethod(Float.class , "defToFloatExplicit" , Object.class); public static final Method DEF_TO_B_DOUBLE_EXPLICIT = getAsmMethod(Double.class , "defToDoubleExplicit" , Object.class); + public static final Method DEF_TO_STRING_IMPLICIT = getAsmMethod(String.class, "defToStringImplicit", Object.class); + public static final Method DEF_TO_STRING_EXPLICIT = getAsmMethod(String.class, "defToStringExplicit", Object.class); + public static final Type DEF_ARRAY_LENGTH_METHOD_TYPE = Type.getMethodType(Type.INT_TYPE, Type.getType(Object.class)); /** invokedynamic bootstrap for lambda expression/method references */ diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefCastTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefCastTests.java index d114baa6adb35..c01cdcd2c970c 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefCastTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefCastTests.java @@ -85,6 +85,7 @@ public void testdefToshortImplicit() { } public void testdefTocharImplicit() { + expectScriptThrows(ClassCastException.class, () -> exec("def d = 's'; char b = d;")); expectScriptThrows(ClassCastException.class, () -> exec("def d = 'string'; char b = d;")); expectScriptThrows(ClassCastException.class, () -> exec("def d = true; char b = d;")); expectScriptThrows(ClassCastException.class, () -> exec("def d = (byte)0; char b = d;")); @@ -401,6 +402,7 @@ public void testdefToShortImplicit() { } public void testdefToCharacterImplicit() { + expectScriptThrows(ClassCastException.class, () -> exec("def d = 's'; Character b = d;")); expectScriptThrows(ClassCastException.class, () -> exec("def d = 'string'; Character b = d;")); expectScriptThrows(ClassCastException.class, () -> exec("def d = true; Character b = d;")); expectScriptThrows(ClassCastException.class, () -> exec("def d = (byte)0; Character b = d;")); @@ -569,6 +571,7 @@ public void testdefToShortExplicit() { } public void testdefToCharacterExplicit() { + assertEquals('s', exec("def d = 's'; Character b = (Character)d; b")); expectScriptThrows(ClassCastException.class, () -> exec("def d = 'string'; Character b = (Character)d;")); expectScriptThrows(ClassCastException.class, () -> exec("def d = true; Character b = (Character)d;")); assertEquals((char)0, exec("def d = (byte)0; Character b = (Character)d; b")); @@ -672,4 +675,12 @@ public void testdefToDoubleExplicit() { assertEquals((double)0, exec("def d = Double.valueOf(0); Double b = (Double)d; b")); expectScriptThrows(ClassCastException.class, () -> exec("def d = new ArrayList(); Double b = (Double)d;")); } + + public void testdefToStringImplicit() { + expectScriptThrows(ClassCastException.class, () -> exec("def d = (char)'s'; String b = d;")); + } + + public void testdefToStringExplicit() { + assertEquals("s", exec("def d = (char)'s'; String b = (String)d; b")); + } }