Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

swapping values does not work #92

Open
khvzak opened this issue Sep 2, 2024 · 1 comment
Open

swapping values does not work #92

khvzak opened this issue Sep 2, 2024 · 1 comment

Comments

@khvzak
Copy link

khvzak commented Sep 2, 2024

The following lua script:

local t = {1, 2}
t[1], t[2] = t[2], t[1]
assert(table.concat(t, ',') == '2,1')

fails in latest piccolo fcbaabc

the table contains 2,2 instead of 2,1

@Aeledfyr
Copy link
Contributor

https://www.lua.org/manual/5.4/manual.html#3.3.3

If a variable is both assigned and read inside a multiple assignment, Lua ensures that all reads get the value of the variable before the assignment.
Note that this guarantee covers only accesses syntactically inside the assignment statement. If a function or a metamethod called during the assignment changes the value of a variable, Lua gives no guarantees about the order of that access.

It looks like the issue is in Compiler::assignment_statement, which currently generates a sequence of assignments, interleaving the evaluation and assignment. The simple fix would be to evaluate the RHS expressions into temporaries before evaluating the assignments, but handling varargs expressions will be more complex. (In addition, this relies on optimization passes to remove the unnecessary register moves.)

The issue is not limited to table assignments, as it also occurs with locals:

local x, y = 1, 2
x, y = y, x
print(x, y)    -- 2, 2

Bytecode:

0: OpCode(LoadConstant { dest: RegisterIndex(0), constant: ConstantIndex16(0) })   # x = 1
1: OpCode(LoadConstant { dest: RegisterIndex(1), constant: ConstantIndex16(1) })   # y = 2
2: OpCode(Move { dest: RegisterIndex(0), source: RegisterIndex(1) })  # x = y
3: OpCode(Move { dest: RegisterIndex(2), source: RegisterIndex(0) })  # temp = x
4: OpCode(Move { dest: RegisterIndex(1), source: RegisterIndex(2) })  # y = temp

In PRLua, the evaluation order appears to be left-to-right for the values, and then right-to-left for the assignments; logging the operations in the following code:

t[4], t[5], t[6] = t[2], t[1], nil
index	2
index	1
newindex	6	nil
newindex	5	1
newindex	4	2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants