Skip to content

Commit

Permalink
Remove constant folding in Painless user tree (#52783)
Browse files Browse the repository at this point in the history
This change removes constant folding from the Painless user tree. This 
accomplishes two goals. The first is to remove all optimizations from the 
user tree which will at a later time become optimization phases for the ir 
tree. The second is to make the user tree immutable, and this is a step 
toward that since we will no longer remove/modify/replace nodes in the 
user tree during the process of constant folding.

One important note is that the conditional promotion code has changed, 
since the promoteConditional method considered constants (similarly to 
the JVM spec) that are now removed, but this code path was unreachable 
to begin with so the constants were never actually used to determine the 
appropriate promotion.
jdconrad authored Feb 26, 2020
1 parent fb64c18 commit f6d89ae
Showing 20 changed files with 85 additions and 555 deletions.
Original file line number Diff line number Diff line change
@@ -520,7 +520,7 @@ public static Class<?> promoteEquality(Class<?> from0, Class<?> from1) {
return Object.class;
}

public static Class<?> promoteConditional(Class<?> from0, Class<?> from1, Object const0, Object const1) {
public static Class<?> promoteConditional(Class<?> from0, Class<?> from1) {
if (from0 == from1) {
return from0;
}
@@ -529,123 +529,29 @@ public static Class<?> promoteConditional(Class<?> from0, Class<?> from1, Object
return def.class;
}

if (from0.isPrimitive() && from1.isPrimitive()) {
if (from0 == boolean.class && from1 == boolean.class) {
return boolean.class;
}

if (from0.isPrimitive() && from0 != boolean.class && from1.isPrimitive() && from1 != boolean.class) {
if (from0 == double.class || from1 == double.class) {
return double.class;
} else if (from0 == float.class || from1 == float.class) {
return float.class;
} else if (from0 == long.class || from1 == long.class) {
return long.class;
} else if (from0 == int.class || from1 == int.class) {
return int.class;
} else if (from0 == char.class) {
if (from1 == short.class || from1 == byte.class) {
return int.class;
} else {
return null;
}
} else if (from1 == char.class) {
if (from0 == short.class || from0 == byte.class) {
return int.class;
} else {
if (from0 == byte.class) {
if (from1 == byte.class) {
return byte.class;
} else if (from1 == short.class) {
if (const1 != null) {
final short constant = (short)const1;

if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) {
return byte.class;
}
}

return short.class;
} else if (from1 == char.class) {
return int.class;
} else if (from1 == int.class) {
if (const1 != null) {
final int constant = (int)const1;

if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) {
return byte.class;
}
}

return int.class;
}
} else if (from0 == short.class) {
if (from1 == byte.class) {
if (const0 != null) {
final short constant = (short)const0;

if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) {
return byte.class;
}
}

return short.class;
} else if (from1 == short.class) {
return short.class;
} else if (from1 == char.class) {
return int.class;
} else if (from1 == int.class) {
if (const1 != null) {
final int constant = (int)const1;

if (constant <= Short.MAX_VALUE && constant >= Short.MIN_VALUE) {
return short.class;
}
}

return int.class;
}
} else if (from0 == char.class) {
if (from1 == byte.class) {
return int.class;
} else if (from1 == short.class) {
return int.class;
} else if (from1 == char.class) {
return char.class;
} else if (from1 == int.class) {
if (const1 != null) {
final int constant = (int)const1;

if (constant <= Character.MAX_VALUE && constant >= Character.MIN_VALUE) {
return byte.class;
}
}

return int.class;
}
} else if (from0 == int.class) {
if (from1 == byte.class) {
if (const0 != null) {
final int constant = (int)const0;

if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) {
return byte.class;
}
}

return int.class;
} else if (from1 == short.class) {
if (const0 != null) {
final int constant = (int)const0;

if (constant <= Short.MAX_VALUE && constant >= Short.MIN_VALUE) {
return byte.class;
}
}

return int.class;
} else if (from1 == char.class) {
if (const0 != null) {
final int constant = (int)const0;

if (constant <= Character.MAX_VALUE && constant >= Character.MIN_VALUE) {
return byte.class;
}
}

return int.class;
} else if (from1 == int.class) {
return int.class;
}
return null;
}
} else {
return null;
}
}

Original file line number Diff line number Diff line change
@@ -25,7 +25,6 @@
import org.elasticsearch.painless.ir.ClassNode;
import org.elasticsearch.painless.ir.ExpressionNode;
import org.elasticsearch.painless.lookup.PainlessCast;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.ScriptRoot;

import java.util.Objects;
@@ -84,14 +83,6 @@ public abstract class AExpression extends ANode {
*/
boolean internal = false;

/**
* Set to the value of the constant this expression node represents if
* and only if the node represents a constant. If this is not null
* this node will be replaced by an {@link EConstant} during casting
* if it's not already one.
*/
Object constant = null;

/**
* Set to true by {@link ENull} to represent a null value.
*/
@@ -134,97 +125,14 @@ AExpression cast(ScriptRoot scriptRoot, Scope scope) {
PainlessCast cast = AnalyzerCaster.getLegalCast(location, actual, expected, explicit, internal);

if (cast == null) {
if (constant == null || this instanceof EConstant) {
// For the case where a cast is not required and a constant is not set
// or the node is already an EConstant no changes are required to the tree.

return this;
} else {
// For the case where a cast is not required but a
// constant is set, an EConstant replaces this node
// with the constant copied from this node. Note that
// for constants output data does not need to be copied
// from this node because the output data for the EConstant
// will already be the same.

EConstant econstant = new EConstant(location, constant);
econstant.analyze(scriptRoot, scope);

if (!expected.equals(econstant.actual)) {
throw createError(new IllegalStateException("Illegal tree structure."));
}

return econstant;
}
return this;
} else {
if (constant == null) {
// For the case where a cast is required and a constant is not set.
// Modify the tree to add an ECast between this node and its parent.
// The output data from this node is copied to the ECast for
// further reads done by the parent.

ECast ecast = new ECast(location, this, cast);
ecast.statement = statement;
ecast.actual = expected;
ecast.isNull = isNull;

return ecast;
} else {
if (PainlessLookupUtility.isConstantType(expected)) {
// For the case where a cast is required, a constant is set,
// and the constant can be immediately cast to the expected type.
// An EConstant replaces this node with the constant cast appropriately
// from the constant value defined by this node. Note that
// for constants output data does not need to be copied
// from this node because the output data for the EConstant
// will already be the same.

constant = AnalyzerCaster.constCast(location, constant, cast);

EConstant econstant = new EConstant(location, constant);
econstant.analyze(scriptRoot, scope);

if (!expected.equals(econstant.actual)) {
throw createError(new IllegalStateException("Illegal tree structure."));
}

return econstant;
} else if (this instanceof EConstant) {
// For the case where a cast is required, a constant is set,
// the constant cannot be immediately cast to the expected type,
// and this node is already an EConstant. Modify the tree to add
// an ECast between this node and its parent. Note that
// for constants output data does not need to be copied
// from this node because the output data for the EConstant
// will already be the same.

ECast ecast = new ECast(location, this, cast);
ecast.actual = expected;

return ecast;
} else {
// For the case where a cast is required, a constant is set,
// the constant cannot be immediately cast to the expected type,
// and this node is not an EConstant. Replace this node with
// an Econstant node copying the constant from this node.
// Modify the tree to add an ECast between the EConstant node
// and its parent. Note that for constants output data does not
// need to be copied from this node because the output data for
// the EConstant will already be the same.

EConstant econstant = new EConstant(location, constant);
econstant.analyze(scriptRoot, scope);

if (!actual.equals(econstant.actual)) {
throw createError(new IllegalStateException("Illegal tree structure."));
}

ECast ecast = new ECast(location, econstant, cast);
ecast.actual = expected;

return ecast;
}
}
ECast ecast = new ECast(location, this, cast);
ecast.statement = statement;
ecast.actual = expected;
ecast.isNull = isNull;

return ecast;
}
}
}
Original file line number Diff line number Diff line change
@@ -116,20 +116,6 @@ private void analyzeMul(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promote == int.class) {
constant = (int)left.constant * (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant * (long)right.constant;
} else if (promote == float.class) {
constant = (float)left.constant * (float)right.constant;
} else if (promote == double.class) {
constant = (double)left.constant * (double)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
}

private void analyzeDiv(ScriptRoot scriptRoot, Scope variables) {
@@ -160,24 +146,6 @@ private void analyzeDiv(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
try {
if (promote == int.class) {
constant = (int)left.constant / (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant / (long)right.constant;
} else if (promote == float.class) {
constant = (float)left.constant / (float)right.constant;
} else if (promote == double.class) {
constant = (double)left.constant / (double)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
} catch (ArithmeticException exception) {
throw createError(exception);
}
}
}

private void analyzeRem(ScriptRoot scriptRoot, Scope variables) {
@@ -208,24 +176,6 @@ private void analyzeRem(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
try {
if (promote == int.class) {
constant = (int)left.constant % (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant % (long)right.constant;
} else if (promote == float.class) {
constant = (float)left.constant % (float)right.constant;
} else if (promote == double.class) {
constant = (double)left.constant % (double)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
} catch (ArithmeticException exception) {
throw createError(exception);
}
}
}

private void analyzeAdd(ScriptRoot scriptRoot, Scope variables) {
@@ -268,23 +218,6 @@ private void analyzeAdd(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promote == int.class) {
constant = (int)left.constant + (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant + (long)right.constant;
} else if (promote == float.class) {
constant = (float)left.constant + (float)right.constant;
} else if (promote == double.class) {
constant = (double)left.constant + (double)right.constant;
} else if (promote == String.class) {
constant = left.constant.toString() + right.constant.toString();
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

}

private void analyzeSub(ScriptRoot scriptRoot, Scope variables) {
@@ -315,20 +248,6 @@ private void analyzeSub(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promote == int.class) {
constant = (int)left.constant - (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant - (long)right.constant;
} else if (promote == float.class) {
constant = (float)left.constant - (float)right.constant;
} else if (promote == double.class) {
constant = (double)left.constant - (double)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
}

private void analyzeRegexOp(ScriptRoot scriptRoot, Scope variables) {
@@ -381,16 +300,6 @@ private void analyzeLSH(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promote == int.class) {
constant = (int)left.constant << (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant << (int)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
}

private void analyzeRSH(ScriptRoot scriptRoot, Scope variables) {
@@ -429,16 +338,6 @@ private void analyzeRSH(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promote == int.class) {
constant = (int)left.constant >> (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant >> (int)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
}

private void analyzeUSH(ScriptRoot scriptRoot, Scope variables) {
@@ -477,16 +376,6 @@ private void analyzeUSH(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promote == int.class) {
constant = (int)left.constant >>> (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant >>> (int)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
}

private void analyzeBWAnd(ScriptRoot scriptRoot, Scope variables) {
@@ -517,16 +406,6 @@ private void analyzeBWAnd(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promote == int.class) {
constant = (int)left.constant & (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant & (long)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
}

private void analyzeXor(ScriptRoot scriptRoot, Scope variables) {
@@ -556,18 +435,6 @@ private void analyzeXor(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promote == boolean.class) {
constant = (boolean)left.constant ^ (boolean)right.constant;
} else if (promote == int.class) {
constant = (int)left.constant ^ (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant ^ (long)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
}

private void analyzeBWOr(ScriptRoot scriptRoot, Scope variables) {
@@ -597,16 +464,6 @@ private void analyzeBWOr(ScriptRoot scriptRoot, Scope variables) {

left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promote == int.class) {
constant = (int)left.constant | (int)right.constant;
} else if (promote == long.class) {
constant = (long)left.constant | (long)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
}

@Override
Original file line number Diff line number Diff line change
@@ -55,16 +55,6 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
right.analyze(scriptRoot, scope);
right = right.cast(scriptRoot, scope);

if (left.constant != null && right.constant != null) {
if (operation == Operation.AND) {
constant = (boolean)left.constant && (boolean)right.constant;
} else if (operation == Operation.OR) {
constant = (boolean)left.constant || (boolean)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

actual = boolean.class;
}

Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Scope;
import org.elasticsearch.painless.ir.ClassNode;
import org.elasticsearch.painless.ir.ConstantNode;
import org.elasticsearch.painless.ir.ExpressionNode;
import org.elasticsearch.painless.symbol.ScriptRoot;

@@ -30,6 +31,8 @@
*/
public final class EBoolean extends AExpression {

protected boolean constant;

public EBoolean(Location location, boolean constant) {
super(location);

@@ -47,7 +50,12 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {

@Override
ExpressionNode write(ClassNode classNode) {
throw createError(new IllegalStateException("Illegal tree structure."));
ConstantNode constantNode = new ConstantNode();
constantNode.setLocation(location);
constantNode.setExpressionType(actual);
constantNode.setConstant(constant);

return constantNode;
}

@Override
Original file line number Diff line number Diff line change
@@ -100,26 +100,6 @@ private void analyzeEq(ScriptRoot scriptRoot, Scope variables) {
throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
}

if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
if (promotedType == boolean.class) {
constant = (boolean)left.constant == (boolean)right.constant;
} else if (promotedType == int.class) {
constant = (int)left.constant == (int)right.constant;
} else if (promotedType == long.class) {
constant = (long)left.constant == (long)right.constant;
} else if (promotedType == float.class) {
constant = (float)left.constant == (float)right.constant;
} else if (promotedType == double.class) {
constant = (double)left.constant == (double)right.constant;
} else if (!left.isNull) {
constant = left.constant.equals(right.constant);
} else if (!right.isNull) {
constant = right.constant.equals(null);
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

actual = boolean.class;
}

@@ -145,22 +125,6 @@ private void analyzeEqR(ScriptRoot scriptRoot, Scope variables) {
throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
}

if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
if (promotedType == boolean.class) {
constant = (boolean)left.constant == (boolean)right.constant;
} else if (promotedType == int.class) {
constant = (int)left.constant == (int)right.constant;
} else if (promotedType == long.class) {
constant = (long)left.constant == (long)right.constant;
} else if (promotedType == float.class) {
constant = (float)left.constant == (float)right.constant;
} else if (promotedType == double.class) {
constant = (double)left.constant == (double)right.constant;
} else {
constant = left.constant == right.constant;
}
}

actual = boolean.class;
}

@@ -191,26 +155,6 @@ private void analyzeNE(ScriptRoot scriptRoot, Scope variables) {
throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
}

if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
if (promotedType == boolean.class) {
constant = (boolean)left.constant != (boolean)right.constant;
} else if (promotedType == int.class) {
constant = (int)left.constant != (int)right.constant;
} else if (promotedType == long.class) {
constant = (long)left.constant != (long)right.constant;
} else if (promotedType == float.class) {
constant = (float)left.constant != (float)right.constant;
} else if (promotedType == double.class) {
constant = (double)left.constant != (double)right.constant;
} else if (!left.isNull) {
constant = !left.constant.equals(right.constant);
} else if (!right.isNull) {
constant = !right.constant.equals(null);
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

actual = boolean.class;
}

@@ -236,22 +180,6 @@ private void analyzeNER(ScriptRoot scriptRoot, Scope variables) {
throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
}

if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
if (promotedType == boolean.class) {
constant = (boolean)left.constant != (boolean)right.constant;
} else if (promotedType == int.class) {
constant = (int)left.constant != (int)right.constant;
} else if (promotedType == long.class) {
constant = (long)left.constant != (long)right.constant;
} else if (promotedType == float.class) {
constant = (float)left.constant != (float)right.constant;
} else if (promotedType == double.class) {
constant = (double)left.constant != (double)right.constant;
} else {
constant = left.constant != right.constant;
}
}

actual = boolean.class;
}

@@ -278,20 +206,6 @@ private void analyzeGTE(ScriptRoot scriptRoot, Scope variables) {
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promotedType == int.class) {
constant = (int)left.constant >= (int)right.constant;
} else if (promotedType == long.class) {
constant = (long)left.constant >= (long)right.constant;
} else if (promotedType == float.class) {
constant = (float)left.constant >= (float)right.constant;
} else if (promotedType == double.class) {
constant = (double)left.constant >= (double)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

actual = boolean.class;
}

@@ -318,20 +232,6 @@ private void analyzeGT(ScriptRoot scriptRoot, Scope variables) {
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promotedType == int.class) {
constant = (int)left.constant > (int)right.constant;
} else if (promotedType == long.class) {
constant = (long)left.constant > (long)right.constant;
} else if (promotedType == float.class) {
constant = (float)left.constant > (float)right.constant;
} else if (promotedType == double.class) {
constant = (double)left.constant > (double)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

actual = boolean.class;
}

@@ -358,20 +258,6 @@ private void analyzeLTE(ScriptRoot scriptRoot, Scope variables) {
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promotedType == int.class) {
constant = (int)left.constant <= (int)right.constant;
} else if (promotedType == long.class) {
constant = (long)left.constant <= (long)right.constant;
} else if (promotedType == float.class) {
constant = (float)left.constant <= (float)right.constant;
} else if (promotedType == double.class) {
constant = (double)left.constant <= (double)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

actual = boolean.class;
}

@@ -398,20 +284,6 @@ private void analyzeLT(ScriptRoot scriptRoot, Scope variables) {
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);

if (left.constant != null && right.constant != null) {
if (promotedType == int.class) {
constant = (int)left.constant < (int)right.constant;
} else if (promotedType == long.class) {
constant = (long)left.constant < (long)right.constant;
} else if (promotedType == float.class) {
constant = (float)left.constant < (float)right.constant;
} else if (promotedType == double.class) {
constant = (double)left.constant < (double)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

actual = boolean.class;
}

Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
import org.elasticsearch.painless.Scope;
import org.elasticsearch.painless.ir.ClassNode;
import org.elasticsearch.painless.ir.ConditionalNode;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.ScriptRoot;

import java.util.Objects;
@@ -51,10 +52,6 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
condition.analyze(scriptRoot, scope);
condition = condition.cast(scriptRoot, scope);

if (condition.constant != null) {
throw createError(new IllegalArgumentException("Extraneous conditional statement."));
}

left.expected = expected;
left.explicit = explicit;
left.internal = internal;
@@ -67,7 +64,13 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
right.analyze(scriptRoot, scope);

if (expected == null) {
Class<?> promote = AnalyzerCaster.promoteConditional(left.actual, right.actual, left.constant, right.constant);
Class<?> promote = AnalyzerCaster.promoteConditional(left.actual, right.actual);

if (promote == null) {
throw createError(new ClassCastException("cannot apply a conditional operator [?:] to the types " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]"));
}

left.expected = promote;
right.expected = promote;
Original file line number Diff line number Diff line change
@@ -31,6 +31,8 @@
*/
final class EConstant extends AExpression {

protected Object constant;

EConstant(Location location, Object constant) {
super(location);

@@ -65,7 +67,6 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
@Override
ConstantNode write(ClassNode classNode) {
ConstantNode constantNode = new ConstantNode();

constantNode.setLocation(location);
constantNode.setExpressionType(actual);
constantNode.setConstant(constant);
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Scope;
import org.elasticsearch.painless.ir.ClassNode;
import org.elasticsearch.painless.ir.ConstantNode;
import org.elasticsearch.painless.ir.ExpressionNode;
import org.elasticsearch.painless.symbol.ScriptRoot;

@@ -34,6 +35,8 @@ public final class EDecimal extends AExpression {

private final String value;

protected Object constant;

public EDecimal(Location location, String value) {
super(location);

@@ -69,7 +72,12 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {

@Override
ExpressionNode write(ClassNode classNode) {
throw createError(new IllegalStateException("Illegal tree structure."));
ConstantNode constantNode = new ConstantNode();
constantNode.setLocation(location);
constantNode.setExpressionType(actual);
constantNode.setConstant(constant);

return constantNode;
}

@Override
Original file line number Diff line number Diff line change
@@ -61,7 +61,11 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
if (lhs.isNull) {
throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is null."));
}
if (lhs.constant != null) {
if (lhs instanceof EBoolean
|| lhs instanceof ENumeric
|| lhs instanceof EDecimal
|| lhs instanceof EString
|| lhs instanceof EConstant) {
throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a constant."));
}
if (lhs.actual.isPrimitive()) {
@@ -72,7 +76,7 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
}

if (expected == null) {
Class<?> promote = AnalyzerCaster.promoteConditional(lhs.actual, rhs.actual, lhs.constant, rhs.constant);
Class<?> promote = AnalyzerCaster.promoteConditional(lhs.actual, rhs.actual);

lhs.expected = promote;
rhs.expected = promote;
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Scope;
import org.elasticsearch.painless.ir.ClassNode;
import org.elasticsearch.painless.ir.ConstantNode;
import org.elasticsearch.painless.ir.ExpressionNode;
import org.elasticsearch.painless.symbol.ScriptRoot;

@@ -35,6 +36,8 @@ public final class ENumeric extends AExpression {
private final String value;
private int radix;

protected Object constant;

public ENumeric(Location location, String value, int radix) {
super(location);

@@ -111,7 +114,12 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {

@Override
ExpressionNode write(ClassNode classNode) {
throw createError(new IllegalStateException("Illegal tree structure."));
ConstantNode constantNode = new ConstantNode();
constantNode.setLocation(location);
constantNode.setExpressionType(actual);
constantNode.setConstant(constant);

return constantNode;
}

@Override
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Scope;
import org.elasticsearch.painless.ir.ClassNode;
import org.elasticsearch.painless.ir.ConstantNode;
import org.elasticsearch.painless.ir.ExpressionNode;
import org.elasticsearch.painless.symbol.ScriptRoot;

@@ -32,6 +33,8 @@
*/
public final class EString extends AExpression {

protected String constant;

public EString(Location location, String string) {
super(location);

@@ -49,7 +52,12 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {

@Override
ExpressionNode write(ClassNode classNode) {
throw new IllegalStateException("Illegal tree structure.");
ConstantNode constantNode = new ConstantNode();
constantNode.setLocation(location);
constantNode.setExpressionType(actual);
constantNode.setConstant(constant);

return constantNode;
}

@Override
Original file line number Diff line number Diff line change
@@ -72,10 +72,6 @@ void analyzeNot(ScriptRoot scriptRoot, Scope variables) {
child.analyze(scriptRoot, variables);
child = child.cast(scriptRoot, variables);

if (child.constant != null) {
constant = !(boolean)child.constant;
}

actual = boolean.class;
}

@@ -92,16 +88,6 @@ void analyzeBWNot(ScriptRoot scriptRoot, Scope variables) {
child.expected = promote;
child = child.cast(scriptRoot, variables);

if (child.constant != null) {
if (promote == int.class) {
constant = ~(int)child.constant;
} else if (promote == long.class) {
constant = ~(long)child.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

if (promote == def.class && expected != null) {
actual = expected;
} else {
@@ -122,20 +108,6 @@ void analyzerAdd(ScriptRoot scriptRoot, Scope variables) {
child.expected = promote;
child = child.cast(scriptRoot, variables);

if (child.constant != null) {
if (promote == int.class) {
constant = +(int)child.constant;
} else if (promote == long.class) {
constant = +(long)child.constant;
} else if (promote == float.class) {
constant = +(float)child.constant;
} else if (promote == double.class) {
constant = +(double)child.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

if (promote == def.class && expected != null) {
actual = expected;
} else {
@@ -156,20 +128,6 @@ void analyzerSub(ScriptRoot scriptRoot, Scope variables) {
child.expected = promote;
child = child.cast(scriptRoot, variables);

if (child.constant != null) {
if (promote == int.class) {
constant = -(int)child.constant;
} else if (promote == long.class) {
constant = -(long)child.constant;
} else if (promote == float.class) {
constant = -(float)child.constant;
} else if (promote == double.class) {
constant = -(double)child.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}

if (promote == def.class && expected != null) {
actual = expected;
} else {
Original file line number Diff line number Diff line change
@@ -64,8 +64,8 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
condition.analyze(scriptRoot, scope);
condition = condition.cast(scriptRoot, scope);

if (condition.constant != null) {
continuous = (boolean)condition.constant;
if (condition instanceof EBoolean) {
continuous = ((EBoolean)condition).constant;

if (!continuous) {
throw createError(new IllegalArgumentException("Extraneous do while loop."));
Original file line number Diff line number Diff line change
@@ -79,8 +79,8 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
condition.analyze(scriptRoot, scope);
condition = condition.cast(scriptRoot, scope);

if (condition.constant != null) {
continuous = (boolean)condition.constant;
if (condition instanceof EBoolean) {
continuous = ((EBoolean)condition).constant;

if (!continuous) {
throw createError(new IllegalArgumentException("Extraneous for loop."));
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
condition.analyze(scriptRoot, scope);
condition = condition.cast(scriptRoot, scope);

if (condition.constant != null) {
if (condition instanceof EBoolean) {
throw createError(new IllegalArgumentException("Extraneous if statement."));
}

Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
condition.analyze(scriptRoot, scope);
condition = condition.cast(scriptRoot, scope);

if (condition.constant != null) {
if (condition instanceof EBoolean) {
throw createError(new IllegalArgumentException("Extraneous if statement."));
}

Original file line number Diff line number Diff line change
@@ -52,8 +52,8 @@ void analyze(ScriptRoot scriptRoot, Scope scope) {
condition.analyze(scriptRoot, scope);
condition = condition.cast(scriptRoot, scope);

if (condition.constant != null) {
continuous = (boolean)condition.constant;
if (condition instanceof EBoolean) {
continuous = ((EBoolean)condition).constant;

if (!continuous) {
throw createError(new IllegalArgumentException("Extraneous while loop."));
Original file line number Diff line number Diff line change
@@ -557,7 +557,6 @@ public void testReturnsPrimitiveDouble() throws Exception {
.newInstance().execute(), 0);

String debug = Debugger.toString(ReturnsPrimitiveDouble.class, "1", new CompilerSettings());
assertThat(debug, containsString("DCONST_1"));
// The important thing here is that we have the bytecode for returning a double instead of an object
assertThat(debug, containsString("DRETURN"));

Original file line number Diff line number Diff line change
@@ -167,12 +167,12 @@ public void testStringAndCharacter() {
assertEquals('c', exec("String s = \"c\"; (char)s"));
assertEquals('c', exec("String s = 'c'; (char)s"));

ClassCastException expected = expectScriptThrows(ClassCastException.class, false, () -> {
ClassCastException expected = expectScriptThrows(ClassCastException.class, () -> {
assertEquals("cc", exec("return (String)(char)\"cc\""));
});
assertTrue(expected.getMessage().contains("cannot cast java.lang.String with length not equal to one to char"));

expected = expectScriptThrows(ClassCastException.class, false, () -> {
expected = expectScriptThrows(ClassCastException.class, () -> {
assertEquals("cc", exec("return (String)(char)'cc'"));
});
assertTrue(expected.getMessage().contains("cannot cast java.lang.String with length not equal to one to char"));

0 comments on commit f6d89ae

Please sign in to comment.