diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java index 95f154469db..dbefd548cd2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java @@ -23,6 +23,29 @@ import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Type; +import java.util.Objects; + +import static org.elasticsearch.painless.Definition.BOOLEAN_OBJ_TYPE; +import static org.elasticsearch.painless.Definition.BOOLEAN_TYPE; +import static org.elasticsearch.painless.Definition.BYTE_OBJ_TYPE; +import static org.elasticsearch.painless.Definition.BYTE_TYPE; +import static org.elasticsearch.painless.Definition.CHAR_OBJ_TYPE; +import static org.elasticsearch.painless.Definition.CHAR_TYPE; +import static org.elasticsearch.painless.Definition.DEF_TYPE; +import static org.elasticsearch.painless.Definition.DOUBLE_OBJ_TYPE; +import static org.elasticsearch.painless.Definition.DOUBLE_TYPE; +import static org.elasticsearch.painless.Definition.FLOAT_OBJ_TYPE; +import static org.elasticsearch.painless.Definition.FLOAT_TYPE; +import static org.elasticsearch.painless.Definition.INT_OBJ_TYPE; +import static org.elasticsearch.painless.Definition.INT_TYPE; +import static org.elasticsearch.painless.Definition.LONG_OBJ_TYPE; +import static org.elasticsearch.painless.Definition.LONG_TYPE; +import static org.elasticsearch.painless.Definition.NUMBER_TYPE; +import static org.elasticsearch.painless.Definition.OBJECT_TYPE; +import static org.elasticsearch.painless.Definition.SHORT_OBJ_TYPE; +import static org.elasticsearch.painless.Definition.SHORT_TYPE; +import static org.elasticsearch.painless.Definition.STRING_TYPE; + /** * Used during the analysis phase to collect legal type casts and promotions * for type-checking and later to write necessary casts in the bytecode. @@ -30,9 +53,9 @@ import org.elasticsearch.painless.Definition.Type; public final class AnalyzerCaster { public static Cast getLegalCast(Location location, Type actual, Type expected, boolean explicit, boolean internal) { - if (actual == null || expected == null) { - throw new IllegalStateException("Neither actual [" + actual + "] nor expected [" + expected + "] can be null"); - } + Objects.requireNonNull(actual); + Objects.requireNonNull(expected); + if (actual.equals(expected)) { return null; } @@ -41,15 +64,15 @@ public final class AnalyzerCaster { case BOOL: switch (expected.sort) { case DEF: - return new Cast(actual, Definition.DEF_TYPE, explicit, false, false, true, false); + return new Cast(BOOLEAN_OBJ_TYPE, DEF_TYPE, explicit, null, null, BOOLEAN_TYPE, null); case OBJECT: - if (Definition.OBJECT_TYPE.equals(expected) && internal) - return new Cast(actual, actual, explicit, false, false, false, true); + if (OBJECT_TYPE.equals(expected) && internal) + return new Cast(BOOLEAN_OBJ_TYPE, OBJECT_TYPE, explicit, null, null, BOOLEAN_TYPE, null); break; case BOOL_OBJ: if (internal) - return new Cast(actual, actual, explicit, false, false, false, true); + return new Cast(BOOLEAN_TYPE, BOOLEAN_TYPE, explicit, null, null, null, BOOLEAN_TYPE); } break; @@ -60,53 +83,57 @@ public final class AnalyzerCaster { case LONG: case FLOAT: case DOUBLE: - return new Cast(actual, expected, explicit); + return new Cast(BYTE_TYPE, expected, explicit); case CHAR: if (explicit) - return new Cast(actual, expected, true); + return new Cast(BYTE_TYPE, CHAR_TYPE, true); break; case DEF: - return new Cast(actual, Definition.DEF_TYPE, explicit, false, false, true, false); + return new Cast(BYTE_OBJ_TYPE, DEF_TYPE, explicit, null, null, BYTE_TYPE, null); case OBJECT: - if (Definition.OBJECT_TYPE.equals(expected) && internal) - return new Cast(actual, actual, explicit, false, false, false, true); + if (OBJECT_TYPE.equals(expected) && internal) + return new Cast(BYTE_OBJ_TYPE, OBJECT_TYPE, explicit, null, null, BYTE_TYPE, null); break; case NUMBER: + if (internal) + return new Cast(BYTE_OBJ_TYPE, NUMBER_TYPE, explicit, null, null, BYTE_TYPE, null); + + break; case BYTE_OBJ: if (internal) - return new Cast(actual, actual, explicit, false, false, false, true); + return new Cast(BYTE_TYPE, BYTE_TYPE, explicit, null, null, null, BYTE_TYPE); break; case SHORT_OBJ: if (internal) - return new Cast(actual,Definition.SHORT_TYPE, explicit, false, false, false, true); + return new Cast(BYTE_TYPE, SHORT_TYPE, explicit, null, null, null, SHORT_TYPE); break; case INT_OBJ: if (internal) - return new Cast(actual, Definition.INT_TYPE, explicit, false, false, false, true); + return new Cast(BYTE_TYPE, INT_TYPE, explicit, null, null, null, INT_TYPE); break; case LONG_OBJ: if (internal) - return new Cast(actual, Definition.LONG_TYPE, explicit, false, false, false, true); + return new Cast(BYTE_TYPE, LONG_TYPE, explicit, null, null, null, LONG_TYPE); break; case FLOAT_OBJ: if (internal) - return new Cast(actual, Definition.FLOAT_TYPE, explicit, false, false, false, true); + return new Cast(BYTE_TYPE, FLOAT_TYPE, explicit, null, null, null, FLOAT_TYPE); break; case DOUBLE_OBJ: if (internal) - return new Cast(actual, Definition.DOUBLE_TYPE, explicit, false, false, false, true); + return new Cast(BYTE_TYPE, DOUBLE_TYPE, explicit, null, null, null, DOUBLE_TYPE); break; case CHAR_OBJ: if (explicit && internal) - return new Cast(actual, Definition.CHAR_TYPE, explicit, false, false, false, true); + return new Cast(BYTE_TYPE, CHAR_TYPE, true, null, null, null, CHAR_TYPE); break; } @@ -118,54 +145,58 @@ public final class AnalyzerCaster { case LONG: case FLOAT: case DOUBLE: - return new Cast(actual, expected, explicit); + return new Cast(SHORT_TYPE, expected, explicit); case BYTE: case CHAR: if (explicit) - return new Cast(actual, expected, true); + return new Cast(SHORT_TYPE, expected, true); break; case DEF: - return new Cast(actual, Definition.DEF_TYPE, explicit, false, false, true, false); + return new Cast(SHORT_OBJ_TYPE, DEF_TYPE, explicit, null, null, SHORT_TYPE, null); case OBJECT: - if (Definition.OBJECT_TYPE.equals(expected) && internal) - return new Cast(actual, actual, explicit, false, false, false, true); + if (OBJECT_TYPE.equals(expected) && internal) + return new Cast(SHORT_OBJ_TYPE, OBJECT_TYPE, explicit, null, null, SHORT_TYPE, null); break; case NUMBER: + if (internal) + return new Cast(SHORT_OBJ_TYPE, NUMBER_TYPE, explicit, null, null, SHORT_TYPE, null); + + break; case SHORT_OBJ: if (internal) - return new Cast(actual, actual, explicit, false, false, false, true); + return new Cast(SHORT_TYPE, SHORT_TYPE, explicit, null, null, null, SHORT_TYPE); break; case INT_OBJ: if (internal) - return new Cast(actual, Definition.INT_TYPE, explicit, false, false, false, true); + return new Cast(SHORT_TYPE, INT_TYPE, explicit, null, null, null, INT_TYPE); break; case LONG_OBJ: if (internal) - return new Cast(actual, Definition.LONG_TYPE, explicit, false, false, false, true); + return new Cast(SHORT_TYPE, LONG_TYPE, explicit, null, null, null, LONG_TYPE); break; case FLOAT_OBJ: if (internal) - return new Cast(actual, Definition.FLOAT_TYPE, explicit, false, false, false, true); + return new Cast(SHORT_TYPE, FLOAT_TYPE, explicit, null, null, null, FLOAT_TYPE); break; case DOUBLE_OBJ: if (internal) - return new Cast(actual, Definition.DOUBLE_TYPE, explicit, false, false, false, true); + return new Cast(SHORT_TYPE, DOUBLE_TYPE, explicit, null, null, null, DOUBLE_TYPE); break; case BYTE_OBJ: if (explicit && internal) - return new Cast(actual, Definition.BYTE_TYPE, true, false, false, false, true); + return new Cast(SHORT_TYPE, BYTE_TYPE, true, null, null, null, BYTE_TYPE); break; case CHAR_OBJ: if (explicit && internal) - return new Cast(actual, Definition.CHAR_TYPE, true, false, false, false, true); + return new Cast(SHORT_TYPE, CHAR_TYPE, true, null, null, null, CHAR_TYPE); break; } @@ -177,7 +208,7 @@ public final class AnalyzerCaster { case LONG: case FLOAT: case DOUBLE: - return new Cast(actual, expected, explicit); + return new Cast(CHAR_TYPE, expected, explicit); case BYTE: case SHORT: if (explicit) @@ -185,48 +216,52 @@ public final class AnalyzerCaster { break; case DEF: - return new Cast(actual, Definition.DEF_TYPE, explicit, false, false, true, false); + return new Cast(CHAR_OBJ_TYPE, DEF_TYPE, explicit, null, null, CHAR_TYPE, null); case OBJECT: - if (Definition.OBJECT_TYPE.equals(expected) && internal) - return new Cast(actual, actual, explicit, false, false, false, true); + if (OBJECT_TYPE.equals(expected) && internal) + return new Cast(CHAR_OBJ_TYPE, OBJECT_TYPE, explicit, null, null, CHAR_TYPE, null); break; case NUMBER: + if (internal) + return new Cast(CHAR_OBJ_TYPE, NUMBER_TYPE, explicit, null, null, CHAR_TYPE, null); + + break; case CHAR_OBJ: if (internal) - return new Cast(actual, actual, explicit, false, false, false, true); + return new Cast(CHAR_TYPE, CHAR_TYPE, explicit, null, null, null, CHAR_TYPE); break; case STRING: - return new Cast(actual, Definition.STRING_TYPE, explicit, false, false, false, false); + return new Cast(CHAR_TYPE, STRING_TYPE, explicit); case INT_OBJ: if (internal) - return new Cast(actual, Definition.INT_TYPE, explicit, false, false, false, true); + return new Cast(CHAR_TYPE, INT_TYPE, explicit, null, null, null, INT_TYPE); break; case LONG_OBJ: if (internal) - return new Cast(actual, Definition.LONG_TYPE, explicit, false, false, false, true); + return new Cast(CHAR_TYPE, LONG_TYPE, explicit, null, null, null, LONG_TYPE); break; case FLOAT_OBJ: if (internal) - return new Cast(actual, Definition.FLOAT_TYPE, explicit, false, false, false, true); + return new Cast(CHAR_TYPE, FLOAT_TYPE, explicit, null, null, null, FLOAT_TYPE); break; case DOUBLE_OBJ: if (internal) - return new Cast(actual, Definition.DOUBLE_TYPE, explicit, false, false, false, true); + return new Cast(CHAR_TYPE, DOUBLE_TYPE, explicit, null, null, null, DOUBLE_TYPE); break; case BYTE_OBJ: if (explicit && internal) - return new Cast(actual, Definition.BYTE_TYPE, true, false, false, false, true); + return new Cast(CHAR_TYPE, BYTE_TYPE, true, null, null, null, BYTE_TYPE); break; case SHORT_OBJ: if (explicit && internal) - return new Cast(actual, Definition.SHORT_TYPE, true, false, false, false, true); + return new Cast(CHAR_TYPE, SHORT_TYPE, true, null, null, null, SHORT_TYPE); break; } @@ -237,55 +272,59 @@ public final class AnalyzerCaster { case LONG: case FLOAT: case DOUBLE: - return new Cast(actual, expected, explicit); + return new Cast(INT_TYPE, expected, explicit); case BYTE: case SHORT: case CHAR: if (explicit) - return new Cast(actual, expected, true); + return new Cast(INT_TYPE, expected, true); break; case DEF: - return new Cast(actual, Definition.DEF_TYPE, explicit, false, false, true, false); + return new Cast(INT_OBJ_TYPE, DEF_TYPE, explicit, null, null, INT_TYPE, null); case OBJECT: - if (Definition.OBJECT_TYPE.equals(expected) && internal) - return new Cast(actual, actual, explicit, false, false, false, true); + if (OBJECT_TYPE.equals(expected) && internal) + return new Cast(INT_OBJ_TYPE, OBJECT_TYPE, explicit, null, null, INT_TYPE, null); break; case NUMBER: + if (internal) + return new Cast(INT_OBJ_TYPE, NUMBER_TYPE, explicit, null, null, INT_TYPE, null); + + break; case INT_OBJ: if (internal) - return new Cast(actual, actual, explicit, false, false, false, true); + return new Cast(INT_TYPE, INT_TYPE, explicit, null, null, null, INT_TYPE); break; case LONG_OBJ: if (internal) - return new Cast(actual, Definition.LONG_TYPE, explicit, false, false, false, true); + return new Cast(INT_TYPE, LONG_TYPE, explicit, null, null, null, LONG_TYPE); break; case FLOAT_OBJ: if (internal) - return new Cast(actual, Definition.FLOAT_TYPE, explicit, false, false, false, true); + return new Cast(INT_TYPE, FLOAT_TYPE, explicit, null, null, null, FLOAT_TYPE); break; case DOUBLE_OBJ: if (internal) - return new Cast(actual, Definition.DOUBLE_TYPE, explicit, false, false, false, true); + return new Cast(INT_TYPE, DOUBLE_TYPE, explicit, null, null, null, DOUBLE_TYPE); break; case BYTE_OBJ: if (explicit && internal) - return new Cast(actual, Definition.BYTE_TYPE, true, false, false, false, true); + return new Cast(INT_TYPE, BYTE_TYPE, true, null, null, null, BYTE_TYPE); break; case SHORT_OBJ: if (explicit && internal) - return new Cast(actual, Definition.SHORT_TYPE, true, false, false, false, true); + return new Cast(INT_TYPE, SHORT_TYPE, true, null, null, null, SHORT_TYPE); break; case CHAR_OBJ: if (explicit && internal) - return new Cast(actual, Definition.CHAR_TYPE, true, false, false, false, true); + return new Cast(INT_TYPE, CHAR_TYPE, true, null, null, null, CHAR_TYPE); break; } @@ -295,7 +334,7 @@ public final class AnalyzerCaster { switch (expected.sort) { case FLOAT: case DOUBLE: - return new Cast(actual, expected, explicit); + return new Cast(LONG_TYPE, expected, explicit); case BYTE: case SHORT: case CHAR: @@ -305,46 +344,50 @@ public final class AnalyzerCaster { break; case DEF: - return new Cast(actual, Definition.DEF_TYPE, explicit, false, false, true, false); + return new Cast(LONG_TYPE, DEF_TYPE, explicit, null, null, LONG_TYPE, null); case OBJECT: - if (Definition.OBJECT_TYPE.equals(expected) && internal) - return new Cast(actual, actual, explicit, false, false, false, true); + if (OBJECT_TYPE.equals(expected) && internal) + return new Cast(LONG_TYPE, actual, explicit, null, null, LONG_TYPE, null); break; case NUMBER: + if (internal) + return new Cast(LONG_OBJ_TYPE, NUMBER_TYPE, explicit, null, null, LONG_TYPE, null); + + break; case LONG_OBJ: if (internal) - return new Cast(actual, actual, explicit, false, false, false, true); + return new Cast(LONG_TYPE, LONG_TYPE, explicit, null, null, null, LONG_TYPE); break; case FLOAT_OBJ: if (internal) - return new Cast(actual, Definition.FLOAT_TYPE, explicit, false, false, false, true); + return new Cast(LONG_TYPE, FLOAT_TYPE, explicit, null, null, null, FLOAT_TYPE); break; case DOUBLE_OBJ: if (internal) - return new Cast(actual, Definition.DOUBLE_TYPE, explicit, false, false, false, true); + return new Cast(LONG_TYPE, DOUBLE_TYPE, explicit, null, null, null, DOUBLE_TYPE); break; case BYTE_OBJ: if (explicit && internal) - return new Cast(actual, Definition.BYTE_TYPE, true, false, false, false, true); + return new Cast(LONG_TYPE, BYTE_TYPE, true, null, null, null, BYTE_TYPE); break; case SHORT_OBJ: if (explicit && internal) - return new Cast(actual, Definition.SHORT_TYPE, true, false, false, false, true); + return new Cast(LONG_TYPE, SHORT_TYPE, true, null, null, null, SHORT_TYPE); break; case CHAR_OBJ: if (explicit && internal) - return new Cast(actual, Definition.CHAR_TYPE, true, false, false, false, true); + return new Cast(LONG_TYPE, CHAR_TYPE, true, null, null, null, CHAR_TYPE); break; case INT_OBJ: if (explicit && internal) - return new Cast(actual, Definition.INT_TYPE, true, false, false, false, true); + return new Cast(LONG_TYPE, INT_TYPE, true, null, null, null, INT_TYPE); break; } @@ -364,46 +407,50 @@ public final class AnalyzerCaster { break; case DEF: - return new Cast(actual, Definition.DEF_TYPE, explicit, false, false, true, false); + return new Cast(FLOAT_OBJ_TYPE, DEF_TYPE, explicit, null, null, FLOAT_TYPE, null); case OBJECT: - if (Definition.OBJECT_TYPE.equals(expected) && internal) - return new Cast(actual, actual, explicit, false, false, false, true); + if (OBJECT_TYPE.equals(expected) && internal) + return new Cast(FLOAT_OBJ_TYPE, OBJECT_TYPE, explicit, null, null, FLOAT_TYPE, null); break; case NUMBER: + if (internal) + return new Cast(FLOAT_OBJ_TYPE, NUMBER_TYPE, explicit, null, null, FLOAT_TYPE, null); + + break; case FLOAT_OBJ: if (internal) - return new Cast(actual, actual, explicit, false, false, false, true); + return new Cast(FLOAT_TYPE, FLOAT_TYPE, explicit, null, null, null, FLOAT_TYPE); break; case DOUBLE_OBJ: if (internal) - return new Cast(actual, Definition.DOUBLE_TYPE, explicit, false, false, false, true); + return new Cast(FLOAT_TYPE, DOUBLE_TYPE, explicit, null, null, null, DOUBLE_TYPE); break; case BYTE_OBJ: if (explicit && internal) - return new Cast(actual, Definition.BYTE_TYPE, true, false, false, false, true); + return new Cast(FLOAT_TYPE, BYTE_TYPE, true, null, null, null, BYTE_TYPE); break; case SHORT_OBJ: if (explicit && internal) - return new Cast(actual, Definition.SHORT_TYPE, true, false, false, false, true); + return new Cast(FLOAT_TYPE, SHORT_TYPE, true, null, null, null, SHORT_TYPE); break; case CHAR_OBJ: if (explicit && internal) - return new Cast(actual, Definition.CHAR_TYPE, true, false, false, false, true); + return new Cast(FLOAT_TYPE, CHAR_TYPE, true, null, null, null, CHAR_TYPE); break; case INT_OBJ: if (explicit && internal) - return new Cast(actual, Definition.INT_TYPE, true, false, false, false, true); + return new Cast(FLOAT_TYPE, INT_TYPE, true, null, null, null, INT_TYPE); break; case LONG_OBJ: if (explicit && internal) - return new Cast(actual, Definition.LONG_TYPE, true, false, false, false, true); + return new Cast(FLOAT_TYPE, LONG_TYPE, true, null, null, null, LONG_TYPE); break; } @@ -417,91 +464,95 @@ public final class AnalyzerCaster { case INT: case FLOAT: if (explicit) - return new Cast(actual, expected, true); + return new Cast(DOUBLE_TYPE, expected, true); break; case DEF: - return new Cast(actual, Definition.DEF_TYPE, explicit, false, false, true, false); + return new Cast(DOUBLE_OBJ_TYPE, DEF_TYPE, explicit, null, null, DOUBLE_TYPE, null); case OBJECT: - if (Definition.OBJECT_TYPE.equals(expected) && internal) - return new Cast(actual, actual, explicit, false, false, false, true); + if (OBJECT_TYPE.equals(expected) && internal) + return new Cast(DOUBLE_OBJ_TYPE, OBJECT_TYPE, explicit, null, null, DOUBLE_TYPE, null); break; case NUMBER: + if (internal) + return new Cast(DOUBLE_OBJ_TYPE, NUMBER_TYPE, explicit, null, null, DOUBLE_TYPE, null); + + break; case DOUBLE_OBJ: if (internal) - return new Cast(actual, actual, explicit, false, false, false, true); + return new Cast(DOUBLE_TYPE, DOUBLE_TYPE, explicit, null, null, null, DOUBLE_TYPE); break; case BYTE_OBJ: if (explicit && internal) - return new Cast(actual, Definition.BYTE_TYPE, true, false, false, false, true); + return new Cast(DOUBLE_TYPE, BYTE_TYPE, true, null, null, null, BYTE_TYPE); break; case SHORT_OBJ: if (explicit && internal) - return new Cast(actual, Definition.SHORT_TYPE, true, false, false, false, true); + return new Cast(DOUBLE_TYPE, SHORT_TYPE, true, null, null, null, SHORT_TYPE); break; case CHAR_OBJ: if (explicit && internal) - return new Cast(actual, Definition.CHAR_TYPE, true, false, false, false, true); + return new Cast(DOUBLE_TYPE, CHAR_TYPE, true, null, null, null, CHAR_TYPE); break; case INT_OBJ: if (explicit && internal) - return new Cast(actual, Definition.INT_TYPE, true, false, false, false, true); + return new Cast(DOUBLE_TYPE, INT_TYPE, true, null, null, null, INT_TYPE); break; case LONG_OBJ: if (explicit && internal) - return new Cast(actual, Definition.LONG_TYPE, true, false, false, false, true); + return new Cast(DOUBLE_TYPE, LONG_TYPE, true, null, null, null, LONG_TYPE); break; case FLOAT_OBJ: if (explicit && internal) - return new Cast(actual, Definition.FLOAT_TYPE, true, false, false, false, true); + return new Cast(DOUBLE_TYPE, FLOAT_TYPE, true, null, null, null, FLOAT_TYPE); break; } break; case OBJECT: - if (Definition.OBJECT_TYPE.equals(actual)) + if (OBJECT_TYPE.equals(actual)) switch (expected.sort) { case BYTE: if (internal && explicit) - return new Cast(actual, Definition.BYTE_OBJ_TYPE, true, false, true, false, false); + return new Cast(OBJECT_TYPE, BYTE_OBJ_TYPE, true, null, BYTE_TYPE, null, null); break; case SHORT: if (internal && explicit) - return new Cast(actual, Definition.SHORT_OBJ_TYPE, true, false, true, false, false); + return new Cast(OBJECT_TYPE, SHORT_OBJ_TYPE, true, null, SHORT_TYPE, null, null); break; case CHAR: if (internal && explicit) - return new Cast(actual, Definition.CHAR_OBJ_TYPE, true, false, true, false, false); + return new Cast(OBJECT_TYPE, CHAR_OBJ_TYPE, true, null, CHAR_TYPE, null, null); break; case INT: if (internal && explicit) - return new Cast(actual, Definition.INT_OBJ_TYPE, true, false, true, false, false); + return new Cast(OBJECT_TYPE, INT_OBJ_TYPE, true, null, INT_TYPE, null, null); break; case LONG: if (internal && explicit) - return new Cast(actual, Definition.LONG_OBJ_TYPE, true, false, true, false, false); + return new Cast(OBJECT_TYPE, LONG_OBJ_TYPE, true, null, LONG_TYPE, null, null); break; case FLOAT: if (internal && explicit) - return new Cast(actual, Definition.FLOAT_OBJ_TYPE, true, false, true, false, false); + return new Cast(OBJECT_TYPE, FLOAT_OBJ_TYPE, true, null, FLOAT_TYPE, null, null); break; case DOUBLE: if (internal && explicit) - return new Cast(actual, Definition.DOUBLE_OBJ_TYPE, true, false, true, false, false); + return new Cast(OBJECT_TYPE, DOUBLE_OBJ_TYPE, true, null, DOUBLE_TYPE, null, null); break; } @@ -510,37 +561,37 @@ public final class AnalyzerCaster { switch (expected.sort) { case BYTE: if (internal && explicit) - return new Cast(actual, Definition.BYTE_OBJ_TYPE, true, false, true, false, false); + return new Cast(NUMBER_TYPE, BYTE_OBJ_TYPE, true, null, BYTE_TYPE, null, null); break; case SHORT: if (internal && explicit) - return new Cast(actual, Definition.SHORT_OBJ_TYPE, true, false, true, false, false); + return new Cast(NUMBER_TYPE, SHORT_OBJ_TYPE, true, null, SHORT_TYPE, null, null); break; case CHAR: if (internal && explicit) - return new Cast(actual, Definition.CHAR_OBJ_TYPE, true, false, true, false, false); + return new Cast(NUMBER_TYPE, CHAR_OBJ_TYPE, true, null, CHAR_TYPE, null, null); break; case INT: if (internal && explicit) - return new Cast(actual, Definition.INT_OBJ_TYPE, true, false, true, false, false); + return new Cast(NUMBER_TYPE, INT_OBJ_TYPE, true, null, INT_TYPE, null, null); break; case LONG: if (internal && explicit) - return new Cast(actual, Definition.LONG_OBJ_TYPE, true, false, true, false, false); + return new Cast(NUMBER_TYPE, LONG_OBJ_TYPE, true, null, LONG_TYPE, null, null); break; case FLOAT: if (internal && explicit) - return new Cast(actual, Definition.FLOAT_OBJ_TYPE, true, false, true, false, false); + return new Cast(NUMBER_TYPE, FLOAT_OBJ_TYPE, true, null, FLOAT_TYPE, null, null); break; case DOUBLE: if (internal && explicit) - return new Cast(actual, Definition.DOUBLE_OBJ_TYPE, true, false, true, false, false); + return new Cast(NUMBER_TYPE, DOUBLE_OBJ_TYPE, true, null, DOUBLE_TYPE, null, null); break; } @@ -550,7 +601,7 @@ public final class AnalyzerCaster { switch (expected.sort) { case BOOL: if (internal) - return new Cast(actual, expected, explicit, true, false, false, false); + return new Cast(BOOLEAN_TYPE, BOOLEAN_TYPE, explicit, BOOLEAN_TYPE, null, null, null); break; } @@ -565,12 +616,12 @@ public final class AnalyzerCaster { case FLOAT: case DOUBLE: if (internal) - return new Cast(actual, expected, explicit, true, false, false, false); + return new Cast(BYTE_TYPE, expected, explicit, BYTE_TYPE, null, null, null); break; case CHAR: if (internal && explicit) - return new Cast(actual, expected, true, true, false, false, false); + return new Cast(BYTE_TYPE, expected, true, BYTE_TYPE, null, null, null); break; } @@ -584,13 +635,13 @@ public final class AnalyzerCaster { case FLOAT: case DOUBLE: if (internal) - return new Cast(actual, expected, explicit, true, false, false, false); + return new Cast(SHORT_TYPE, expected, explicit, SHORT_TYPE, null, null, null); break; case BYTE: case CHAR: if (internal && explicit) - return new Cast(actual, expected, true, true, false, false, false); + return new Cast(SHORT_TYPE, expected, true, SHORT_TYPE, null, null, null); break; } @@ -604,13 +655,13 @@ public final class AnalyzerCaster { case FLOAT: case DOUBLE: if (internal) - return new Cast(actual, expected, explicit, true, false, false, false); + return new Cast(CHAR_TYPE, expected, explicit, CHAR_TYPE, null, null, null); break; case BYTE: case SHORT: if (internal && explicit) - return new Cast(actual, expected, true, true, false, false, false); + return new Cast(CHAR_TYPE, expected, true, CHAR_TYPE, null, null, null); break; } @@ -623,14 +674,14 @@ public final class AnalyzerCaster { case FLOAT: case DOUBLE: if (internal) - return new Cast(actual, expected, explicit, true, false, false, false); + return new Cast(INT_TYPE, expected, explicit, INT_TYPE, null, null, null); break; case BYTE: case SHORT: case CHAR: if (internal && explicit) - return new Cast(actual, expected, true, true, false, false, false); + return new Cast(INT_TYPE, expected, true, INT_TYPE, null, null, null); break; } @@ -642,7 +693,7 @@ public final class AnalyzerCaster { case FLOAT: case DOUBLE: if (internal) - return new Cast(actual, expected, explicit, true, false, false, false); + return new Cast(LONG_TYPE, expected, explicit, LONG_TYPE, null, null, null); break; case BYTE: @@ -650,7 +701,7 @@ public final class AnalyzerCaster { case CHAR: case INT: if (internal && explicit) - return new Cast(actual, expected, true, true, false, false, false); + return new Cast(LONG_TYPE, expected, true, LONG_TYPE, null, null, null); break; } @@ -661,7 +712,7 @@ public final class AnalyzerCaster { case FLOAT: case DOUBLE: if (internal) - return new Cast(actual, expected, explicit, true, false, false, false); + return new Cast(FLOAT_TYPE, expected, explicit, FLOAT_TYPE, null, null, null); break; case BYTE: @@ -670,7 +721,7 @@ public final class AnalyzerCaster { case INT: case LONG: if (internal && explicit) - return new Cast(actual, expected, true, true, false, false, false); + return new Cast(FLOAT_TYPE, expected, true, FLOAT_TYPE, null, null, null); break; } @@ -678,10 +729,9 @@ public final class AnalyzerCaster { break; case DOUBLE_OBJ: switch (expected.sort) { - case FLOAT: case DOUBLE: if (internal) - return new Cast(actual, expected, explicit, true, false, false, false); + return new Cast(DOUBLE_TYPE, expected, explicit, DOUBLE_TYPE, null, null, null); break; case BYTE: @@ -689,8 +739,9 @@ public final class AnalyzerCaster { case CHAR: case INT: case LONG: + case FLOAT: if (internal && explicit) - return new Cast(actual, expected, true, true, false, false, false); + return new Cast(DOUBLE_TYPE, expected, true, DOUBLE_TYPE, null, null, null); break; } @@ -699,14 +750,21 @@ public final class AnalyzerCaster { case DEF: switch (expected.sort) { case BOOL: + return new Cast(DEF_TYPE, BOOLEAN_OBJ_TYPE, explicit, null, BOOLEAN_TYPE, null, null); case BYTE: + return new Cast(DEF_TYPE, BYTE_OBJ_TYPE, explicit, null, BYTE_TYPE, null, null); case SHORT: + return new Cast(DEF_TYPE, SHORT_OBJ_TYPE, explicit, null, SHORT_TYPE, null, null); case CHAR: + return new Cast(DEF_TYPE, CHAR_OBJ_TYPE, explicit, null, CHAR_TYPE, null, null); case INT: + return new Cast(DEF_TYPE, INT_OBJ_TYPE, explicit, null, INT_TYPE, null, null); case LONG: + return new Cast(DEF_TYPE, LONG_OBJ_TYPE, explicit, null, LONG_TYPE, null, null); case FLOAT: + return new Cast(DEF_TYPE, FLOAT_OBJ_TYPE, explicit, null, FLOAT_TYPE, null, null); case DOUBLE: - return new Cast(actual, expected, explicit, true, false, false, false); + return new Cast(DEF_TYPE, DOUBLE_OBJ_TYPE, explicit, null, DOUBLE_TYPE, null, null); } break; @@ -714,7 +772,7 @@ public final class AnalyzerCaster { switch (expected.sort) { case CHAR: if (explicit) - return new Cast(actual, expected, true, false, false, false, false); + return new Cast(STRING_TYPE, CHAR_TYPE, true); break; } @@ -773,15 +831,15 @@ public final class AnalyzerCaster { final Sort sort = from.sort; if (sort == Sort.DEF) { - return Definition.DEF_TYPE; + return DEF_TYPE; } else if ((sort == Sort.DOUBLE) && decimal) { - return Definition.DOUBLE_TYPE; + return DOUBLE_TYPE; } else if ((sort == Sort.FLOAT) && decimal) { - return Definition.FLOAT_TYPE; + return FLOAT_TYPE; } else if (sort == Sort.LONG) { - return Definition.LONG_TYPE; + return LONG_TYPE; } else if (sort == Sort.INT || sort == Sort.CHAR || sort == Sort.SHORT || sort == Sort.BYTE) { - return Definition.INT_TYPE; + return INT_TYPE; } return null; @@ -792,24 +850,24 @@ public final class AnalyzerCaster { final Sort sort1 = from1.sort; if (sort0 == Sort.DEF || sort1 == Sort.DEF) { - return Definition.DEF_TYPE; + return DEF_TYPE; } if (decimal) { if (sort0 == Sort.DOUBLE || sort1 == Sort.DOUBLE) { - return Definition.DOUBLE_TYPE; + return DOUBLE_TYPE; } else if (sort0 == Sort.FLOAT || sort1 == Sort.FLOAT) { - return Definition.FLOAT_TYPE; + return FLOAT_TYPE; } } if (sort0 == Sort.LONG || sort1 == Sort.LONG) { - return Definition.LONG_TYPE; + return LONG_TYPE; } else if (sort0 == Sort.INT || sort1 == Sort.INT || sort0 == Sort.CHAR || sort1 == Sort.CHAR || sort0 == Sort.SHORT || sort1 == Sort.SHORT || sort0 == Sort.BYTE || sort1 == Sort.BYTE) { - return Definition.INT_TYPE; + return INT_TYPE; } return null; @@ -820,7 +878,7 @@ public final class AnalyzerCaster { final Sort sort1 = from1.sort; if (sort0 == Sort.STRING || sort1 == Sort.STRING) { - return Definition.STRING_TYPE; + return STRING_TYPE; } return promoteNumeric(from0, from1, true); @@ -831,11 +889,11 @@ public final class AnalyzerCaster { final Sort sort1 = from1.sort; if (sort0 == Sort.DEF || sort1 == Sort.DEF) { - return Definition.DEF_TYPE; + return DEF_TYPE; } if (sort0.bool || sort1.bool) { - return Definition.BOOLEAN_TYPE; + return BOOLEAN_TYPE; } return promoteNumeric(from0, from1, false); @@ -846,12 +904,12 @@ public final class AnalyzerCaster { final Sort sort1 = from1.sort; if (sort0 == Sort.DEF || sort1 == Sort.DEF) { - return Definition.DEF_TYPE; + return DEF_TYPE; } if (sort0.primitive && sort1.primitive) { if (sort0.bool && sort1.bool) { - return Definition.BOOLEAN_TYPE; + return BOOLEAN_TYPE; } if (sort0.numeric && sort1.numeric) { @@ -859,7 +917,7 @@ public final class AnalyzerCaster { } } - return Definition.OBJECT_TYPE; + return OBJECT_TYPE; } public static Type promoteConditional(final Type from0, final Type from1, final Object const0, final Object const1) { @@ -871,46 +929,46 @@ public final class AnalyzerCaster { final Sort sort1 = from1.sort; if (sort0 == Sort.DEF || sort1 == Sort.DEF) { - return Definition.DEF_TYPE; + return DEF_TYPE; } if (sort0.primitive && sort1.primitive) { if (sort0.bool && sort1.bool) { - return Definition.BOOLEAN_TYPE; + return BOOLEAN_TYPE; } if (sort0 == Sort.DOUBLE || sort1 == Sort.DOUBLE) { - return Definition.DOUBLE_TYPE; + return DOUBLE_TYPE; } else if (sort0 == Sort.FLOAT || sort1 == Sort.FLOAT) { - return Definition.FLOAT_TYPE; + return FLOAT_TYPE; } else if (sort0 == Sort.LONG || sort1 == Sort.LONG) { - return Definition.LONG_TYPE; + return LONG_TYPE; } else { if (sort0 == Sort.BYTE) { if (sort1 == Sort.BYTE) { - return Definition.BYTE_TYPE; + return BYTE_TYPE; } else if (sort1 == Sort.SHORT) { if (const1 != null) { final short constant = (short)const1; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return Definition.BYTE_TYPE; + return BYTE_TYPE; } } - return Definition.SHORT_TYPE; + return SHORT_TYPE; } else if (sort1 == Sort.CHAR) { - return Definition.INT_TYPE; + return INT_TYPE; } else if (sort1 == Sort.INT) { if (const1 != null) { final int constant = (int)const1; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return Definition.BYTE_TYPE; + return BYTE_TYPE; } } - return Definition.INT_TYPE; + return INT_TYPE; } } else if (sort0 == Sort.SHORT) { if (sort1 == Sort.BYTE) { @@ -918,43 +976,43 @@ public final class AnalyzerCaster { final short constant = (short)const0; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return Definition.BYTE_TYPE; + return BYTE_TYPE; } } - return Definition.SHORT_TYPE; + return SHORT_TYPE; } else if (sort1 == Sort.SHORT) { - return Definition.SHORT_TYPE; + return SHORT_TYPE; } else if (sort1 == Sort.CHAR) { - return Definition.INT_TYPE; + return INT_TYPE; } else if (sort1 == Sort.INT) { if (const1 != null) { final int constant = (int)const1; if (constant <= Short.MAX_VALUE && constant >= Short.MIN_VALUE) { - return Definition.SHORT_TYPE; + return SHORT_TYPE; } } - return Definition.INT_TYPE; + return INT_TYPE; } } else if (sort0 == Sort.CHAR) { if (sort1 == Sort.BYTE) { - return Definition.INT_TYPE; + return INT_TYPE; } else if (sort1 == Sort.SHORT) { - return Definition.INT_TYPE; + return INT_TYPE; } else if (sort1 == Sort.CHAR) { - return Definition.CHAR_TYPE; + return CHAR_TYPE; } else if (sort1 == Sort.INT) { if (const1 != null) { final int constant = (int)const1; if (constant <= Character.MAX_VALUE && constant >= Character.MIN_VALUE) { - return Definition.BYTE_TYPE; + return BYTE_TYPE; } } - return Definition.INT_TYPE; + return INT_TYPE; } } else if (sort0 == Sort.INT) { if (sort1 == Sort.BYTE) { @@ -962,33 +1020,33 @@ public final class AnalyzerCaster { final int constant = (int)const0; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return Definition.BYTE_TYPE; + return BYTE_TYPE; } } - return Definition.INT_TYPE; + return INT_TYPE; } else if (sort1 == Sort.SHORT) { if (const0 != null) { final int constant = (int)const0; if (constant <= Short.MAX_VALUE && constant >= Short.MIN_VALUE) { - return Definition.BYTE_TYPE; + return BYTE_TYPE; } } - return Definition.INT_TYPE; + return INT_TYPE; } else if (sort1 == Sort.CHAR) { if (const0 != null) { final int constant = (int)const0; if (constant <= Character.MAX_VALUE && constant >= Character.MIN_VALUE) { - return Definition.BYTE_TYPE; + return BYTE_TYPE; } } - return Definition.INT_TYPE; + return INT_TYPE; } else if (sort1 == Sort.INT) { - return Definition.INT_TYPE; + return INT_TYPE; } } } @@ -998,7 +1056,7 @@ public final class AnalyzerCaster { // to calculate the highest upper bound for the two types and return that. // However, for now we just return objectType that may require an extra cast. - return Definition.OBJECT_TYPE; + return OBJECT_TYPE; } private AnalyzerCaster() {} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java index 9f03540c2d8..16f0339677e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java @@ -87,6 +87,7 @@ public final class Definition { public static final Type CHAR_OBJ_TYPE = getType("Character"); public static final Type OBJECT_TYPE = getType("Object"); public static final Type DEF_TYPE = getType("def"); + public static final Type NUMBER_TYPE = getType("Number"); public static final Type STRING_TYPE = getType("String"); public static final Type EXCEPTION_TYPE = getType("Exception"); public static final Type PATTERN_TYPE = getType("Pattern"); @@ -434,23 +435,23 @@ public final class Definition { public final Type from; public final Type to; public final boolean explicit; - public final boolean unboxFrom; - public final boolean unboxTo; - public final boolean boxFrom; - public final boolean boxTo; + public final Type unboxFrom; + public final Type unboxTo; + public final Type boxFrom; + public final Type boxTo; public Cast(final Type from, final Type to, final boolean explicit) { this.from = from; this.to = to; this.explicit = explicit; - this.unboxFrom = false; - this.unboxTo = false; - this.boxFrom = false; - this.boxTo = false; + this.unboxFrom = null; + this.unboxTo = null; + this.boxFrom = null; + this.boxTo = null; } public Cast(final Type from, final Type to, final boolean explicit, - final boolean unboxFrom, final boolean unboxTo, final boolean boxFrom, final boolean boxTo) { + final Type unboxFrom, final Type unboxTo, final Type boxFrom, final Type boxTo) { this.from = from; this.to = to; this.explicit = explicit; 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 7e56bf49156..ac902ee134e 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 @@ -131,51 +131,48 @@ public final class MethodWriter extends GeneratorAdapter { public void writeCast(final Cast cast) { if (cast != null) { - final Type from = cast.from; - final Type to = cast.to; - - if (from.sort == Sort.CHAR && to.sort == Sort.STRING) { + if (cast.from.sort == Sort.CHAR && cast.to.sort == Sort.STRING) { invokeStatic(UTILITY_TYPE, CHAR_TO_STRING); - } else if (from.sort == Sort.STRING && to.sort == Sort.CHAR) { + } else if (cast.from.sort == Sort.STRING && cast.to.sort == Sort.CHAR) { invokeStatic(UTILITY_TYPE, STRING_TO_CHAR); - } else if (cast.unboxFrom) { - if (from.sort == Sort.DEF) { + } else if (cast.unboxFrom != null) { + unbox(cast.unboxFrom.type); + writeCast(cast.from, cast.to); + } else if (cast.unboxTo != null) { + if (cast.from.sort == Sort.DEF) { if (cast.explicit) { - if (to.sort == Sort.BOOL) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); - else if (to.sort == Sort.BYTE) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_EXPLICIT); - else if (to.sort == Sort.SHORT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_EXPLICIT); - else if (to.sort == Sort.CHAR) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_EXPLICIT); - else if (to.sort == Sort.INT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_EXPLICIT); - else if (to.sort == Sort.LONG) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_EXPLICIT); - else if (to.sort == Sort.FLOAT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_EXPLICIT); - else if (to.sort == Sort.DOUBLE) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_EXPLICIT); + if (cast.to.sort == Sort.BOOL_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); + else if (cast.to.sort == Sort.BYTE_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_EXPLICIT); + else if (cast.to.sort == Sort.SHORT_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_EXPLICIT); + else if (cast.to.sort == Sort.CHAR_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_EXPLICIT); + else if (cast.to.sort == Sort.INT_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_EXPLICIT); + else if (cast.to.sort == Sort.LONG_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_EXPLICIT); + else if (cast.to.sort == Sort.FLOAT_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_EXPLICIT); + else if (cast.to.sort == Sort.DOUBLE_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_EXPLICIT); else throw new IllegalStateException("Illegal tree structure."); } else { - if (to.sort == Sort.BOOL) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); - else if (to.sort == Sort.BYTE) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_IMPLICIT); - else if (to.sort == Sort.SHORT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_IMPLICIT); - else if (to.sort == Sort.CHAR) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_IMPLICIT); - else if (to.sort == Sort.INT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_IMPLICIT); - else if (to.sort == Sort.LONG) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_IMPLICIT); - else if (to.sort == Sort.FLOAT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_IMPLICIT); - else if (to.sort == Sort.DOUBLE) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_IMPLICIT); + if (cast.to.sort == Sort.BOOL_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); + else if (cast.to.sort == Sort.BYTE_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_IMPLICIT); + else if (cast.to.sort == Sort.SHORT_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_IMPLICIT); + else if (cast.to.sort == Sort.CHAR_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_IMPLICIT); + else if (cast.to.sort == Sort.INT_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_IMPLICIT); + else if (cast.to.sort == Sort.LONG_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_IMPLICIT); + else if (cast.to.sort == Sort.FLOAT_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_IMPLICIT); + else if (cast.to.sort == Sort.DOUBLE_OBJ) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_IMPLICIT); else throw new IllegalStateException("Illegal tree structure."); } } else { - unbox(from.type); - writeCast(from, to); + writeCast(cast.from, cast.to); + unbox(cast.unboxTo.type); } - } else if (cast.unboxTo) { - writeCast(from, to); - unbox(to.type); - } else if (cast.boxFrom) { - box(from.type); - writeCast(from, to); - } else if (cast.boxTo) { - writeCast(from, to); - box(to.type); + } else if (cast.boxFrom != null) { + box(cast.boxFrom.type); + writeCast(cast.from, cast.to); + } else if (cast.boxTo != null) { + writeCast(cast.from, cast.to); + box(cast.boxTo.type); } else { - writeCast(from, to); + writeCast(cast.from, cast.to); } } } @@ -269,19 +266,19 @@ public final class MethodWriter extends GeneratorAdapter { } /** Writes a dynamic binary instruction: returnType, lhs, and rhs can be different */ - public void writeDynamicBinaryInstruction(Location location, Type returnType, Type lhs, Type rhs, + public void writeDynamicBinaryInstruction(Location location, Type returnType, Type lhs, Type rhs, Operation operation, int flags) { org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType(returnType.type, lhs.type, rhs.type); - + switch (operation) { case MUL: - invokeDefCall("mul", methodType, DefBootstrap.BINARY_OPERATOR, flags); + invokeDefCall("mul", methodType, DefBootstrap.BINARY_OPERATOR, flags); break; case DIV: - invokeDefCall("div", methodType, DefBootstrap.BINARY_OPERATOR, flags); + invokeDefCall("div", methodType, DefBootstrap.BINARY_OPERATOR, flags); break; case REM: - invokeDefCall("rem", methodType, DefBootstrap.BINARY_OPERATOR, flags); + invokeDefCall("rem", methodType, DefBootstrap.BINARY_OPERATOR, flags); break; case ADD: // if either side is primitive, then the + operator should always throw NPE on null, @@ -294,31 +291,31 @@ public final class MethodWriter extends GeneratorAdapter { invokeDefCall("add", methodType, DefBootstrap.BINARY_OPERATOR, flags); break; case SUB: - invokeDefCall("sub", methodType, DefBootstrap.BINARY_OPERATOR, flags); + invokeDefCall("sub", methodType, DefBootstrap.BINARY_OPERATOR, flags); break; case LSH: invokeDefCall("lsh", methodType, DefBootstrap.SHIFT_OPERATOR, flags); break; case USH: - invokeDefCall("ush", methodType, DefBootstrap.SHIFT_OPERATOR, flags); + invokeDefCall("ush", methodType, DefBootstrap.SHIFT_OPERATOR, flags); break; case RSH: - invokeDefCall("rsh", methodType, DefBootstrap.SHIFT_OPERATOR, flags); + invokeDefCall("rsh", methodType, DefBootstrap.SHIFT_OPERATOR, flags); break; - case BWAND: + case BWAND: invokeDefCall("and", methodType, DefBootstrap.BINARY_OPERATOR, flags); break; - case XOR: + case XOR: invokeDefCall("xor", methodType, DefBootstrap.BINARY_OPERATOR, flags); break; - case BWOR: + case BWOR: invokeDefCall("or", methodType, DefBootstrap.BINARY_OPERATOR, flags); break; default: throw location.createError(new IllegalStateException("Illegal tree structure.")); } } - + /** Writes a static binary instruction */ public void writeBinaryInstruction(Location location, Type type, Operation operation) { final Sort sort = type.sort; 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 0551965f067..0ca72f993e5 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 @@ -21,7 +21,7 @@ package org.elasticsearch.painless; /** Tests for explicit casts */ public class CastTests extends ScriptTestCase { - + /** * Unary operator with explicit cast */ @@ -34,7 +34,7 @@ public class CastTests extends ScriptTestCase { assertEquals(5L, exec("long x = 5L; return (long) (+x);")); assertEquals(5D, exec("long x = 5L; return (double) (+x);")); } - + /** * Binary operators with explicit cast */ @@ -73,7 +73,7 @@ public class CastTests extends ScriptTestCase { assertEquals(6L, exec("long x = 5L; return (long) (++x);")); assertEquals(6D, exec("long x = 5L; return (double) (++x);")); } - + /** * Binary compound postifx with explicit cast */ @@ -86,7 +86,7 @@ public class CastTests extends ScriptTestCase { assertEquals(5L, exec("long x = 5L; return (long) (x++);")); assertEquals(5D, exec("long x = 5L; return (double) (x++);")); } - + /** * Shift operators with explicit cast */ @@ -99,7 +99,7 @@ public class CastTests extends ScriptTestCase { assertEquals(10L, exec("long x = 5L; return (long) (x << 1);")); assertEquals(10D, exec("long x = 5L; return (double) (x << 1);")); } - + /** * Shift compound assignment with explicit cast */ @@ -112,7 +112,7 @@ public class CastTests extends ScriptTestCase { assertEquals(10L, exec("long x = 5L; return (long) (x <<= 1);")); assertEquals(10D, exec("long x = 5L; return (double) (x <<= 1);")); } - + /** * Test that without a cast, we fail when conversions would narrow. */ @@ -136,7 +136,7 @@ public class CastTests extends ScriptTestCase { exec("long x = 5L; boolean y = (x + x); return y"); }); } - + /** * Test that even with a cast, some things aren't allowed. */ @@ -161,7 +161,7 @@ public class CastTests extends ScriptTestCase { public void testMethodCallDef() { assertEquals(5, exec("def x = 5; return (int)x.longValue();")); } - + /** * Currently these do not adopt the argument value, we issue a separate cast! */ @@ -170,7 +170,7 @@ public class CastTests extends ScriptTestCase { assertEquals(6, exec("def x = 5; def y = 1L; return x + (int)y")); assertEquals('b', exec("def x = 'abcdeg'; def y = 1L; x.charAt((int)y)")); } - + /** * Unary operators adopt the return value */ @@ -183,7 +183,7 @@ public class CastTests extends ScriptTestCase { assertEquals(5L, exec("def x = 5L; return (long) (+x);")); assertEquals(5D, exec("def x = 5L; return (double) (+x);")); } - + /** * Binary operators adopt the return value */ @@ -196,7 +196,7 @@ public class CastTests extends ScriptTestCase { assertEquals(6L, exec("def x = 5L; return (long) (x + 1);")); assertEquals(6D, exec("def x = 5L; return (double) (x + 1);")); } - + /** * Binary operators don't yet adopt the return value with compound assignment */ @@ -209,7 +209,7 @@ public class CastTests extends ScriptTestCase { assertEquals(6L, exec("def x = 5L; return (long) (x += 1);")); assertEquals(6D, exec("def x = 5L; return (double) (x += 1);")); } - + /** * Binary operators don't yet adopt the return value with compound assignment */ @@ -222,7 +222,7 @@ public class CastTests extends ScriptTestCase { assertEquals(6L, exec("def x = 5L; return (long) (++x);")); assertEquals(6D, exec("def x = 5L; return (double) (++x);")); } - + /** * Binary operators don't yet adopt the return value with compound assignment */ @@ -235,7 +235,7 @@ public class CastTests extends ScriptTestCase { assertEquals(5L, exec("def x = 5L; return (long) (x++);")); assertEquals(5D, exec("def x = 5L; return (double) (x++);")); } - + /** * Shift operators adopt the return value */ @@ -248,7 +248,7 @@ public class CastTests extends ScriptTestCase { assertEquals(10L, exec("def x = 5L; return (long) (x << 1);")); assertEquals(10D, exec("def x = 5L; return (double) (x << 1);")); } - + /** * Shift operators don't yet adopt the return value with compound assignment */ @@ -261,7 +261,7 @@ public class CastTests extends ScriptTestCase { assertEquals(10L, exec("def x = 5L; return (long) (x <<= 1);")); assertEquals(10D, exec("def x = 5L; return (double) (x <<= 1);")); } - + /** * Test that without a cast, we fail when conversions would narrow. */ @@ -285,7 +285,21 @@ public class CastTests extends ScriptTestCase { exec("def x = 5L; boolean y = (x + x); return y"); }); } - + + public void testUnboxMethodParameters() { + assertEquals('a', exec("'a'.charAt(Integer.valueOf(0))")); + } + + public void testIllegalCastInMethodArgument() { + assertEquals('a', exec("'a'.charAt(0)")); + Exception e = expectScriptThrows(ClassCastException.class, () -> exec("'a'.charAt(0L)")); + assertEquals("Cannot cast from [long] to [int].", e.getMessage()); + e = expectScriptThrows(ClassCastException.class, () -> exec("'a'.charAt(0.0f)")); + assertEquals("Cannot cast from [float] to [int].", e.getMessage()); + e = expectScriptThrows(ClassCastException.class, () -> exec("'a'.charAt(0.0d)")); + assertEquals("Cannot cast from [double] to [int].", e.getMessage()); + } + /** * Test that even with a cast, some things aren't allowed. * (stuff that methodhandles explicitCastArguments would otherwise allow) diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionTests.java index 68bac55db78..8f9505d09c9 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionTests.java @@ -54,6 +54,18 @@ public class FunctionTests extends ScriptTestCase { assertThat(expected.getMessage(), containsString("Cannot generate an empty function")); } + public void testReturnsAreUnboxedIfNeeded() { + assertEquals((byte) 5, exec("byte get() {Byte.valueOf(5)} get()")); + assertEquals((short) 5, exec("short get() {Byte.valueOf(5)} get()")); + assertEquals(5, exec("int get() {Byte.valueOf(5)} get()")); + assertEquals((short) 5, exec("short get() {Short.valueOf(5)} get()")); + assertEquals(5, exec("int get() {Integer.valueOf(5)} get()")); + assertEquals(5.0f, exec("float get() {Float.valueOf(5)} get()")); + assertEquals(5.0d, exec("double get() {Float.valueOf(5)} get()")); + assertEquals(5.0d, exec("double get() {Double.valueOf(5)} get()")); + assertEquals(true, exec("boolean get() {Boolean.TRUE} get()")); + } + public void testDuplicates() { Exception expected = expectScriptThrows(IllegalArgumentException.class, () -> { exec("void test(int x) {x = 2;} void test(def y) {y = 3;} test()"); @@ -61,6 +73,15 @@ public class FunctionTests extends ScriptTestCase { assertThat(expected.getMessage(), containsString("Duplicate functions")); } + public void testBadCastFromMethod() { + Exception e = expectScriptThrows(ClassCastException.class, () -> exec("int get() {5L} get()")); + assertEquals("Cannot cast from [long] to [int].", e.getMessage()); + e = expectScriptThrows(ClassCastException.class, () -> exec("int get() {5.1f} get()")); + assertEquals("Cannot cast from [float] to [int].", e.getMessage()); + e = expectScriptThrows(ClassCastException.class, () -> exec("int get() {5.1d} get()")); + assertEquals("Cannot cast from [double] to [int].", e.getMessage()); + } + public void testInfiniteLoop() { Error expected = expectScriptThrows(PainlessError.class, () -> { exec("void test() {boolean x = true; while (x) {}} test()");