[ 
https://issues.apache.org/jira/browse/GROOVY-12619?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Scott Murphy Heiberg updated GROOVY-12619:
------------------------------------------
    Description: 
{code:groovy}
class Box { int v = 1 }
class C {
    int calls = 0
    Box box = new Box()
    Box obj() { calls++; box }
    def m() { obj().v += 2; [calls, box.v] }
    def n() { obj().v++; [calls, box.v] }
}
assert new C().m() == [1, 3]
assert new C().n() == [1, 2]
{code}
Actual: m() returns [2, 3] and n() returns [2, 2]. The receiver obj() is called 
once for the read of the property and again for the write. The same happens in 
dynamic Groovy, under @TypeChecked and under @CompileStatic. It also happens 
for prefix and postfix increment and decrement, attribute access ({{obj().@f += 
2}}), safe navigation ({{obj()?.v += 2}}), chains with a side-effecting getter, 
static properties reached through an instance, and extension properties such as 
File text. Under @CompileStatic, {{obj().d++}} on a BigDecimal property calls 
obj() three times.

Expected: the receiver is evaluated once, before the right-hand side, and 
reused for the read and the write. Subscripts already behave this way 
(GROOVY-12098).

Cause: the code generator evaluated the property expression once as an rvalue 
and once as the assignment target. The static compiler's rewrites to x.p = 
x.p.op(y) and to the extension setter reused the receiver expression on both 
sides. The elvis assignment form is GROOVY-12515.

Seen in 4.0.33, 5.0.8 and 6.0.0.

PR: https://github.com/apache/groovy/pull/3145

  was:
{code:groovy}
class Box { int v = 1 }
class C {
    int calls = 0
    Box box = new Box()
    Box obj() { calls++; box }
    def m() { obj().v += 2; [calls, box.v] }
    def n() { obj().v++; [calls, box.v] }
}
assert new C().m() == [1, 3]
assert new C().n() == [1, 2]
{code}
Actual: m() returns [2, 3] and n() returns [2, 2]. The receiver obj() is called 
once for the read of the property and again for the write. The same happens in 
dynamic Groovy, under @TypeChecked and under @CompileStatic. It also happens 
for prefix and postfix increment and decrement, attribute access ({{obj().@f += 
2}}), safe navigation ({{obj()?.v += 2}}), chains with a side-effecting getter, 
static properties reached through an instance, and extension properties such as 
File text. Under @CompileStatic, {{obj().d++}} on a BigDecimal property calls 
obj() three times.

Expected: the receiver is evaluated once, before the right-hand side, and 
reused for the read and the write. Subscripts already behave this way 
(GROOVY-12098).

Cause: the code generator evaluated the property expression once as an rvalue 
and once as the assignment target. The static compiler's rewrites to x.p = 
x.p.op(y) and to the extension setter reused the receiver expression on both 
sides. The elvis assignment form is GROOVY-12515.

Seen in 4.0.33, 5.0.8 and 6.0.0.


> Compound assignment and increment on a property evaluate the receiver 
> expression twice
> --------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12619
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12619
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 4.0.33, 5.0.8, 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> {code:groovy}
> class Box { int v = 1 }
> class C {
>     int calls = 0
>     Box box = new Box()
>     Box obj() { calls++; box }
>     def m() { obj().v += 2; [calls, box.v] }
>     def n() { obj().v++; [calls, box.v] }
> }
> assert new C().m() == [1, 3]
> assert new C().n() == [1, 2]
> {code}
> Actual: m() returns [2, 3] and n() returns [2, 2]. The receiver obj() is 
> called once for the read of the property and again for the write. The same 
> happens in dynamic Groovy, under @TypeChecked and under @CompileStatic. It 
> also happens for prefix and postfix increment and decrement, attribute access 
> ({{obj().@f += 2}}), safe navigation ({{obj()?.v += 2}}), chains with a 
> side-effecting getter, static properties reached through an instance, and 
> extension properties such as File text. Under @CompileStatic, {{obj().d++}} 
> on a BigDecimal property calls obj() three times.
> Expected: the receiver is evaluated once, before the right-hand side, and 
> reused for the read and the write. Subscripts already behave this way 
> (GROOVY-12098).
> Cause: the code generator evaluated the property expression once as an rvalue 
> and once as the assignment target. The static compiler's rewrites to x.p = 
> x.p.op(y) and to the extension setter reused the receiver expression on both 
> sides. The elvis assignment form is GROOVY-12515.
> Seen in 4.0.33, 5.0.8 and 6.0.0.
> PR: https://github.com/apache/groovy/pull/3145



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)
  • [jira] [Updated] (GROOVY-126... Scott Murphy Heiberg (Jira) via notifications

Reply via email to