diff --git a/docs/painless/painless-casting.asciidoc b/docs/painless/painless-casting.asciidoc index 4bcd14cbfc6a1..cf5a8a0adafe1 100644 --- a/docs/painless/painless-casting.asciidoc +++ b/docs/painless/painless-casting.asciidoc @@ -501,7 +501,7 @@ indicates whether a cast to the specified target type is implicit (I), explicit |==== | | o | b | s | c | i | j | f | d | O | B | S | C | I | L | F | D | T | R | def | def as boolean | I | - | - | - | - | - | - | - | I | - | - | - | - | - | - | - | - | - | -| def as byte | - | I | I | I | I | I | I | I | - | I | I | I | I | I | I | I | - | - | +| def as byte | - | I | I | E | I | I | I | I | - | I | I | E | I | I | I | I | - | - | | def as short | - | E | I | E | I | I | I | I | - | E | I | E | I | I | I | I | - | - | | def as char | - | E | E | I | I | I | I | I | - | E | E | I | I | I | I | I | E | - | | def as int | - | E | E | E | I | I | I | I | - | E | E | E | I | I | I | I | - | - | @@ -509,7 +509,7 @@ indicates whether a cast to the specified target type is implicit (I), explicit | def as float | - | E | E | E | E | E | I | I | - | E | E | E | E | E | I | I | - | - | | def as double | - | E | E | E | E | E | E | I | - | E | E | E | E | E | E | I | - | - | | def as Boolean | I | - | - | - | - | - | - | - | I | - | - | - | | - | - | - | - | - | -| def as Byte | - | I | I | I | I | I | I | I | - | I | I | I | I | I | I | I | - | - | +| def as Byte | - | I | I | E | I | I | I | I | - | I | I | E | I | I | I | I | - | - | | def as Short | - | E | I | E | I | I | I | I | - | E | I | E | I | I | I | I | - | - | | def as Character | - | E | E | I | I | I | I | I | - | E | E | I | I | I | I | I | - | - | | def as Integer | - | E | E | E | I | I | I | I | - | E | E | E | I | I | I | I | - | - | 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 1e17d6024d4d1..448f43383f537 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 @@ -620,17 +620,17 @@ static MethodHandle lookupIterator(Class receiverClass) { } - // Conversion methods for Def to primitive types. + // Conversion methods for def to primitive types. - public static boolean DefToboolean(final Object value) { + public static boolean defToboolean(final Object value) { return (boolean)value; } - public static byte DefTobyteImplicit(final Object value) { + public static byte defTobyteImplicit(final Object value) { return (byte)value; } - public static short DefToshortImplicit(final Object value) { + public static short defToshortImplicit(final Object value) { if (value instanceof Byte) { return (byte)value; } else { @@ -638,15 +638,11 @@ public static short DefToshortImplicit(final Object value) { } } - public static char DefTocharImplicit(final Object value) { - if (value instanceof Byte) { - return (char)(byte)value; - } else { - return (char)value; - } + public static char defTocharImplicit(final Object value) { + return (char)value; } - public static int DefTointImplicit(final Object value) { + public static int defTointImplicit(final Object value) { if (value instanceof Byte) { return (byte)value; } else if (value instanceof Short) { @@ -658,7 +654,7 @@ public static int DefTointImplicit(final Object value) { } } - public static long DefTolongImplicit(final Object value) { + public static long defTolongImplicit(final Object value) { if (value instanceof Byte) { return (byte)value; } else if (value instanceof Short) { @@ -672,7 +668,7 @@ public static long DefTolongImplicit(final Object value) { } } - public static float DefTofloatImplicit(final Object value) { + public static float defTofloatImplicit(final Object value) { if (value instanceof Byte) { return (byte)value; } else if (value instanceof Short) { @@ -688,7 +684,7 @@ public static float DefTofloatImplicit(final Object value) { } } - public static double DefTodoubleImplicit(final Object value) { + public static double defTodoubleImplicit(final Object value) { if (value instanceof Byte) { return (byte)value; } else if (value instanceof Short) { @@ -706,7 +702,7 @@ public static double DefTodoubleImplicit(final Object value) { } } - public static byte DefTobyteExplicit(final Object value) { + public static byte defTobyteExplicit(final Object value) { if (value instanceof Character) { return (byte)(char)value; } else { @@ -714,7 +710,7 @@ public static byte DefTobyteExplicit(final Object value) { } } - public static short DefToshortExplicit(final Object value) { + public static short defToshortExplicit(final Object value) { if (value instanceof Character) { return (short)(char)value; } else { @@ -722,15 +718,15 @@ public static short DefToshortExplicit(final Object value) { } } - public static char DefTocharExplicit(final Object value) { + public static char defTocharExplicit(final Object value) { if (value instanceof Character) { - return ((Character)value); + return (char)value; } else { return (char)((Number)value).intValue(); } } - public static int DefTointExplicit(final Object value) { + public static int defTointExplicit(final Object value) { if (value instanceof Character) { return (char)value; } else { @@ -738,7 +734,7 @@ public static int DefTointExplicit(final Object value) { } } - public static long DefTolongExplicit(final Object value) { + public static long defTolongExplicit(final Object value) { if (value instanceof Character) { return (char)value; } else { @@ -746,7 +742,7 @@ public static long DefTolongExplicit(final Object value) { } } - public static float DefTofloatExplicit(final Object value) { + public static float defTofloatExplicit(final Object value) { if (value instanceof Character) { return (char)value; } else { @@ -754,7 +750,7 @@ public static float DefTofloatExplicit(final Object value) { } } - public static double DefTodoubleExplicit(final Object value) { + public static double defTodoubleExplicit(final Object value) { if (value instanceof Character) { return (char)value; } else { @@ -762,6 +758,164 @@ public static double DefTodoubleExplicit(final Object value) { } } + // Conversion methods for def to boxed types. + + public static Short defToShortImplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Byte) { + return (short)(byte)value; + } else { + return (Short)value; + } + } + + public static Character defToCharacterImplicit(final Object value) { + if (value == null) { + return null; + } else { + return (Character)value; + } + } + + public static Integer defToIntegerImplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Byte) { + return (int)(byte)value; + } else if (value instanceof Short) { + return (int)(short)value; + } else if (value instanceof Character) { + return (int)(char)value; + } else { + return (Integer)value; + } + } + + public static Long defToLongImplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Byte) { + return (long)(byte)value; + } else if (value instanceof Short) { + return (long)(short)value; + } else if (value instanceof Character) { + return (long)(char)value; + } else if (value instanceof Integer) { + return (long)(int)value; + } else { + return (Long)value; + } + } + + public static Float defToFloatImplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Byte) { + return (float)(byte)value; + } else if (value instanceof Short) { + return (float)(short)value; + } else if (value instanceof Character) { + return (float)(char)value; + } else if (value instanceof Integer) { + return (float)(int)value; + } else if (value instanceof Long) { + return (float)(long)value; + } else { + return (Float)value; + } + } + + public static Double defToDoubleImplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Byte) { + return (double)(byte)value; + } else if (value instanceof Short) { + return (double)(short)value; + } else if (value instanceof Character) { + return (double)(char)value; + } else if (value instanceof Integer) { + return (double)(int)value; + } else if (value instanceof Long) { + return (double)(long)value; + } else if (value instanceof Float) { + return (double)(float)value; + } else { + return (Double)value; + } + } + + public static Byte defToByteExplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Character) { + return (byte)(char)value; + } else { + return ((Number)value).byteValue(); + } + } + + public static Short defToShortExplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Character) { + return (short)(char)value; + } else { + return ((Number)value).shortValue(); + } + } + + public static Character defToCharacterExplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Character) { + return (Character)value; + } else { + return (char)((Number)value).intValue(); + } + } + + public static Integer defToIntegerExplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Character) { + return (int)(char)value; + } else { + return ((Number)value).intValue(); + } + } + + public static Long defToLongExplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Character) { + return (long)(char)value; + } else { + return ((Number)value).longValue(); + } + } + + public static Float defToFloatExplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Character) { + return (float)(char)value; + } else { + return ((Number)value).floatValue(); + } + } + + public static Double defToDoubleExplicit(final Object value) { + if (value == null) { + return null; + } else if (value instanceof Character) { + return (double)(char)value; + } else { + return ((Number)value).doubleValue(); + } + } + /** * "Normalizes" the index into a {@code Map} by making no change to the index. */ 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 a39453838f307..dc9725a5dd7e5 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 @@ -39,21 +39,34 @@ import static org.elasticsearch.painless.WriterConstants.CHAR_TO_STRING; import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_BOOLEAN; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_BYTE_EXPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_BYTE_IMPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_CHAR_EXPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_CHAR_IMPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_DOUBLE_EXPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_DOUBLE_IMPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_FLOAT_EXPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_FLOAT_IMPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_INT_EXPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_INT_IMPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_LONG_EXPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_LONG_IMPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_SHORT_EXPLICIT; -import static org.elasticsearch.painless.WriterConstants.DEF_TO_SHORT_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_BYTE_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_CHARACTER_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_CHARACTER_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_DOUBLE_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_DOUBLE_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_FLOAT_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_FLOAT_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_INTEGER_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_INTEGER_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_LONG_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_LONG_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_SHORT_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_B_SHORT_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_BOOLEAN; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_BYTE_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_BYTE_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_CHAR_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_CHAR_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_DOUBLE_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_DOUBLE_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_FLOAT_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_FLOAT_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_INT_EXPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_INT_IMPLICIT; +import static org.elasticsearch.painless.WriterConstants.DEF_TO_P_LONG_EXPLICIT; +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_UTIL_TYPE; import static org.elasticsearch.painless.WriterConstants.INDY_STRING_CONCAT_BOOTSTRAP_HANDLE; import static org.elasticsearch.painless.WriterConstants.LAMBDA_BOOTSTRAP_HANDLE; @@ -145,26 +158,26 @@ public void writeCast(PainlessCast cast) { } else if (cast.unboxTargetType != null) { if (cast.originalType == def.class) { if (cast.explicitCast) { - if (cast.targetType == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); - else if (cast.targetType == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_EXPLICIT); - else if (cast.targetType == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_EXPLICIT); - else if (cast.targetType == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_EXPLICIT); - else if (cast.targetType == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_EXPLICIT); - else if (cast.targetType == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_EXPLICIT); - else if (cast.targetType == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_EXPLICIT); - else if (cast.targetType == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_EXPLICIT); + if (cast.targetType == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_BOOLEAN); + else if (cast.targetType == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_BYTE_EXPLICIT); + else if (cast.targetType == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_SHORT_EXPLICIT); + else if (cast.targetType == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_CHAR_EXPLICIT); + else if (cast.targetType == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_INT_EXPLICIT); + else if (cast.targetType == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_LONG_EXPLICIT); + else if (cast.targetType == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_FLOAT_EXPLICIT); + else if (cast.targetType == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_DOUBLE_EXPLICIT); else { throw new IllegalStateException("Illegal tree structure."); } } else { - if (cast.targetType == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); - else if (cast.targetType == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_IMPLICIT); - else if (cast.targetType == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_IMPLICIT); - else if (cast.targetType == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_IMPLICIT); - else if (cast.targetType == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_IMPLICIT); - else if (cast.targetType == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_IMPLICIT); - else if (cast.targetType == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_IMPLICIT); - else if (cast.targetType == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_IMPLICIT); + if (cast.targetType == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_BOOLEAN); + else if (cast.targetType == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_BYTE_IMPLICIT); + else if (cast.targetType == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_SHORT_IMPLICIT); + else if (cast.targetType == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_CHAR_IMPLICIT); + else if (cast.targetType == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_INT_IMPLICIT); + else if (cast.targetType == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_LONG_IMPLICIT); + else if (cast.targetType == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_FLOAT_IMPLICIT); + else if (cast.targetType == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_P_DOUBLE_IMPLICIT); else { throw new IllegalStateException("Illegal tree structure."); } @@ -180,7 +193,32 @@ public void writeCast(PainlessCast cast) { writeCast(cast.originalType, cast.targetType); box(getType(cast.boxTargetType)); } else { - writeCast(cast.originalType, cast.targetType); + if (cast.originalType == def.class) { + if (cast.explicitCast) { + if (cast.targetType == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_BYTE_EXPLICIT); + else if (cast.targetType == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_SHORT_EXPLICIT); + else if (cast.targetType == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_CHARACTER_EXPLICIT); + else if (cast.targetType == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_INTEGER_EXPLICIT); + 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 { + writeCast(cast.originalType, cast.targetType); + } + } else { + if (cast.targetType == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_SHORT_IMPLICIT); + else if (cast.targetType == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_CHARACTER_IMPLICIT); + else if (cast.targetType == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_B_INTEGER_IMPLICIT); + 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 { + writeCast(cast.originalType, cast.targetType); + } + } + } 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 9c3d991080d26..c361edec915db 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 @@ -123,21 +123,37 @@ public final class WriterConstants { Map.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class, int.class, Object[].class); public static final Type DEF_UTIL_TYPE = Type.getType(Def.class); - public static final Method DEF_TO_BOOLEAN = getAsmMethod(boolean.class, "DefToboolean" , Object.class); - public static final Method DEF_TO_BYTE_IMPLICIT = getAsmMethod(byte.class , "DefTobyteImplicit" , Object.class); - public static final Method DEF_TO_SHORT_IMPLICIT = getAsmMethod(short.class , "DefToshortImplicit" , Object.class); - public static final Method DEF_TO_CHAR_IMPLICIT = getAsmMethod(char.class , "DefTocharImplicit" , Object.class); - public static final Method DEF_TO_INT_IMPLICIT = getAsmMethod(int.class , "DefTointImplicit" , Object.class); - public static final Method DEF_TO_LONG_IMPLICIT = getAsmMethod(long.class , "DefTolongImplicit" , Object.class); - public static final Method DEF_TO_FLOAT_IMPLICIT = getAsmMethod(float.class , "DefTofloatImplicit" , Object.class); - public static final Method DEF_TO_DOUBLE_IMPLICIT = getAsmMethod(double.class , "DefTodoubleImplicit", Object.class); - public static final Method DEF_TO_BYTE_EXPLICIT = getAsmMethod(byte.class , "DefTobyteExplicit" , Object.class); - public static final Method DEF_TO_SHORT_EXPLICIT = getAsmMethod(short.class , "DefToshortExplicit" , Object.class); - public static final Method DEF_TO_CHAR_EXPLICIT = getAsmMethod(char.class , "DefTocharExplicit" , Object.class); - public static final Method DEF_TO_INT_EXPLICIT = getAsmMethod(int.class , "DefTointExplicit" , Object.class); - public static final Method DEF_TO_LONG_EXPLICIT = getAsmMethod(long.class , "DefTolongExplicit" , Object.class); - public static final Method DEF_TO_FLOAT_EXPLICIT = getAsmMethod(float.class , "DefTofloatExplicit" , Object.class); - public static final Method DEF_TO_DOUBLE_EXPLICIT = getAsmMethod(double.class , "DefTodoubleExplicit", Object.class); + + public static final Method DEF_TO_P_BOOLEAN = getAsmMethod(boolean.class, "defToboolean" , Object.class); + public static final Method DEF_TO_P_BYTE_IMPLICIT = getAsmMethod(byte.class , "defTobyteImplicit" , Object.class); + public static final Method DEF_TO_P_SHORT_IMPLICIT = getAsmMethod(short.class , "defToshortImplicit" , Object.class); + public static final Method DEF_TO_P_CHAR_IMPLICIT = getAsmMethod(char.class , "defTocharImplicit" , Object.class); + public static final Method DEF_TO_P_INT_IMPLICIT = getAsmMethod(int.class , "defTointImplicit" , Object.class); + public static final Method DEF_TO_P_LONG_IMPLICIT = getAsmMethod(long.class , "defTolongImplicit" , Object.class); + public static final Method DEF_TO_P_FLOAT_IMPLICIT = getAsmMethod(float.class , "defTofloatImplicit" , Object.class); + public static final Method DEF_TO_P_DOUBLE_IMPLICIT = getAsmMethod(double.class , "defTodoubleImplicit", Object.class); + public static final Method DEF_TO_P_BYTE_EXPLICIT = getAsmMethod(byte.class , "defTobyteExplicit" , Object.class); + public static final Method DEF_TO_P_SHORT_EXPLICIT = getAsmMethod(short.class , "defToshortExplicit" , Object.class); + public static final Method DEF_TO_P_CHAR_EXPLICIT = getAsmMethod(char.class , "defTocharExplicit" , Object.class); + public static final Method DEF_TO_P_INT_EXPLICIT = getAsmMethod(int.class , "defTointExplicit" , Object.class); + public static final Method DEF_TO_P_LONG_EXPLICIT = getAsmMethod(long.class , "defTolongExplicit" , Object.class); + public static final Method DEF_TO_P_FLOAT_EXPLICIT = getAsmMethod(float.class , "defTofloatExplicit" , Object.class); + public static final Method DEF_TO_P_DOUBLE_EXPLICIT = getAsmMethod(double.class , "defTodoubleExplicit", Object.class); + + public static final Method DEF_TO_B_SHORT_IMPLICIT = getAsmMethod(Short.class , "defToShortImplicit" , Object.class); + public static final Method DEF_TO_B_CHARACTER_IMPLICIT = getAsmMethod(Character.class, "defToCharacterImplicit", Object.class); + public static final Method DEF_TO_B_INTEGER_IMPLICIT = getAsmMethod(Integer.class , "defToIntegerImplicit" , Object.class); + public static final Method DEF_TO_B_LONG_IMPLICIT = getAsmMethod(Long.class , "defToLongImplicit" , Object.class); + public static final Method DEF_TO_B_FLOAT_IMPLICIT = getAsmMethod(Float.class , "defToFloatImplicit" , Object.class); + public static final Method DEF_TO_B_DOUBLE_IMPLICIT = getAsmMethod(Double.class , "defToDoubleImplicit" , Object.class); + public static final Method DEF_TO_B_BYTE_EXPLICIT = getAsmMethod(Byte.class , "defToByteExplicit" , Object.class); + public static final Method DEF_TO_B_SHORT_EXPLICIT = getAsmMethod(Short.class , "defToShortExplicit" , Object.class); + public static final Method DEF_TO_B_CHARACTER_EXPLICIT = getAsmMethod(Character.class, "defToCharacterExplicit", Object.class); + public static final Method DEF_TO_B_INTEGER_EXPLICIT = getAsmMethod(Integer.class , "defToIntegerExplicit" , Object.class); + public static final Method DEF_TO_B_LONG_EXPLICIT = getAsmMethod(Long.class , "defToLongExplicit" , Object.class); + 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 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/main/java/org/elasticsearch/painless/node/ENull.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java index 3a47dfc725f29..618665c767da4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java @@ -24,6 +24,7 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Opcodes; import java.util.Set; @@ -58,7 +59,7 @@ void analyze(Locals locals) { actual = expected; } else { - actual = Object.class; + actual = def.class; } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BaseClassTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BaseClassTests.java index ae96c8b3b7944..8bf085cb6bd39 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BaseClassTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BaseClassTests.java @@ -53,6 +53,8 @@ protected Map, List> scriptContexts() { contexts.put(ReturnsPrimitiveInt.CONTEXT, Whitelist.BASE_WHITELISTS); contexts.put(ReturnsPrimitiveFloat.CONTEXT, Whitelist.BASE_WHITELISTS); contexts.put(ReturnsPrimitiveDouble.CONTEXT, Whitelist.BASE_WHITELISTS); + contexts.put(ReturnsBoxedInteger.CONTEXT, Whitelist.BASE_WHITELISTS); + contexts.put(ReturnsBoxedDouble.CONTEXT, Whitelist.BASE_WHITELISTS); contexts.put(NoArgsConstant.CONTEXT, Whitelist.BASE_WHITELISTS); contexts.put(WrongArgsConstant.CONTEXT, Whitelist.BASE_WHITELISTS); contexts.put(WrongLengthOfArgConstant.CONTEXT, Whitelist.BASE_WHITELISTS); @@ -566,6 +568,131 @@ public void testReturnsPrimitiveDouble() throws Exception { .newInstance().execute(), 0); } + public abstract static class ReturnsBoxedInteger { + public interface Factory { + ReturnsBoxedInteger newInstance(); + } + + public static final ScriptContext CONTEXT = new ScriptContext<>("returnsboxedinteger", Factory.class); + + public static final String[] PARAMETERS = new String[] {}; + public abstract Integer execute(); + } + public void testReturnsBoxedInteger() throws Exception { + assertEquals(Integer.valueOf(1), + scriptEngine.compile("testReturnsBoxedInteger0", "1", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + assertEquals(Integer.valueOf(1), + scriptEngine.compile("testReturnsBoxedInteger1", "(int) 1L", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + assertEquals(Integer.valueOf(1), + scriptEngine.compile("testReturnsBoxedInteger2", "(int) 1.1d", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + assertEquals(Integer.valueOf(1), + scriptEngine.compile("testReturnsBoxedInteger3", "(int) 1.1f", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + assertEquals(Integer.valueOf(1), + scriptEngine.compile("testReturnsBoxedInteger4", "Integer.valueOf(1)", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + + assertEquals(Integer.valueOf(1), + scriptEngine.compile("testReturnsBoxedInteger5", "def i = 1; i", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + assertEquals(Integer.valueOf(1), + scriptEngine.compile( + "testReturnsBoxedInteger6", "def i = Integer.valueOf(1); i", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + + assertEquals(Integer.valueOf(2), + scriptEngine.compile("testReturnsBoxedInteger7", "1 + 1", ReturnsBoxedInteger.CONTEXT, emptyMap()).newInstance().execute()); + + Exception e = expectScriptThrows(ClassCastException.class, () -> + scriptEngine.compile("testReturnsBoxedInteger8", "1L", ReturnsBoxedInteger.CONTEXT, emptyMap()).newInstance().execute()); + assertEquals("Cannot cast from [long] to [java.lang.Integer].", e.getMessage()); + e = expectScriptThrows(ClassCastException.class, () -> + scriptEngine.compile("testReturnsBoxedInteger9", "1.1f", ReturnsBoxedInteger.CONTEXT, emptyMap()).newInstance().execute()); + assertEquals("Cannot cast from [float] to [java.lang.Integer].", e.getMessage()); + e = expectScriptThrows(ClassCastException.class, () -> + scriptEngine.compile("testReturnsBoxedInteger10", "1.1d", ReturnsBoxedInteger.CONTEXT, emptyMap()).newInstance().execute()); + assertEquals("Cannot cast from [double] to [java.lang.Integer].", e.getMessage()); + expectScriptThrows(ClassCastException.class, () -> + scriptEngine.compile("testReturnsBoxedInteger11", "def i = 1L; i", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + expectScriptThrows(ClassCastException.class, () -> + scriptEngine.compile("testReturnsBoxedInteger12", "def i = 1.1f; i", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + expectScriptThrows(ClassCastException.class, () -> + scriptEngine.compile("testReturnsBoxedInteger13", "def i = 1.1d; i", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + + assertEquals(Integer.valueOf(0), + scriptEngine.compile("testReturnsBoxedInteger14", "short i; i = 0", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + assertNull( + scriptEngine.compile("testReturnsBoxedInteger15", "return null", ReturnsBoxedInteger.CONTEXT, emptyMap()) + .newInstance().execute()); + } + + public abstract static class ReturnsBoxedDouble { + public interface Factory { + ReturnsBoxedDouble newInstance(); + } + + public static final ScriptContext CONTEXT = new ScriptContext<>("returnsboxeddouble", Factory.class); + + public static final String[] PARAMETERS = new String[] {}; + public abstract Double execute(); + } + public void testReturnsBoxedDouble() throws Exception { + assertEquals(1.0, + scriptEngine.compile("testReturnsBoxedDouble0", "1", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals(1.0, + scriptEngine.compile("testReturnsBoxedDouble1", "1L", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals(1.1, + scriptEngine.compile("testReturnsBoxedDouble2", "1.1d", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals((double) 1.1f, + scriptEngine.compile("testReturnsBoxedDouble3", "1.1f", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals(1.1, scriptEngine.compile( + "testReturnsBoxedDouble4", "Double.valueOf(1.1)", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals((double) 1.1f, scriptEngine.compile( + "testReturnsBoxedDouble5", "(def)Float.valueOf(1.1f)", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + + assertEquals(1.0, + scriptEngine.compile("testReturnsBoxedDouble6", "def d = 1; d", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals(1.0, + scriptEngine.compile("testReturnsBoxedDouble7", "def d = 1L; d", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals(1.1, + scriptEngine.compile("testReturnsBoxedDouble8", "def d = 1.1d; d", ReturnsBoxedDouble.CONTEXT, emptyMap()). + newInstance().execute(), 0); + assertEquals((double) 1.1f, + scriptEngine.compile("testReturnsBoxedDouble9", "def d = 1.1f; d", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals(1.1, scriptEngine.compile( + "testReturnsBoxedDouble10", "def d = Double.valueOf(1.1); d", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals((double) 1.1f, scriptEngine.compile( + "testReturnsBoxedDouble11", "def d = Float.valueOf(1.1f); d", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + + assertEquals(1.1 + 6.7, + scriptEngine.compile("testReturnsBoxedDouble12", "1.1 + 6.7", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertEquals(0.0, + scriptEngine.compile("testReturnsBoxedDouble13", "int i; i = 0", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute(), 0); + assertNull( + scriptEngine.compile("testReturnsBoxedDouble13", "null", ReturnsBoxedDouble.CONTEXT, emptyMap()) + .newInstance().execute()); + } + public abstract static class NoArgsConstant { public interface Factory { NoArgsConstant newInstance(); diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/CastTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/CastTests.java index c9954fd7171e0..27276c9d311dd 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/CastTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/CastTests.java @@ -286,6 +286,31 @@ public void testIllegalConversionsDef() { }); } + public void testDefToBoxedImplicit() { + assertEquals((byte)1, exec("def x = (byte)1; Byte y = x; return y;")); + assertEquals((short)1, exec("def x = (short)1; Short y = x; return y;")); + assertEquals((char)1, exec("def x = (char)1; Character y = x; return y;")); + assertEquals(1, exec("def x = 1; Integer y = x; return y;")); + assertEquals(1L, exec("def x = 1; Long y = x; return y;")); + assertEquals(1F, exec("def x = 1; Float y = x; return y;")); + assertEquals(1D, exec("def x = 1; Double y = x; return y;")); + } + + public void testDefToBoxedExplicit() { + assertEquals((byte)1, exec("def x = 1; Byte y = (Byte)x; return y;")); + assertEquals((short)1, exec("def x = 1; Short y = (Short)x; return y;")); + assertEquals((char)1, exec("def x = 1; Character y = (Character)x; return y;")); + assertEquals(1, exec("def x = 1D; Integer y = (Integer)x; return y;")); + assertEquals(1L, exec("def x = 1D; Long y = (Long)x; return y;")); + assertEquals(1F, exec("def x = 1D; Float y = (Float)x; return y;")); + assertEquals(1D, exec("def x = 1D; Double y = (Double)x; return y;")); + } + + public void testDefToBoxedException() { + expectScriptThrows(ClassCastException.class, () -> exec("def x = 1; Byte y = x; return y;")); + expectScriptThrows(ClassCastException.class, () -> exec("def x = (short)1; Character y = x; return y;")); + } + public void testUnboxMethodParameters() { assertEquals('a', exec("'a'.charAt(Integer.valueOf(0))")); }