Skip to content

Commit 01289d0

Browse files
committed
GROOVY-10394
1 parent e2743d4 commit 01289d0

File tree

4 files changed

+77
-41
lines changed

4 files changed

+77
-41
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java

+23
Original file line numberDiff line numberDiff line change
@@ -6955,4 +6955,27 @@ public void testCompileStatic10381() {
69556955
"Duplicate default methods named m with the parameters () and () are inherited from the types A and B\n" +
69566956
"----------\n");
69576957
}
6958+
6959+
@Test
6960+
public void testCompileStatic10394() {
6961+
//@formatter:off
6962+
String[] sources = {
6963+
"Main.groovy",
6964+
"@groovy.transform.CompileStatic\n" +
6965+
"class C {\n" +
6966+
" int i = 0, j = 1\n" +
6967+
" Integer getA() { i++ }\n" +
6968+
" Integer getB() { j++ }\n" +
6969+
" void test() {\n" +
6970+
" assert (a <=> b) == -1\n" +
6971+
" print i\n" +
6972+
" print j\n" +
6973+
" }\n" +
6974+
"}\n" +
6975+
"new C().test()\n",
6976+
};
6977+
//@formatter:on
6978+
6979+
runConformTest(sources, "12");
6980+
}
69586981
}

base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java

+6
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ Expression transformBinaryExpression(final BinaryExpression bin) {
161161
if (rightType.implementsInterface(ClassHelper.COMPARABLE_TYPE)) {
162162
Expression left = staticCompilationTransformer.transform(leftExpression);
163163
Expression right = staticCompilationTransformer.transform(rightExpression);
164+
// GRECLIPSE add -- GROOVY-10394
165+
left = transformRepeatedReference(left); right = transformRepeatedReference(right);
166+
// GRECLIPSE end
164167
MethodCallExpression call = new MethodCallExpression(left, "compareTo", new ArgumentListExpression(right));
165168
call.setImplicitThis(false);
166169
call.setMethodTarget(COMPARE_TO_METHOD);
@@ -188,6 +191,9 @@ Expression transformBinaryExpression(final BinaryExpression bin) {
188191
TernaryExpression expr = (TernaryExpression) result.getFalseExpression();
189192
expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
190193
expr.getFalseExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
194+
// GRECLIPSE add -- GROOVY-10394
195+
expr.putNodeMetaData("classgen.callback", classgenCallback(right).andThen(classgenCallback(left)));
196+
// GRECLIPSE end
191197
return result;
192198
}
193199
}

base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ public Expression transformBinaryExpression(final BinaryExpression bin) {
178178
if (operationType == Types.COMPARE_TO
179179
&& findType(leftExpression).implementsInterface(ClassHelper.COMPARABLE_TYPE)
180180
&& findType(rightExpression).implementsInterface(ClassHelper.COMPARABLE_TYPE)) {
181+
// GRECLIPSE add -- GROOVY-10394
182+
left = transformRepeatedReference(left);
183+
right = transformRepeatedReference(right);
184+
// GRECLIPSE end
181185
call = callX(left, "compareTo", args(right));
182186
call.setImplicitThis(false);
183187
call.setMethodTarget(COMPARE_TO_METHOD);
@@ -206,7 +210,9 @@ && findType(rightExpression).implementsInterface(ClassHelper.COMPARABLE_TYPE)) {
206210
expr
207211
);
208212
expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
209-
213+
// GRECLIPSE add -- GROOVY-10394
214+
expr.putNodeMetaData("classgen.callback", classgenCallback(right).andThen(classgenCallback(left)));
215+
// GRECLIPSE end
210216
return expr;
211217
}
212218

base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java

+41-40
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ public Expression transformBinaryExpression(final BinaryExpression bin) {
124124
case Types.COMPARE_NOT_EQUAL:
125125
case Types.COMPARE_NOT_IDENTICAL:
126126
expr = transformEqualityComparison(bin, equal);
127+
if (expr != null) return expr; else break;
128+
case Types.COMPARE_TO:
129+
expr = transformRelationComparison(bin);
127130
if (expr != null) return expr;
128131
}
129132

@@ -229,8 +232,7 @@ private static Expression transformAssignmentToSetterCall(
229232
}
230233

231234
private Expression transformInOperation(final BinaryExpression bin, final boolean in) {
232-
Expression leftExpression = bin.getLeftExpression();
233-
Expression rightExpression = bin.getRightExpression();
235+
Expression leftExpression = bin.getLeftExpression(), rightExpression = bin.getRightExpression();
234236

235237
// transform "left [!]in right" into "right.is[Not]Case(left)"
236238
MethodCallExpression call = callX(rightExpression, in ? "isCase" : "isNotCase", leftExpression);
@@ -282,6 +284,41 @@ private Expression transformEqualityComparison(final BinaryExpression bin, final
282284
return null;
283285
}
284286

287+
private Expression transformRelationComparison(final BinaryExpression bin) {
288+
Expression leftExpression = bin.getLeftExpression(), rightExpression = bin.getRightExpression();
289+
ClassNode leftType = findType(leftExpression), rightType = findType(rightExpression);
290+
291+
if (leftType.implementsInterface(ClassHelper.COMPARABLE_TYPE)
292+
&& rightType.implementsInterface(ClassHelper.COMPARABLE_TYPE)) {
293+
// GROOVY-5644, GROOVY-6137, GROOVY-7473, GROOVY-10394: null safety and one-time evaluation
294+
Expression left = transformRepeatedReference(staticCompilationTransformer.transform(leftExpression));
295+
Expression right = transformRepeatedReference(staticCompilationTransformer.transform(rightExpression));
296+
297+
MethodCallExpression call = callX(left, "compareTo", args(right));
298+
call.setMethodTarget(COMPARE_TO_METHOD);
299+
call.setImplicitThis(false);
300+
call.setSourcePosition(bin);
301+
302+
// right == null ? 1 : left.compareTo(right)
303+
Expression expr = ternaryX(new CompareToNullExpression(right, true), CONSTANT_ONE, call);
304+
expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
305+
306+
// left == null ? -1 : (right == null ? 1 : left.compareTo(right))
307+
expr = ternaryX(new CompareToNullExpression(left, true), CONSTANT_MINUS_ONE, expr);
308+
expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
309+
310+
// left === right ? 0 : (left == null ? -1 : (right == null ? 1 : left.compareTo(right)))
311+
expr = ternaryX(new CompareIdentityExpression(left, right), CONSTANT_ZERO, expr);
312+
expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
313+
expr.putNodeMetaData("classgen.callback", // pop temporary variables
314+
classgenCallback(right).andThen(classgenCallback(left)));
315+
316+
return expr;
317+
}
318+
319+
return null;
320+
}
321+
285322
private Expression transformMultipleAssignment(final BinaryExpression bin) {
286323
ListOfExpressionsExpression list = new ListOfExpressionsExpression();
287324
List<Expression> leftExpressions = ((TupleExpression) bin.getLeftExpression()).getExpressions();
@@ -330,54 +367,18 @@ private Expression transformMultipleAssignment(final BinaryExpression bin) {
330367
}
331368

332369
private Expression transformToTargetMethodCall(final BinaryExpression bin, final MethodNode node, final String name) {
333-
MethodCallExpression call;
334-
Token operation = bin.getOperation();
335-
int operationType = operation.getType();
370+
Token operation = bin.getOperation(); int operationType = operation.getType();
336371
Expression left = staticCompilationTransformer.transform(bin.getLeftExpression());
337372
Expression right = staticCompilationTransformer.transform(bin.getRightExpression());
338373

339-
if (operationType == Types.COMPARE_TO
340-
&& findType(left).implementsInterface(ClassHelper.COMPARABLE_TYPE)
341-
&& findType(right).implementsInterface(ClassHelper.COMPARABLE_TYPE)) {
342-
call = callX(left, "compareTo", args(right));
343-
call.setImplicitThis(false);
344-
call.setMethodTarget(COMPARE_TO_METHOD);
345-
call.setSourcePosition(bin);
346-
347-
// right == null ? 1 : left.compareTo(right)
348-
Expression expr = ternaryX(
349-
new CompareToNullExpression(right, true),
350-
CONSTANT_ONE,
351-
call
352-
);
353-
expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
354-
355-
// left == null ? -1 : (right == null ? 1 : left.compareTo(right))
356-
expr = ternaryX(
357-
new CompareToNullExpression(left, true),
358-
CONSTANT_MINUS_ONE,
359-
expr
360-
);
361-
expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
362-
363-
// left === right ? 0 : (left == null ? -1 : (right == null ? 1 : left.compareTo(right)))
364-
expr = ternaryX(
365-
new CompareIdentityExpression(left, right),
366-
CONSTANT_ZERO,
367-
expr
368-
);
369-
expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
370-
371-
return expr;
372-
}
373-
374374
Expression expr = tryOptimizeCharComparison(left, right, bin);
375375
if (expr != null) {
376376
expr.removeNodeMetaData(StaticCompilationMetadataKeys.BINARY_EXP_TARGET);
377377
expr.removeNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
378378
return expr;
379379
}
380380

381+
MethodCallExpression call;
381382
// replace the binary expression with a method call to ScriptBytecodeAdapter or something else
382383
MethodNode adapter = StaticCompilationTransformer.BYTECODE_BINARY_ADAPTERS.get(operationType);
383384
if (adapter != null) {

0 commit comments

Comments
 (0)