Skip to content

Commit 022d3d7

Browse files
authored
Remove PainlessCast from AExpression as mutable state (#56047)
PainlessCast currently exists as mutable state on the AExpression node, but this is no longer necessary as each cast is only used directly in the semantic pass after its creation. This change moves it to be local state during the semantic pass as opposed to mutable state on the nodes. Relates #53702
1 parent f36ab09 commit 022d3d7

28 files changed

+193
-104
lines changed

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java

+7-12
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
package org.elasticsearch.painless.node;
2121

22-
import org.elasticsearch.painless.AnalyzerCaster;
2322
import org.elasticsearch.painless.Location;
2423
import org.elasticsearch.painless.Scope;
2524
import org.elasticsearch.painless.ir.CastNode;
@@ -132,20 +131,16 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
132131
throw new UnsupportedOperationException();
133132
}
134133

135-
void cast(Input input, Output output) {
136-
output.painlessCast = AnalyzerCaster.getLegalCast(location, output.actual, input.expected, input.explicit, input.internal);
137-
}
138-
139-
ExpressionNode cast(Output output) {
140-
if (output.painlessCast == null) {
141-
return output.expressionNode;
134+
static ExpressionNode cast(ExpressionNode expressionNode, PainlessCast painlessCast) {
135+
if (painlessCast == null) {
136+
return expressionNode;
142137
}
143138

144139
CastNode castNode = new CastNode();
145-
castNode.setLocation(location);
146-
castNode.setExpressionType(output.painlessCast.targetType);
147-
castNode.setCast(output.painlessCast);
148-
castNode.setChildNode(output.expressionNode);
140+
castNode.setLocation(expressionNode.getLocation());
141+
castNode.setExpressionType(painlessCast.targetType);
142+
castNode.setCast(painlessCast);
143+
castNode.setChildNode(expressionNode);
149144

150145
return castNode;
151146
}

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
6868
boolean cat = false;
6969
Class<?> promote = null;
7070
Class<?> shiftDistance = null;
71+
PainlessCast rightCast;
7172
PainlessCast there = null;
7273
PainlessCast back = null;
7374

@@ -178,7 +179,8 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
178179
rightInput.expected = promote;
179180
}
180181

181-
rhs.cast(rightInput, rightOutput);
182+
rightCast = AnalyzerCaster.getLegalCast(rhs.location,
183+
rightOutput.actual, rightInput.expected, rightInput.explicit, rightInput.internal);
182184

183185
there = AnalyzerCaster.getLegalCast(location, leftOutput.actual, promote, false, false);
184186
back = AnalyzerCaster.getLegalCast(location, promote, leftOutput.actual, true, false);
@@ -210,7 +212,8 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
210212
rightOutput = rhs.analyze(classNode, scriptRoot, scope, rightInput);
211213
}
212214

213-
rhs.cast(rightInput, rightOutput);
215+
rightCast = AnalyzerCaster.getLegalCast(rhs.location,
216+
rightOutput.actual, rightInput.expected, rightInput.explicit, rightInput.internal);
214217
} else {
215218
throw new IllegalStateException("Illegal tree structure.");
216219
}
@@ -220,7 +223,7 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
220223
AssignmentNode assignmentNode = new AssignmentNode();
221224

222225
assignmentNode.setLeftNode(leftOutput.expressionNode);
223-
assignmentNode.setRightNode(rhs.cast(rightOutput));
226+
assignmentNode.setRightNode(cast(rightOutput.expressionNode, rightCast));
224227

225228
assignmentNode.setLocation(location);
226229
assignmentNode.setExpressionType(output.actual);

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.painless.Scope;
2626
import org.elasticsearch.painless.ir.BinaryMathNode;
2727
import org.elasticsearch.painless.ir.ClassNode;
28+
import org.elasticsearch.painless.lookup.PainlessCast;
2829
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
2930
import org.elasticsearch.painless.lookup.def;
3031
import org.elasticsearch.painless.symbol.ScriptRoot;
@@ -141,13 +142,15 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
141142
}
142143
}
143144

144-
left.cast(leftInput, leftOutput);
145-
right.cast(rightInput, rightOutput);
145+
PainlessCast leftCast = AnalyzerCaster.getLegalCast(left.location,
146+
leftOutput.actual, leftInput.expected, leftInput.explicit, leftInput.internal);
147+
PainlessCast rightCast = AnalyzerCaster.getLegalCast(right.location,
148+
rightOutput.actual, rightInput.expected, rightInput.explicit, rightInput.internal);
146149

147150
BinaryMathNode binaryMathNode = new BinaryMathNode();
148151

