You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/11/28 00:39:42 UTC
[groovy] 01/01: GROOVY-10383: SC: optimize `a !in b`
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY-10383
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 9217fa8197c51b1c82148d7c5c94e0eacd996ea7
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Nov 27 18:39:26 2021 -0600
GROOVY-10383: SC: optimize `a !in b`
---
.../transformers/BinaryExpressionTransformer.java | 13 +++----
.../transform/stc/STCnAryExpressionTest.groovy | 40 ++++++++++++++++++++++
2 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java b/src/main/java/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java
index f1a6de5..5f8907b 100644
--- a/src/main/java/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java
+++ b/src/main/java/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java
@@ -61,7 +61,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.binX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.isNullX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements;
import static org.codehaus.groovy.ast.tools.GeneralUtils.ternaryX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
@@ -115,7 +114,9 @@ public class BinaryExpressionTransformer {
}
break;
case Types.KEYWORD_IN:
- return transformInOperation(bin);
+ equal = true; //fallthrough
+ case Types.COMPARE_NOT_IN:
+ return transformInOperation(bin, equal);
case Types.COMPARE_EQUAL:
case Types.COMPARE_IDENTICAL:
equal = true; //fallthrough
@@ -226,12 +227,12 @@ public class BinaryExpressionTransformer {
pos);
}
- private Expression transformInOperation(final BinaryExpression bin) {
+ private Expression transformInOperation(final BinaryExpression bin, final boolean in) {
Expression leftExpression = bin.getLeftExpression();
Expression rightExpression = bin.getRightExpression();
- // transform "left in right" into "right.isCase(left)"
- MethodCallExpression call = callX(rightExpression, "isCase", leftExpression);
+ // transform "left [!]in right" into "right.is[Not]Case(left)"
+ MethodCallExpression call = callX(rightExpression, in ? "isCase" : "isNotCase", leftExpression);
call.setImplicitThis(false); call.setSourcePosition(bin); call.copyNodeMetaData(bin);
call.setMethodTarget(bin.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET));
// GROOVY-7473: no null test for simple cases
@@ -245,7 +246,7 @@ public class BinaryExpressionTransformer {
// GROOVY-6137, GROOVY-7473: null safety and one-time evaluation
call.setObjectExpression(rightExpression = transformRepeatedReference(rightExpression));
- Expression safe = ternaryX(isNullX( rightExpression ), isNullX( leftExpression ), call);
+ Expression safe = ternaryX(new CompareToNullExpression(rightExpression,true), new CompareToNullExpression(leftExpression,in), call);
safe.putNodeMetaData("classgen.callback", classgenCallback(call.getObjectExpression()));
return staticCompilationTransformer.transform(safe);
}
diff --git a/src/test/groovy/transform/stc/STCnAryExpressionTest.groovy b/src/test/groovy/transform/stc/STCnAryExpressionTest.groovy
index 51fe8a4..2d79f8b 100644
--- a/src/test/groovy/transform/stc/STCnAryExpressionTest.groovy
+++ b/src/test/groovy/transform/stc/STCnAryExpressionTest.groovy
@@ -172,6 +172,46 @@ class STCnAryExpressionTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-6137, GROOVY-7473, GROOVY-10383
+ void testInOperatorShouldEvaluateOperandsOnce2() {
+ assertScript '''
+ import groovy.transform.Field
+
+ @Field int i = 0
+ @Field int j = 0
+ int getA() { i++ }
+ int getB() { j++ }
+
+ assert !(a !in b)
+ assert i == 1
+ assert j == 1
+ '''
+ assertScript '''
+ import groovy.transform.Field
+
+ @Field int i = 0
+ @Field int j = 0
+ def getA() { i++; null }
+ def getB() { j++ }
+
+ assert a !in b
+ assert i == 1
+ assert j == 1
+ '''
+ assertScript '''
+ import groovy.transform.Field
+
+ @Field int i = 0
+ @Field int j = 0
+ def getA() { i++ }
+ def getB() { j++; null }
+
+ assert a !in b
+ assert i == 1
+ assert j == 1
+ '''
+ }
+
void testComparisonOperatorCheckWithIncompatibleTypesOkIfComparableNotImplemented() {
shouldFailWithMessages '''
[] < 1