3064 result = tree; |
3064 result = tree; |
3065 } |
3065 } |
3066 } |
3066 } |
3067 |
3067 |
3068 public void visitAssignop(final JCAssignOp tree) { |
3068 public void visitAssignop(final JCAssignOp tree) { |
3069 if (!tree.lhs.type.isPrimitive() && |
3069 final boolean boxingReq = !tree.lhs.type.isPrimitive() && |
3070 tree.operator.type.getReturnType().isPrimitive()) { |
3070 tree.operator.type.getReturnType().isPrimitive(); |
3071 // boxing required; need to rewrite as x = (unbox typeof x)(x op y); |
3071 |
3072 // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y) |
3072 // boxing required; need to rewrite as x = (unbox typeof x)(x op y); |
3073 // (but without recomputing x) |
3073 // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y) |
3074 JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() { |
3074 // (but without recomputing x) |
3075 public JCTree build(final JCTree lhs) { |
3075 JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() { |
3076 JCTree.Tag newTag = tree.getTag().noAssignOp(); |
3076 public JCTree build(final JCTree lhs) { |
3077 // Erasure (TransTypes) can change the type of |
3077 JCTree.Tag newTag = tree.getTag().noAssignOp(); |
3078 // tree.lhs. However, we can still get the |
3078 // Erasure (TransTypes) can change the type of |
3079 // unerased type of tree.lhs as it is stored |
3079 // tree.lhs. However, we can still get the |
3080 // in tree.type in Attr. |
3080 // unerased type of tree.lhs as it is stored |
3081 Symbol newOperator = rs.resolveBinaryOperator(tree.pos(), |
3081 // in tree.type in Attr. |
3082 newTag, |
3082 Symbol newOperator = rs.resolveBinaryOperator(tree.pos(), |
3083 attrEnv, |
3083 newTag, |
3084 tree.type, |
3084 attrEnv, |
3085 tree.rhs.type); |
3085 tree.type, |
3086 JCExpression expr = (JCExpression)lhs; |
3086 tree.rhs.type); |
3087 if (expr.type != tree.type) |
3087 JCExpression expr = (JCExpression)lhs; |
3088 expr = make.TypeCast(tree.type, expr); |
3088 if (expr.type != tree.type) |
3089 JCBinary opResult = make.Binary(newTag, expr, tree.rhs); |
3089 expr = make.TypeCast(tree.type, expr); |
3090 opResult.operator = newOperator; |
3090 JCBinary opResult = make.Binary(newTag, expr, tree.rhs); |
3091 opResult.type = newOperator.type.getReturnType(); |
3091 opResult.operator = newOperator; |
3092 JCTypeCast newRhs = make.TypeCast(types.unboxedType(tree.type), |
3092 opResult.type = newOperator.type.getReturnType(); |
3093 opResult); |
3093 JCExpression newRhs = boxingReq ? |
3094 return make.Assign((JCExpression)lhs, newRhs).setType(tree.type); |
3094 make.TypeCast(types.unboxedType(tree.type), |
3095 } |
3095 opResult) : |
3096 }); |
3096 opResult; |
3097 result = translate(newTree); |
3097 return make.Assign((JCExpression)lhs, newRhs).setType(tree.type); |
3098 return; |
3098 } |
3099 } |
3099 }); |
3100 tree.lhs = translate(tree.lhs, tree); |
3100 result = translate(newTree); |
3101 tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head); |
|
3102 |
|
3103 // If translated left hand side is an Apply, we are |
|
3104 // seeing an access method invocation. In this case, append |
|
3105 // right hand side as last argument of the access method. |
|
3106 if (tree.lhs.hasTag(APPLY)) { |
|
3107 JCMethodInvocation app = (JCMethodInvocation)tree.lhs; |
|
3108 // if operation is a += on strings, |
|
3109 // make sure to convert argument to string |
|
3110 JCExpression rhs = (((OperatorSymbol)tree.operator).opcode == string_add) |
|
3111 ? makeString(tree.rhs) |
|
3112 : tree.rhs; |
|
3113 app.args = List.of(rhs).prependList(app.args); |
|
3114 result = app; |
|
3115 } else { |
|
3116 result = tree; |
|
3117 } |
|
3118 } |
3101 } |
3119 |
3102 |
3120 /** Lower a tree of the form e++ or e-- where e is an object type */ |
3103 /** Lower a tree of the form e++ or e-- where e is an object type */ |
3121 JCTree lowerBoxedPostop(final JCUnary tree) { |
3104 JCTree lowerBoxedPostop(final JCUnary tree) { |
3122 // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2 |
3105 // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2 |