149-
binaryMathNode.setLeftNode(left.cast(leftOutput));
150-
binaryMathNode.setRightNode(right.cast(rightOutput));
152+
binaryMathNode.setLeftNode(cast(leftOutput.expressionNode, leftCast));
153+
binaryMathNode.setRightNode(cast(rightOutput.expressionNode, rightCast));
151154

152155
binaryMathNode.setLocation(location);
153156
binaryMathNode.setExpressionType(output.actual);

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919

2020
package org.elasticsearch.painless.node;
2121

22+
import org.elasticsearch.painless.AnalyzerCaster;
2223
import org.elasticsearch.painless.Location;
2324
import org.elasticsearch.painless.Operation;
2425
import org.elasticsearch.painless.Scope;
2526
import org.elasticsearch.painless.ir.BooleanNode;
2627
import org.elasticsearch.painless.ir.ClassNode;
28+
import org.elasticsearch.painless.lookup.PainlessCast;
2729
import org.elasticsearch.painless.symbol.ScriptRoot;
2830

2931
import java.util.Objects;
@@ -62,19 +64,21 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
6264
Input leftInput = new Input();
6365
leftInput.expected = boolean.class;
6466
Output leftOutput = left.analyze(classNode, scriptRoot, scope, leftInput);
65-
left.cast(leftInput, leftOutput);
67+
PainlessCast leftCast = AnalyzerCaster.getLegalCast(left.location,
68+
leftOutput.actual, leftInput.expected, leftInput.explicit, leftInput.internal);
6669

6770
Input rightInput = new Input();
6871
rightInput.expected = boolean.class;
6972
Output rightOutput = right.analyze(classNode, scriptRoot, scope, rightInput);
70-
right.cast(rightInput, rightOutput);
73+
PainlessCast rightCast = AnalyzerCaster.getLegalCast(right.location,
74+
rightOutput.actual, rightInput.expected, rightInput.explicit, rightInput.internal);
7175

7276
output.actual = boolean.class;
7377

7478
BooleanNode booleanNode = new BooleanNode();
7579

76-
booleanNode.setLeftNode(left.cast(leftOutput));
77-
booleanNode.setRightNode(right.cast(rightOutput));
80+
booleanNode.setLeftNode(cast(leftOutput.expressionNode, leftCast));
81+
booleanNode.setRightNode(cast(rightOutput.expressionNode, rightCast));
7882

7983
booleanNode.setLocation(location);
8084
booleanNode.setExpressionType(output.actual);

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBrace.java

+13-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.painless.node;
2121

22+
import org.elasticsearch.painless.AnalyzerCaster;
2223
import org.elasticsearch.painless.Location;
2324
import org.elasticsearch.painless.Scope;
2425
import org.elasticsearch.painless.ir.BraceNode;
@@ -28,6 +29,7 @@
2829
import org.elasticsearch.painless.ir.ExpressionNode;
2930
import org.elasticsearch.painless.ir.ListSubShortcutNode;
3031
import org.elasticsearch.painless.ir.MapSubShortcutNode;
32+
import org.elasticsearch.painless.lookup.PainlessCast;
3133
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
3234
import org.elasticsearch.painless.lookup.PainlessMethod;
3335
import org.elasticsearch.painless.lookup.def;
@@ -66,12 +68,13 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
6668
Input indexInput = new Input();
6769
indexInput.expected = int.class;
6870
Output indexOutput = index.analyze(classNode, scriptRoot, scope, indexInput);
69-
index.cast(indexInput, indexOutput);
71+
PainlessCast indexCast = AnalyzerCaster.getLegalCast(index.location,
72+
indexOutput.actual, indexInput.expected, indexInput.explicit, indexInput.internal);
7073

7174
output.actual = prefixOutput.actual.getComponentType();
7275

7376
BraceSubNode braceSubNode = new BraceSubNode();
74-
braceSubNode.setChildNode(index.cast(indexOutput));
77+
braceSubNode.setChildNode(cast(indexOutput.expressionNode, indexCast));
7578
braceSubNode.setLocation(location);
7679
braceSubNode.setExpressionType(output.actual);
7780
expressionNode = braceSubNode;
@@ -109,20 +112,22 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
109112
}
110113

111114
Output indexOutput;
115+
PainlessCast indexCast;
112116

113117
if ((input.read == false || getter != null) && (input.write == false || setter != null)) {
114118
Input indexInput = new Input();
115119
indexInput.expected = setter != null ? setter.typeParameters.get(0) : getter.typeParameters.get(0);
116120
indexOutput = index.analyze(classNode, scriptRoot, scope, indexInput);
117-
index.cast(indexInput, indexOutput);
121+
indexCast = AnalyzerCaster.getLegalCast(index.location,
122+
indexOutput.actual, indexInput.expected, indexInput.explicit, indexInput.internal);
118123

119124
output.actual = setter != null ? setter.typeParameters.get(1) : getter.returnType;
120125
} else {
121126
throw createError(new IllegalArgumentException("Illegal map shortcut for type [" + canonicalClassName + "]."));
122127
}
123128

