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/20 18:09:08 UTC

[groovy] branch master updated (5174938 -> bec691d)

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git.


    from 5174938  GROOVY-7473: SC: change `a in b` into `b.isCase(a)` for obvious non-null
     new 2c16089  refactor `BinaryExpressionTransformer`
     new bec691d  GROOVY-10377: SC: optimize `x === null` and `x !== null`

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../transformers/BinaryExpressionTransformer.java  | 585 +++++++++++----------
 1 file changed, 298 insertions(+), 287 deletions(-)

[groovy] 01/02: refactor `BinaryExpressionTransformer`

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 2c1608903b946430cb055acc948a10d70d40e695
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Nov 20 11:57:31 2021 -0600

    refactor `BinaryExpressionTransformer`
---
 .../transformers/BinaryExpressionTransformer.java  | 583 +++++++++++----------
 1 file changed, 296 insertions(+), 287 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 3dfd7c8..8ec2ec7 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
@@ -62,14 +62,6 @@ 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;
-import static org.codehaus.groovy.ast.ClassHelper.isBigDecimalType;
-import static org.codehaus.groovy.ast.ClassHelper.isBigIntegerType;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperByte;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperDouble;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperFloat;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperInteger;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperLong;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperShort;
 
 public class BinaryExpressionTransformer {
     private static final MethodNode COMPARE_TO_METHOD = ClassHelper.COMPARABLE_TYPE.getMethods("compareTo").get(0);
@@ -86,250 +78,319 @@ public class BinaryExpressionTransformer {
     }
 
     public Expression transformBinaryExpression(final BinaryExpression bin) {
-        if (bin instanceof DeclarationExpression) {
-            Expression optimized = transformDeclarationExpression(bin);
-            if (optimized != null) {
-                return optimized;
-            }
-        }
-
-        Token operation = bin.getOperation();
-        int operationType = operation.getType();
         Expression leftExpression = bin.getLeftExpression();
         Expression rightExpression = bin.getRightExpression();
+
         if (bin instanceof DeclarationExpression
                 && leftExpression instanceof VariableExpression
-                && rightExpression instanceof ConstantExpression) {
+                && rightExpression instanceof ConstantExpression
+                && !((ConstantExpression) rightExpression).isNullExpression()) {
             ClassNode declarationType = ((VariableExpression) leftExpression).getOriginType();
+            // for "char x = 'c'" change 'c' from String to char
+            if (declarationType.equals(ClassHelper.char_TYPE)) {
+                Character c = tryCharConstant(rightExpression);
+                if (c != null)
+                    return transformCharacterInitialization(bin, c);
+            }
+            // for "float|double|BigDecimal x = n" change n's type
             if (!rightExpression.getType().equals(declarationType)
                     && ClassHelper.getWrapper(declarationType).isDerivedFrom(ClassHelper.Number_TYPE)
                     && WideningCategories.isDoubleCategory(ClassHelper.getUnwrapper(declarationType))) {
-                ConstantExpression constant = (ConstantExpression) rightExpression;
-                if (!constant.isNullExpression()) {
-                    return optimizeConstantInitialization(bin, operation, constant, leftExpression, declarationType);
-                }
+                return transformFloatingPointInitialization(bin, (Number) ((ConstantExpression) rightExpression).getValue(), declarationType);
             }
         }
-        if (operationType == Types.ASSIGN) {
-            // GROOVY-10029: add "?.toArray(new T[0])" to "T[] array = collectionOfT" assignments
-            ClassNode leftType = findType(leftExpression), rightType = findType(rightExpression);
-            if (leftType.isArray() && !(rightExpression instanceof ListExpression) && isOrImplements(rightType, ClassHelper.COLLECTION_TYPE)) {
-                ArrayExpression emptyArray = new ArrayExpression(leftType.getComponentType(), null, Collections.singletonList(CONSTANT_ZERO));
-                rightExpression = callX(rightExpression, "toArray", args(emptyArray));
-                rightExpression.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, leftType);
-                ((MethodCallExpression) rightExpression).setMethodTarget(
-                        rightType.getMethod("toArray", new Parameter[]{new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "a")}));
-                ((MethodCallExpression) rightExpression).setImplicitThis(false);
-                ((MethodCallExpression) rightExpression).setSafe(true);
-            }
 
-            MethodNode directMCT = leftExpression.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
-            if (directMCT != null) {
-                Expression left = staticCompilationTransformer.transform(leftExpression);
-                Expression right = staticCompilationTransformer.transform(rightExpression);
-                if (left instanceof PropertyExpression) {
-                    // transform "a.x = val" into "def tmp = val; a.setX(tmp); tmp"
-                    PropertyExpression pe = (PropertyExpression) left;
-                    return transformAssignmentToSetterCall(
-                            pe.getObjectExpression(), // "a"
-                            directMCT, // "setX"
-                            right, // "val"
-                            false,
-                            pe.isSafe(),
-                            pe.getProperty(), // "x"
-                            bin // "a.x = val"
-                    );
-                } else if (left instanceof VariableExpression) {
-                    // transform "x = val" into "def tmp = val; this.setX(tmp); tmp"
-                    return transformAssignmentToSetterCall(
-                            varX("this"),
-                            directMCT, // "setX"
-                            right, // "val"
-                            true,
-                            false,
-                            left, // "x"
-                            bin // "x = val"
-                    );
-                }
+        boolean equal = false;
+        switch (bin.getOperation().getType()) {
+          case Types.ASSIGN:
+            optimizeArrayCollectionAssignment(bin); // GROOVY-10029
+            Expression expr = transformAssignmentToSetterCall(bin);
+            if (expr != null) return expr;
+            if (leftExpression instanceof TupleExpression
+                    && rightExpression instanceof ListExpression) {
+                return transformMultipleAssignment(bin);
             }
+            break;
+          case Types.KEYWORD_IN:
+            return transformInOperation(bin);
+          case Types.COMPARE_EQUAL:
+            equal = true; //fallthrough
+          case Types.COMPARE_NOT_EQUAL:
+            expr = transformEqualityComparison(bin, equal);
+            if (expr != null) return expr;
+        }
 
-            // if not transformed to setter call but RHS has been transformed...
-            if (rightExpression != bin.getRightExpression()) {
-                bin.setRightExpression(rightExpression);
-            }
-        } else if (operationType == Types.COMPARE_EQUAL || operationType == Types.COMPARE_NOT_EQUAL) {
-            // let's check if one of the operands is the null constant
-            CompareToNullExpression compareToNullExpression = null;
-            if (isNullConstant(leftExpression)) {
-                compareToNullExpression = new CompareToNullExpression(staticCompilationTransformer.transform(rightExpression), operationType == Types.COMPARE_EQUAL);
-            } else if (isNullConstant(rightExpression)) {
-                compareToNullExpression = new CompareToNullExpression(staticCompilationTransformer.transform(leftExpression), operationType == Types.COMPARE_EQUAL);
-            }
-            if (compareToNullExpression != null) {
-                compareToNullExpression.setSourcePosition(bin);
-                return compareToNullExpression;
-            }
-        } else if (operationType == Types.KEYWORD_IN) {
-            // transform "left in right" into "right.isCase(left)"
-            MethodCallExpression call = callX(rightExpression, "isCase", 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
-            if (rightExpression instanceof ListExpression
-                    || rightExpression instanceof MapExpression
-                    || rightExpression instanceof RangeExpression
-                    || rightExpression instanceof ConstantExpression
-                                && !isNullConstant(rightExpression))
-                return staticCompilationTransformer.transform(call);
-
-            // then "right == null ? left == null : right.isCase(left)" for null safety
-            return staticCompilationTransformer.transform(ternaryX(isNullX(rightExpression), isNullX(leftExpression), call));
+        Object[] array = bin.getNodeMetaData(StaticCompilationMetadataKeys.BINARY_EXP_TARGET);
+        if (array != null) {
+            return transformToTargetMethodCall(bin, (MethodNode) array[0], (String) array[1]);
         }
 
-        Object[] list = bin.getNodeMetaData(StaticCompilationMetadataKeys.BINARY_EXP_TARGET);
-        if (list != null) {
-            MethodCallExpression call;
-            Expression left = staticCompilationTransformer.transform(leftExpression);
-            Expression right = staticCompilationTransformer.transform(rightExpression);
-
-            if (operationType == Types.COMPARE_TO
-                    && findType(left).implementsInterface(ClassHelper.COMPARABLE_TYPE)
-                    && findType(right).implementsInterface(ClassHelper.COMPARABLE_TYPE)) {
-                call = callX(left, "compareTo", args(right));
-                call.setImplicitThis(false);
-                call.setMethodTarget(COMPARE_TO_METHOD);
-                call.setSourcePosition(bin);
-
-                // right == null ? 1 : left.compareTo(right)
-                Expression expr = ternaryX(
-                        new CompareToNullExpression(right, true),
-                        CONSTANT_ONE,
-                        call
-                );
-                expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
-
-                // left == null ? -1 : (right == null ? 1 : left.compareTo(right))
-                expr = ternaryX(
-                        new CompareToNullExpression(left, true),
-                        CONSTANT_MINUS_ONE,
-                        expr
-                );
-                expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
-
-                // left === right ? 0 : (left == null ? -1 : (right == null ? 1 : left.compareTo(right)))
-                expr = ternaryX(
-                        new CompareIdentityExpression(left, right),
-                        CONSTANT_ZERO,
-                        expr
-                );
-                expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
-
-                return expr;
-            }
+        return staticCompilationTransformer.superTransform(bin);
+    }
 
-            Expression expr = tryOptimizeCharComparison(left, right, bin);
-            if (expr != null) {
-                expr.removeNodeMetaData(StaticCompilationMetadataKeys.BINARY_EXP_TARGET);
-                expr.removeNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
-                return expr;
-            }
+    private Expression transformCharacterInitialization(final BinaryExpression bin, final Character rhs) {
+        Expression ce = constX(rhs, true);
+        ce.setSourcePosition(bin.getRightExpression());
+
+        bin.setRightExpression(ce);
+        return bin;
+    }
+
+    private Expression transformFloatingPointInitialization(final BinaryExpression bin, final Number rhs, final ClassNode lhsType) {
+        Expression ce = constX(convertConstant(rhs, ClassHelper.getWrapper(lhsType)), true);
+        ce.setSourcePosition(bin.getRightExpression());
+        ce.setType(lhsType);
+
+        bin.setRightExpression(ce);
+        return bin;
+    }
 
-            // replace the binary expression with a method call to ScriptBytecodeAdapter or something else
-            MethodNode adapter = StaticCompilationTransformer.BYTECODE_BINARY_ADAPTERS.get(operationType);
-            if (adapter != null) {
-                Expression sba = classX(StaticCompilationTransformer.BYTECODE_ADAPTER_CLASS);
-                call = callX(sba, adapter.getName(), args(left, right));
-                call.setMethodTarget(adapter);
-            } else {
-                call = callX(left, (String) list[1], args(right));
-                call.setMethodTarget((MethodNode) list[0]);
+    /**
+     * Adds "?.toArray(new T[0])" to "T[] array = collectionOfT" assignments.
+     */
+    private void optimizeArrayCollectionAssignment(final BinaryExpression bin) {
+        Expression rightExpression = bin.getRightExpression();
+        ClassNode leftType = findType(bin.getLeftExpression()), rightType = findType(rightExpression);
+        if (leftType.isArray() && !(rightExpression instanceof ListExpression) && isOrImplements(rightType, ClassHelper.COLLECTION_TYPE)) {
+            ArrayExpression emptyArray = new ArrayExpression(leftType.getComponentType(), null, Collections.singletonList(CONSTANT_ZERO));
+            rightExpression = callX(rightExpression, "toArray", args(emptyArray));
+            rightExpression.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, leftType);
+            ((MethodCallExpression) rightExpression).setMethodTarget(
+                    rightType.getMethod("toArray", new Parameter[]{new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "a")}));
+            ((MethodCallExpression) rightExpression).setImplicitThis(false);
+            ((MethodCallExpression) rightExpression).setSafe(true);
+            bin.setRightExpression(rightExpression);
+        }
+    }
+
+    private Expression transformAssignmentToSetterCall(final BinaryExpression bin) {
+        MethodNode directMCT = bin.getLeftExpression().getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+        if (directMCT != null) {
+            Expression left = staticCompilationTransformer.transform(bin.getLeftExpression());
+            Expression right = staticCompilationTransformer.transform(bin.getRightExpression());
+            if (left instanceof PropertyExpression) {
+                // transform "a.x = val" into "def tmp = val; a.setX(tmp); tmp"
+                PropertyExpression pe = (PropertyExpression) left;
+                return transformAssignmentToSetterCall(
+                        pe.getObjectExpression(), // "a"
+                        directMCT, // "setX"
+                        right, // "val"
+                        false,
+                        pe.isSafe(),
+                        pe.getProperty(), // "x"
+                        bin);
             }
-            call.setImplicitThis(false);
-            if (Types.isAssignment(operationType)) { // +=, -=, /=, ...
-                // GROOVY-5746: one execution of receiver and subscript
-                if (left instanceof BinaryExpression) {
-                    BinaryExpression be = (BinaryExpression) left;
-                    if (be.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
-                        be.setLeftExpression(new TemporaryVariableExpression(be.getLeftExpression()));
-                        be.setRightExpression(new TemporaryVariableExpression(be.getRightExpression()));
-                    }
-                }
-                // call handles the operation, so we must add the assignment now
-                expr = binX(left, Token.newSymbol(Types.ASSIGN, operation.getStartLine(), operation.getStartColumn()), call);
-            } else {
-                expr = call;
+            if (left instanceof VariableExpression) {
+                // transform "x = val" into "def tmp = val; this.setX(tmp); tmp"
+                return transformAssignmentToSetterCall(
+                        varX("this"),
+                        directMCT, // "setX"
+                        right, // "val"
+                        true,
+                        false,
+                        left, // "x"
+                        bin);
             }
-            expr.setSourcePosition(bin);
-            return expr;
         }
+        return null;
+    }
 
-        if (operationType == Types.ASSIGN && leftExpression instanceof TupleExpression && rightExpression instanceof ListExpression) {
-            // multiple assignment
-            ListOfExpressionsExpression cle = new ListOfExpressionsExpression();
-            boolean isDeclaration = (bin instanceof DeclarationExpression);
-            List<Expression> leftExpressions = ((TupleExpression) leftExpression).getExpressions();
-            List<Expression> rightExpressions = ((ListExpression) rightExpression).getExpressions();
-            Iterator<Expression> leftIt = leftExpressions.iterator();
-            Iterator<Expression> rightIt = rightExpressions.iterator();
-            if (isDeclaration) {
-                while (leftIt.hasNext()) {
-                    Expression left = leftIt.next();
-                    if (rightIt.hasNext()) {
-                        Expression right = rightIt.next();
-                        BinaryExpression bexp = new DeclarationExpression(left, operation, right);
-                        bexp.setSourcePosition(right);
-                        cle.addExpression(bexp);
-                    }
-                }
-            } else {
-                // (next, result) = [ result, next+result ]
-                // -->
-                // def tmp1 = result
-                // def tmp2 = next+result
-                // next = tmp1
-                // result = tmp2
-                int size = rightExpressions.size();
-                List<Expression> tmpAssignments = new ArrayList<>(size);
-                List<Expression> finalAssignments = new ArrayList<>(size);
-                for (int i = 0, n = Math.min(size, leftExpressions.size()); i < n; i += 1) {
-                    Expression left = leftIt.next();
+    /**
+     * Adapter for {@link StaticPropertyAccessHelper#transformToSetterCall}.
+     */
+    private static Expression transformAssignmentToSetterCall(
+            final Expression receiver,
+            final MethodNode setterMethod,
+            final Expression valueExpression,
+            final boolean implicitThis,
+            final boolean safeNavigation,
+            final Expression nameExpression,
+            final Expression sourceExpression) {
+        // expression that will transfer assignment and name positions
+        Expression pos = new PropertyExpression(null, nameExpression);
+        pos.setSourcePosition(sourceExpression);
+
+        return StaticPropertyAccessHelper.transformToSetterCall(
+                receiver,
+                setterMethod,
+                valueExpression,
+                implicitThis,
+                safeNavigation,
+                false, // spreadSafe
+                true, // TODO: replace with a proper test whether a return value is required or not
+                pos);
+    }
+
+    private Expression transformInOperation(final BinaryExpression bin) {
+        Expression leftExpression = bin.getLeftExpression();
+        Expression rightExpression = bin.getRightExpression();
+
+        // transform "left in right" into "right.isCase(left)"
+        MethodCallExpression call = callX(rightExpression, "isCase", 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
+        if (rightExpression instanceof ListExpression
+                || rightExpression instanceof MapExpression
+                || rightExpression instanceof RangeExpression
+                || rightExpression instanceof ConstantExpression
+                            && !isNullConstant(rightExpression))
+            return staticCompilationTransformer.transform(call);
+
+        // then "right == null ? left == null : right.isCase(left)" for null safety
+        return staticCompilationTransformer.transform(ternaryX(isNullX(rightExpression), isNullX(leftExpression), call));
+    }
+
+    private Expression transformEqualityComparison(final BinaryExpression bin, final boolean eq) {
+        if (isNullConstant(bin.getRightExpression())) {
+            Expression ctn = new CompareToNullExpression(staticCompilationTransformer.transform(bin.getLeftExpression()), eq);
+            ctn.setSourcePosition(bin);
+            return ctn;
+        }
+        if (isNullConstant(bin.getLeftExpression())) {
+            Expression ctn = new CompareToNullExpression(staticCompilationTransformer.transform(bin.getRightExpression()), eq);
+            ctn.setSourcePosition(bin);
+            return ctn;
+        }
+        return null;
+    }
+
+    private Expression transformMultipleAssignment(final BinaryExpression bin) {
+        ListOfExpressionsExpression list = new ListOfExpressionsExpression();
+        List<Expression> leftExpressions = ((TupleExpression) bin.getLeftExpression()).getExpressions();
+        List<Expression> rightExpressions = ((ListExpression) bin.getRightExpression()).getExpressions();
+        Iterator<Expression> leftIt = leftExpressions.iterator();
+        Iterator<Expression> rightIt = rightExpressions.iterator();
+        if (bin instanceof DeclarationExpression) {
+            while (leftIt.hasNext()) {
+                Expression left = leftIt.next();
+                if (rightIt.hasNext()) {
                     Expression right = rightIt.next();
-                    VariableExpression tmpVar = varX("$tmpVar$" + tmpVarCounter++);
-                    BinaryExpression bexp = new DeclarationExpression(tmpVar, operation, right);
+                    BinaryExpression bexp = new DeclarationExpression(left, bin.getOperation(), right);
                     bexp.setSourcePosition(right);
-                    tmpAssignments.add(bexp);
-                    bexp = binX(left, operation, varX(tmpVar));
-                    bexp.setSourcePosition(left);
-                    finalAssignments.add(bexp);
-                }
-                for (Expression tmpAssignment : tmpAssignments) {
-                    cle.addExpression(tmpAssignment);
-                }
-                for (Expression finalAssignment : finalAssignments) {
-                    cle.addExpression(finalAssignment);
+                    list.addExpression(bexp);
                 }
             }
-            return staticCompilationTransformer.transform(cle);
+        } else {
+            // (next, result) = [ result, next+result ]
+            // -->
+            // def tmp1 = result
+            // def tmp2 = next+result
+            // next = tmp1
+            // result = tmp2
+            int size = rightExpressions.size();
+            List<Expression> tmpAssignments = new ArrayList<>(size);
+            List<Expression> finalAssignments = new ArrayList<>(size);
+            for (int i = 0, n = Math.min(size, leftExpressions.size()); i < n; i += 1) {
+                Expression left = leftIt.next();
+                Expression right = rightIt.next();
+                VariableExpression tmpVar = varX("$tmpVar$" + tmpVarCounter++);
+                BinaryExpression bexp = new DeclarationExpression(tmpVar, bin.getOperation(), right);
+                bexp.setSourcePosition(right);
+                tmpAssignments.add(bexp);
+                bexp = binX(left, bin.getOperation(), varX(tmpVar));
+                bexp.setSourcePosition(left);
+                finalAssignments.add(bexp);
+            }
+            for (Expression tmpAssignment : tmpAssignments) {
+                list.addExpression(tmpAssignment);
+            }
+            for (Expression finalAssignment : finalAssignments) {
+                list.addExpression(finalAssignment);
+            }
         }
-        return staticCompilationTransformer.superTransform(bin);
+        return staticCompilationTransformer.transform(list);
     }
 
-    private ClassNode findType(final Expression expression) {
-        ClassNode classNode = staticCompilationTransformer.getClassNode();
-        return staticCompilationTransformer.getTypeChooser().resolveType(expression, classNode);
+    private Expression transformToTargetMethodCall(final BinaryExpression bin, final MethodNode node, final String name) {
+        MethodCallExpression call;
+        Token operation = bin.getOperation();
+        int operationType = operation.getType();
+        Expression left = staticCompilationTransformer.transform(bin.getLeftExpression());
+        Expression right = staticCompilationTransformer.transform(bin.getRightExpression());
+
+        if (operationType == Types.COMPARE_TO
+                && findType(left).implementsInterface(ClassHelper.COMPARABLE_TYPE)
+                && findType(right).implementsInterface(ClassHelper.COMPARABLE_TYPE)) {
+            call = callX(left, "compareTo", args(right));
+            call.setImplicitThis(false);
+            call.setMethodTarget(COMPARE_TO_METHOD);
+            call.setSourcePosition(bin);
+
+            // right == null ? 1 : left.compareTo(right)
+            Expression expr = ternaryX(
+                    new CompareToNullExpression(right, true),
+                    CONSTANT_ONE,
+                    call
+            );
+            expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
+
+            // left == null ? -1 : (right == null ? 1 : left.compareTo(right))
+            expr = ternaryX(
+                    new CompareToNullExpression(left, true),
+                    CONSTANT_MINUS_ONE,
+                    expr
+            );
+            expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
+
+            // left === right ? 0 : (left == null ? -1 : (right == null ? 1 : left.compareTo(right)))
+            expr = ternaryX(
+                    new CompareIdentityExpression(left, right),
+                    CONSTANT_ZERO,
+                    expr
+            );
+            expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE);
+
+            return expr;
+        }
+
+        Expression expr = tryOptimizeCharComparison(left, right, bin);
+        if (expr != null) {
+            expr.removeNodeMetaData(StaticCompilationMetadataKeys.BINARY_EXP_TARGET);
+            expr.removeNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+            return expr;
+        }
+
+        // replace the binary expression with a method call to ScriptBytecodeAdapter or something else
+        MethodNode adapter = StaticCompilationTransformer.BYTECODE_BINARY_ADAPTERS.get(operationType);
+        if (adapter != null) {
+            Expression sba = classX(StaticCompilationTransformer.BYTECODE_ADAPTER_CLASS);
+            call = callX(sba, adapter.getName(), args(left, right));
+            call.setMethodTarget(adapter);
+        } else {
+            call = callX(left, name, args(right));
+            call.setMethodTarget(node);
+        }
+        call.setImplicitThis(false);
+        if (Types.isAssignment(operationType)) { // +=, -=, /=, ...
+            // GROOVY-5746: one execution of receiver and subscript
+            if (left instanceof BinaryExpression) {
+                BinaryExpression be = (BinaryExpression) left;
+                if (be.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
+                    be.setLeftExpression(new TemporaryVariableExpression(be.getLeftExpression()));
+                    be.setRightExpression(new TemporaryVariableExpression(be.getRightExpression()));
+                }
+            }
+            // call handles the operation, so we must add the assignment now
+            expr = binX(left, Token.newSymbol(Types.ASSIGN, operation.getStartLine(), operation.getStartColumn()), call);
+        } else {
+            expr = call;
+        }
+        expr.setSourcePosition(bin);
+        return expr;
     }
 
-    private static BinaryExpression tryOptimizeCharComparison(final Expression left, final Expression right, final BinaryExpression bin) {
+    private BinaryExpression tryOptimizeCharComparison(final Expression left, final Expression right, final BinaryExpression bin) {
         int op = bin.getOperation().getType();
         if (StaticTypeCheckingSupport.isCompareToBoolean(op) || op == Types.COMPARE_EQUAL || op == Types.COMPARE_NOT_EQUAL) {
             Character cLeft = tryCharConstant(left);
             Character cRight = tryCharConstant(right);
             if (cLeft != null || cRight != null) {
                 Expression oLeft = (cLeft == null ? left : constX(cLeft, true));
-                if (oLeft instanceof PropertyExpression && !hasCharType((PropertyExpression)oLeft)) return null;
+                if (oLeft instanceof PropertyExpression && !hasCharType(oLeft)) return null;
                 oLeft.setSourcePosition(left);
                 Expression oRight = (cRight == null ? right : constX(cRight, true));
-                if (oRight instanceof PropertyExpression && !hasCharType((PropertyExpression)oRight)) return null;
+                if (oRight instanceof PropertyExpression && !hasCharType(oRight)) return null;
                 oRight.setSourcePosition(right);
                 bin.setLeftExpression(oLeft);
                 bin.setRightExpression(oRight);
@@ -339,104 +400,52 @@ public class BinaryExpressionTransformer {
         return null;
     }
 
-    private static boolean hasCharType(PropertyExpression pe) {
-        ClassNode inferredType = pe.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
-        return inferredType != null && ClassHelper.Character_TYPE.equals(ClassHelper.getWrapper(inferredType));
+    //--------------------------------------------------------------------------
+
+    private ClassNode findType(final Expression e) {
+        return staticCompilationTransformer.getTypeChooser().resolveType(e, staticCompilationTransformer.getClassNode());
     }
 
-    private static Character tryCharConstant(final Expression expr) {
-        if (expr instanceof ConstantExpression && ClassHelper.STRING_TYPE.equals(expr.getType())) {
-            String value = (String) ((ConstantExpression) expr).getValue();
-            if (value != null && value.length() == 1) {
-                return value.charAt(0);
-            }
-        }
-        return null;
+    private boolean hasCharType(final Expression e) {
+        ClassNode inferredType = e.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE); //TODO:findType(e);
+        return inferredType != null && ClassHelper.getWrapper(inferredType).equals(ClassHelper.Character_TYPE);
     }
 
-    private static Expression transformDeclarationExpression(final BinaryExpression bin) {
-        Expression leftExpression = bin.getLeftExpression();
-        if (leftExpression instanceof VariableExpression) {
-            if (ClassHelper.char_TYPE.equals(((VariableExpression) leftExpression).getOriginType())) {
-                Expression rightExpression = bin.getRightExpression();
-                Character c = tryCharConstant(rightExpression);
-                if (c != null) {
-                    Expression ce = constX(c, true);
-                    ce.setSourcePosition(rightExpression);
-                    bin.setRightExpression(ce);
-                    return bin;
-                }
+    private static Character tryCharConstant(final Expression e) {
+        if (e instanceof ConstantExpression && ClassHelper.STRING_TYPE.equals(e.getType())) {
+            String value = (String) ((ConstantExpression) e).getValue();
+            if (value != null && value.length() == 1) {
+                return value.charAt(0);
             }
         }
         return null;
     }
 
-    private static DeclarationExpression optimizeConstantInitialization(final BinaryExpression originalDeclaration, final Token operation, final ConstantExpression constant, final Expression leftExpression, final ClassNode declarationType) {
-        Expression cexp = constX(convertConstant((Number) constant.getValue(), ClassHelper.getWrapper(declarationType)), true);
-        cexp.setType(declarationType);
-        cexp.setSourcePosition(constant);
-        DeclarationExpression result = new DeclarationExpression(
-                leftExpression,
-                operation,
-                cexp
-        );
-        result.setSourcePosition(originalDeclaration);
-        result.copyNodeMetaData(originalDeclaration);
-        return result;
-    }
-
     private static Object convertConstant(final Number source, final ClassNode target) {
-        if (isWrapperByte(target)) {
+        if (ClassHelper.isWrapperByte(target)) {
             return source.byteValue();
         }
-        if (isWrapperShort(target)) {
+        if (ClassHelper.isWrapperShort(target)) {
             return source.shortValue();
         }
-        if (isWrapperInteger(target)) {
+        if (ClassHelper.isWrapperInteger(target)) {
             return source.intValue();
         }
-        if (isWrapperLong(target)) {
+        if (ClassHelper.isWrapperLong(target)) {
             return source.longValue();
         }
-        if (isWrapperFloat(target)) {
+        if (ClassHelper.isWrapperFloat(target)) {
             return source.floatValue();
         }
-        if (isWrapperDouble(target)) {
+        if (ClassHelper.isWrapperDouble(target)) {
             return source.doubleValue();
         }
-        if (isBigIntegerType(target)) {
+        if (ClassHelper.isBigIntegerType(target)) {
             return DefaultGroovyMethods.asType(source, BigInteger.class);
         }
-        if (isBigDecimalType(target)) {
+        if (ClassHelper.isBigDecimalType(target)) {
             return DefaultGroovyMethods.asType(source, BigDecimal.class);
         }
-        throw new IllegalArgumentException("Unsupported conversion");
-    }
-
-    /**
-     * Adapter for {@link StaticPropertyAccessHelper#transformToSetterCall}.
-     */
-    private static Expression transformAssignmentToSetterCall(
-            final Expression receiver,
-            final MethodNode setterMethod,
-            final Expression valueExpression,
-            final boolean implicitThis,
-            final boolean safeNavigation,
-            final Expression nameExpression,
-            final Expression binaryExpression) {
-        // expression that will transfer assignment and name positions
-        Expression pos = new PropertyExpression(null, nameExpression);
-        pos.setSourcePosition(binaryExpression);
-
-        return StaticPropertyAccessHelper.transformToSetterCall(
-                receiver,
-                setterMethod,
-                valueExpression,
-                implicitThis,
-                safeNavigation,
-                false, // spreadSafe
-                true, // TODO: replace with a proper test whether a return value is required or not
-                pos
-        );
+        throw new IllegalArgumentException("Unsupported numerical conversion");
     }
 }

[groovy] 02/02: GROOVY-10377: SC: optimize `x === null` and `x !== null`

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit bec691dbcc15cd7df4691fa149e6d57212c883d1
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Nov 20 12:07:15 2021 -0600

    GROOVY-10377: SC: optimize `x === null` and `x !== null`
---
 .../groovy/transform/sc/transformers/BinaryExpressionTransformer.java   | 2 ++
 1 file changed, 2 insertions(+)

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 8ec2ec7..2e609cd 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
@@ -114,8 +114,10 @@ public class BinaryExpressionTransformer {
           case Types.KEYWORD_IN:
             return transformInOperation(bin);
           case Types.COMPARE_EQUAL:
+          case Types.COMPARE_IDENTICAL:
             equal = true; //fallthrough
           case Types.COMPARE_NOT_EQUAL:
+          case Types.COMPARE_NOT_IDENTICAL:
             expr = transformEqualityComparison(bin, equal);
             if (expr != null) return expr;
         }