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:09 UTC

[groovy] 01/02: refactor `BinaryExpressionTransformer`

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");
     }
 }