124129
MapSubShortcutNode mapSubShortcutNode = new MapSubShortcutNode();
125-
mapSubShortcutNode.setChildNode(index.cast(indexOutput));
130+
mapSubShortcutNode.setChildNode(cast(indexOutput.expressionNode, indexCast));
126131
mapSubShortcutNode.setLocation(location);
127132
mapSubShortcutNode.setExpressionType(output.actual);
128133
mapSubShortcutNode.setGetter(getter);
@@ -150,20 +155,22 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
150155
}
151156

152157
Output indexOutput;
158+
PainlessCast indexCast;
153159

154160
if ((input.read == false || getter != null) && (input.write == false || setter != null)) {
155161
Input indexInput = new Input();
156162
indexInput.expected = int.class;
157163
indexOutput = index.analyze(classNode, scriptRoot, scope, indexInput);
158-
index.cast(indexInput, indexOutput);
164+
indexCast = AnalyzerCaster.getLegalCast(index.location,
165+
indexOutput.actual, indexInput.expected, indexInput.explicit, indexInput.internal);
159166

160167
output.actual = setter != null ? setter.typeParameters.get(1) : getter.returnType;
161168
} else {
162169
throw createError(new IllegalArgumentException("Illegal list shortcut for type [" + canonicalClassName + "]."));
163170
}
164171

165172
ListSubShortcutNode listSubShortcutNode = new ListSubShortcutNode();
166-
listSubShortcutNode.setChildNode(index.cast(indexOutput));
173+
listSubShortcutNode.setChildNode(cast(indexOutput.expressionNode, indexCast));
167174
listSubShortcutNode.setLocation(location);
168175
listSubShortcutNode.setExpressionType(output.actual);
169176
listSubShortcutNode.setGetter(getter);

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECall.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.painless.node;
2121

22+
import org.elasticsearch.painless.AnalyzerCaster;
2223
import org.elasticsearch.painless.Location;
2324
import org.elasticsearch.painless.Scope;
2425
import org.elasticsearch.painless.ir.CallNode;
@@ -27,6 +28,7 @@
2728
import org.elasticsearch.painless.ir.ClassNode;
2829
import org.elasticsearch.painless.ir.ExpressionNode;
2930
import org.elasticsearch.painless.ir.NullSafeSubNode;
31+
import org.elasticsearch.painless.lookup.PainlessCast;
3032
import org.elasticsearch.painless.lookup.PainlessMethod;
3133
import org.elasticsearch.painless.lookup.def;
3234
import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation;
@@ -84,18 +86,15 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
8486
throw createError(new IllegalArgumentException(
8587
"Argument(s) cannot be of [void] type when calling method [" + name + "]."));
8688
}
87-
88-
expressionInput.expected = expressionOutput.actual;
89-
argument.cast(expressionInput, expressionOutput);
9089
}
9190

9291
// TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed
9392
output.actual = input.expected == null || input.expected == ZonedDateTime.class || input.explicit ? def.class : input.expected;
9493

9594
CallSubDefNode callSubDefNode = new CallSubDefNode();
9695

