7167125: Two variables after the same operation in a inner class return different results

Fri, 08 Feb 2013 09:21:19 +0000

author
vromero
date
Fri, 08 Feb 2013 09:21:19 +0000
changeset 1557
017e8bdd440f
parent 1556
b1deb90d2e37
child 1558
60caf53b98e2

7167125: Two variables after the same operation in a inner class return different results
Reviewed-by: jjg, mcimadamore

src/share/classes/com/sun/tools/javac/comp/Lower.java file | annotate | diff | comparison | revisions
test/tools/javac/7167125/DiffResultAfterSameOperationInnerClasses.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Feb 08 09:15:27 2013 +0000
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Feb 08 09:21:19 2013 +0000
     1.3 @@ -3066,55 +3066,38 @@
     1.4      }
     1.5  
     1.6      public void visitAssignop(final JCAssignOp tree) {
     1.7 -        if (!tree.lhs.type.isPrimitive() &&
     1.8 -            tree.operator.type.getReturnType().isPrimitive()) {
     1.9 -            // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
    1.10 -            // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
    1.11 -            // (but without recomputing x)
    1.12 -            JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() {
    1.13 -                    public JCTree build(final JCTree lhs) {
    1.14 -                        JCTree.Tag newTag = tree.getTag().noAssignOp();
    1.15 -                        // Erasure (TransTypes) can change the type of
    1.16 -                        // tree.lhs.  However, we can still get the
    1.17 -                        // unerased type of tree.lhs as it is stored
    1.18 -                        // in tree.type in Attr.
    1.19 -                        Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
    1.20 -                                                                      newTag,
    1.21 -                                                                      attrEnv,
    1.22 -                                                                      tree.type,
    1.23 -                                                                      tree.rhs.type);
    1.24 -                        JCExpression expr = (JCExpression)lhs;
    1.25 -                        if (expr.type != tree.type)
    1.26 -                            expr = make.TypeCast(tree.type, expr);
    1.27 -                        JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
    1.28 -                        opResult.operator = newOperator;
    1.29 -                        opResult.type = newOperator.type.getReturnType();
    1.30 -                        JCTypeCast newRhs = make.TypeCast(types.unboxedType(tree.type),
    1.31 -                                                          opResult);
    1.32 -                        return make.Assign((JCExpression)lhs, newRhs).setType(tree.type);
    1.33 -                    }
    1.34 -                });
    1.35 -            result = translate(newTree);
    1.36 -            return;
    1.37 -        }
    1.38 -        tree.lhs = translate(tree.lhs, tree);
    1.39 -        tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
    1.40 -
    1.41 -        // If translated left hand side is an Apply, we are
    1.42 -        // seeing an access method invocation. In this case, append
    1.43 -        // right hand side as last argument of the access method.
    1.44 -        if (tree.lhs.hasTag(APPLY)) {
    1.45 -            JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
    1.46 -            // if operation is a += on strings,
    1.47 -            // make sure to convert argument to string
    1.48 -            JCExpression rhs = (((OperatorSymbol)tree.operator).opcode == string_add)
    1.49 -              ? makeString(tree.rhs)
    1.50 -              : tree.rhs;
    1.51 -            app.args = List.of(rhs).prependList(app.args);
    1.52 -            result = app;
    1.53 -        } else {
    1.54 -            result = tree;
    1.55 -        }
    1.56 +        final boolean boxingReq = !tree.lhs.type.isPrimitive() &&
    1.57 +            tree.operator.type.getReturnType().isPrimitive();
    1.58 +
    1.59 +        // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
    1.60 +        // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
    1.61 +        // (but without recomputing x)
    1.62 +        JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() {
    1.63 +                public JCTree build(final JCTree lhs) {
    1.64 +                    JCTree.Tag newTag = tree.getTag().noAssignOp();
    1.65 +                    // Erasure (TransTypes) can change the type of
    1.66 +                    // tree.lhs.  However, we can still get the
    1.67 +                    // unerased type of tree.lhs as it is stored
    1.68 +                    // in tree.type in Attr.
    1.69 +                    Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
    1.70 +                                                                  newTag,
    1.71 +                                                                  attrEnv,
    1.72 +                                                                  tree.type,
    1.73 +                                                                  tree.rhs.type);
    1.74 +                    JCExpression expr = (JCExpression)lhs;
    1.75 +                    if (expr.type != tree.type)
    1.76 +                        expr = make.TypeCast(tree.type, expr);
    1.77 +                    JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
    1.78 +                    opResult.operator = newOperator;
    1.79 +                    opResult.type = newOperator.type.getReturnType();
    1.80 +                    JCExpression newRhs = boxingReq ?
    1.81 +                            make.TypeCast(types.unboxedType(tree.type),
    1.82 +                                                      opResult) :
    1.83 +                            opResult;
    1.84 +                    return make.Assign((JCExpression)lhs, newRhs).setType(tree.type);
    1.85 +                }
    1.86 +            });
    1.87 +        result = translate(newTree);
    1.88      }
    1.89  
    1.90      /** Lower a tree of the form e++ or e-- where e is an object type */
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/tools/javac/7167125/DiffResultAfterSameOperationInnerClasses.java	Fri Feb 08 09:21:19 2013 +0000
     2.3 @@ -0,0 +1,61 @@
     2.4 +/*
     2.5 + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.
    2.11 + *
    2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.15 + * version 2 for more details (a copy is included in the LICENSE file that
    2.16 + * accompanied this code).
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License version
    2.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.21 + *
    2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.23 + * or visit www.oracle.com if you need additional information or have any
    2.24 + * questions.
    2.25 + */
    2.26 +
    2.27 +/*
    2.28 + * @test
    2.29 + * @bug 7167125
    2.30 + * @summary Two variables after the same operation in a inner class return
    2.31 + * different results
    2.32 + * @run main DiffResultAfterSameOperationInnerClasses
    2.33 + */
    2.34 +
    2.35 +public class DiffResultAfterSameOperationInnerClasses {
    2.36 +    public int i = 1;
    2.37 +    private int j = 1;
    2.38 +    public String s1 = "Hi, ";
    2.39 +    private String s2 = "Hi, ";
    2.40 +
    2.41 +    public static void main(String[] args) {
    2.42 +        InnerClass inner =
    2.43 +                new DiffResultAfterSameOperationInnerClasses().new InnerClass();
    2.44 +        if (!inner.test()) {
    2.45 +            throw new AssertionError("Different results after same calculation");
    2.46 +        }
    2.47 +    }
    2.48 +
    2.49 +    class InnerClass {
    2.50 +        public boolean test() {
    2.51 +            i += i += 1;
    2.52 +            j += j += 1;
    2.53 +
    2.54 +            s1 += s1 += "dude";
    2.55 +            s2 += s2 += "dude";
    2.56 +
    2.57 +            System.out.println("s1 = " + s1);
    2.58 +            System.out.println("s2 = " + s2);
    2.59 +
    2.60 +            return (i == j && i == 3 &&
    2.61 +                    s1.equals(s2) && s1.endsWith("Hi, Hi, dude"));
    2.62 +        }
    2.63 +    }
    2.64 +}

mercurial