[
https://issues.apache.org/jira/browse/GROOVY-12615?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18135636#comment-18135636
]
ASF GitHub Bot commented on GROOVY-12615:
-----------------------------------------
codeconsole opened a new pull request, #3141:
URL: https://github.com/apache/groovy/pull/3141
In trait code, a compound assignment nested in the right operand of another
compound assignment was not rewritten:
```groovy
trait T { int a = 1, b = 1; def m() { a += (b += 1); [a, b] } }
class C implements T {}
assert new C().m() == [3, 2]
```
This threw `ClassCastException: Cannot cast java.lang.Integer to
T$Trait$FieldHelper` in dynamic and type-checked code and `GroovyCastException`
under `@CompileStatic`, in 4.0.33, 5.0.8 and 6.0.0 too. Static trait fields
gave a `VerifyError` or a compile error. `a += (b++)` compiled and lost the
increment, although a postfix update of a trait field is otherwise rejected.
`NAryOperationRewriter` rewrites `x op= y` into `x = x op y` but built the
new expression from the untransformed right operand. It now transforms the
right operand first, so nested compound assignments are rewritten too and
nested prefix/postfix updates of trait fields get the usual compile error.
This touches only the right-operand line of
`NAryOperationRewriter.transformBinaryExpression`, so it merges without
conflict with #3130 (GROOVY-12603) and #3140 (GROOVY-12613), which change the
same method.
## Tests
`TraitASTTransformationTest.testNestedCompoundAssignmentOnTraitFields` and
`testNestedCompoundAssignmentOnStaticTraitFields` run in dynamic,
`@TypeChecked` and `@CompileStatic` modes. They cover properties, private and
public fields, static fields, `this.a += (this.b += 1)`, three levels of
nesting, `a = (b += 1)`, a compound inside a method argument and a local
target. `testPostfixInRightOperandOfCompoundAssignmentOnTraitFieldRejected`
checks that `a += (b++)` is rejected. All of them fail without the change.
`org.codehaus.groovy.transform.traitx.*`, `groovy.transform.stc.*`,
`org.codehaus.groovy.classgen.asm.sc.*`, `gls.*` and `groovy.ThisAndSuperTest`
pass. The Checkstyle and CodeNarc gates pass.
> Compound assignment to a trait field nested in the right operand of another
> compound assignment fails at run time
> -----------------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12615
> URL: https://issues.apache.org/jira/browse/GROOVY-12615
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 4.0.33, 5.0.8, 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> {code:groovy}
> trait T { int a = 1, b = 1; def m() { a += (b += 1); [a, b] } }
> class C implements T {}
> assert new C().m() == [3, 2]
> {code}
> Actual: dynamic and type-checked code throws {{java.lang.ClassCastException:
> Cannot cast java.lang.Integer to T$Trait$FieldHelper}}; with @CompileStatic
> it throws {{GroovyCastException: Cannot cast object '2' with class
> 'java.lang.Integer' to class 'T'}}. With static trait fields it throws a
> VerifyError (dynamic) or fails to compile (@CompileStatic). A postfix update
> in the same position, {{a += (b++)}}, compiles and silently loses the
> increment, although postfix updates of trait fields are a compile error
> everywhere else.
> Expected: [3, 2], and a postfix update there rejected with "Postfix
> expressions on trait fields/properties are not supported in traits."
> Cause: NAryOperationRewriter rewrites x op= y into x = x op y but reuses the
> right operand without transforming it, so a nested compound assignment to a
> trait field stays a compound assignment applied to the field helper call, and
> a nested postfix update is never checked.
> Seen in 4.0.33, 5.0.8 and 6.0.0.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)