97-
for (int argument = 0; argument < arguments.size(); ++ argument) {
98-
callSubDefNode.addArgumentNode(arguments.get(argument).cast(argumentOutputs.get(argument)));
96+
for (Output argumentOutput : argumentOutputs) {
97+
callSubDefNode.addArgumentNode(argumentOutput.expressionNode);
9998
}
10099

101100
callSubDefNode.setLocation(location);
@@ -114,7 +113,8 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
114113

115114
scriptRoot.markNonDeterministic(method.annotations.containsKey(NonDeterministicAnnotation.class));
116115

117-
List<Output> argumentOutputs = new ArrayList<>();
116+
List<Output> argumentOutputs = new ArrayList<>(arguments.size());
117+
List<PainlessCast> argumentCasts = new ArrayList<>(arguments.size());
118118

119119
for (int argument = 0; argument < arguments.size(); ++argument) {
120120
AExpression expression = arguments.get(argument);
@@ -123,16 +123,18 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
123123
expressionInput.expected = method.typeParameters.get(argument);
124124
expressionInput.internal = true;
125125
Output expressionOutput = expression.analyze(classNode, scriptRoot, scope, expressionInput);
126-
expression.cast(expressionInput, expressionOutput);
127126
argumentOutputs.add(expressionOutput);
127+
argumentCasts.add(AnalyzerCaster.getLegalCast(expression.location,
128+
expressionOutput.actual, expressionInput.expected, expressionInput.explicit, expressionInput.internal));
129+
128130
}
129131

130132
output.actual = method.returnType;
131133

132134
CallSubNode callSubNode = new CallSubNode();
133135

134136
for (int argument = 0; argument < arguments.size(); ++ argument) {
135-
callSubNode.addArgumentNode(arguments.get(argument).cast(argumentOutputs.get(argument)));
137+
callSubNode.addArgumentNode(cast(argumentOutputs.get(argument).expressionNode, argumentCasts.get(argument)));
136138
}
137139

138140
callSubNode.setLocation(location);

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919

2020
package org.elasticsearch.painless.node;
2121

22+
import org.elasticsearch.painless.AnalyzerCaster;
2223
import org.elasticsearch.painless.Location;
2324
import org.elasticsearch.painless.Scope;
2425
import org.elasticsearch.painless.ir.ClassNode;
2526
import org.elasticsearch.painless.ir.FieldNode;
2627
import org.elasticsearch.painless.ir.MemberCallNode;
28+
import org.elasticsearch.painless.lookup.PainlessCast;
2729
import org.elasticsearch.painless.lookup.PainlessClassBinding;
2830
import org.elasticsearch.painless.lookup.PainlessInstanceBinding;
2931
import org.elasticsearch.painless.lookup.PainlessMethod;
@@ -158,6 +160,7 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
158160
}
159161

160162
List<Output> argumentOutputs = new ArrayList<>(arguments.size());
163+
List<PainlessCast> argumentCasts = new ArrayList<>(arguments.size());
161164
// if the class binding is using an implicit this reference then the arguments counted must
162165
// be incremented by 1 as the this reference will not be part of the arguments passed into
163166
// the class binding call
@@ -168,14 +171,16 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
168171
argumentInput.expected = typeParameters.get(argument + classBindingOffset);
169172
argumentInput.internal = true;
170173
Output argumentOutput = expression.analyze(classNode, scriptRoot, scope, argumentInput);
171-
expression.cast(argumentInput, argumentOutput);
172174
argumentOutputs.add(argumentOutput);
175+
argumentCasts.add(AnalyzerCaster.getLegalCast(expression.location,
176+
argumentOutput.actual, argumentInput.expected, argumentInput.explicit, argumentInput.internal));
177+
173178
}
174179

175180
MemberCallNode memberCallNode = new MemberCallNode();
176181

177182
for (int argument = 0; argument < arguments.size(); ++argument) {
178-
memberCallNode.addArgumentNode(arguments.get(argument).cast(argumentOutputs.get(argument)));
183+
memberCallNode.addArgumentNode(cast(argumentOutputs.get(argument).expressionNode, argumentCasts.get(argument)));
179184
}
180185

181186
memberCallNode.setLocation(location);

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.painless.Scope;
2626
import org.elasticsearch.painless.ir.ClassNode;
2727
import org.elasticsearch.painless.ir.ComparisonNode;
28+
import org.elasticsearch.painless.lookup.PainlessCast;
2829
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
2930
import org.elasticsearch.painless.lookup.def;
3031
import org.elasticsearch.painless.symbol.ScriptRoot;
@@ -98,15 +99,17 @@ Output analyze(ClassNode classNode, ScriptRoot scriptRoot, Scope scope, Input in
9899
throw createError(new IllegalArgumentException("extraneous comparison of [null] constants"));
99100
}
100101

101-
left.cast(leftInput, leftOutput);
102-
right.cast(rightInput, rightOutput);
102+
PainlessCast leftCast = AnalyzerCaster.getLegalCast(left.location,
103+
leftOutput.actual, leftInput.expected, leftInput.explicit, leftInput.internal);
104+
PainlessCast rightCast = AnalyzerCaster.getLegalCast(right.location,
105+
rightOutput.actual, rightInput.expected, rightInput.explicit, rightInput.internal);
103106

104107
output.actual = boolean.class;
105108

106109
ComparisonNode comparisonNode = new ComparisonNode();
107110

108-
comparisonNode.setLeftNode(left.cast(leftOutput));
109-
comparisonNode.setRightNode(right.cast(rightOutput));
111+
comparisonNode.setLeftNode(cast(leftOutput.expressionNode, leftCast));
112+
comparisonNode.setRightNode(cast(rightOutput.expressionNode, rightCast));
110113

111114
comparisonNode.setLocation(location);
112115
comparisonNode.setExpressionType(output.actual);

0 commit comments

Comments
 (0)