Skip to content

Commit

Permalink
Merge pull request #96 from arichard4/compound-bugfix
Browse files Browse the repository at this point in the history
Compound bugfix
  • Loading branch information
arichard4 committed Jun 5, 2023
2 parents c697e32 + a8de4bc commit f7712ed
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 27 deletions.
8 changes: 4 additions & 4 deletions spec/cli_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,8 @@ Total: 5 warnings / 0 errors in 1 file
spec/samples/compound_operators.lua:2:1: assignment uses compound operator +=
spec/samples/compound_operators.lua:3:1: assignment uses compound operator -=
spec/samples/compound_operators.lua:4:1: assignment uses compound operator *=
spec/samples/compound_operators.lua:5:1: assignment uses compound operator /=
spec/samples/compound_operators.lua:5:2: assignment uses compound operator /=
spec/samples/compound_operators.lua:10:1: assignment uses compound operator *=
Total: 0 warnings / 4 errors in 1 file
]], get_output "spec/samples/compound_operators.lua --no-config")
Expand All @@ -311,8 +311,8 @@ Total: 0 warnings / 4 errors in 1 file
assert.equal([[Checking spec/samples/compound_operators.lua 3 errors
spec/samples/compound_operators.lua:3:1: assignment uses compound operator -=
spec/samples/compound_operators.lua:4:1: assignment uses compound operator *=
spec/samples/compound_operators.lua:5:1: assignment uses compound operator /=
spec/samples/compound_operators.lua:5:2: assignment uses compound operator /=
spec/samples/compound_operators.lua:10:1: assignment uses compound operator *=
Total: 0 warnings / 3 errors in 1 file
]], get_output "spec/samples/compound_operators.lua --no-config --operators +=")
Expand Down
11 changes: 8 additions & 3 deletions spec/samples/compound_operators.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
local i = 0
i += 10
i -= 5
i *= 2
i /= 5
return i
local function func()
i /= 5
end
func()
local t = {}
t.a = i
t.a *= 2
return t
2 changes: 1 addition & 1 deletion src/luacheck/parser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ local function parse_expression_statement(state)
parse_error(state, "compound assignment not allowed on tuples near " .. compound_operator .. "=")
end

return new_inner_node(start_range, rhs[1], "OpSet", {compound_operator, lhs[1], rhs[1]})
return new_inner_node(start_range, rhs[1], "OpSet", {lhs, rhs, compound_operator})
else
-- This is an assignment in the form `lhs = rhs`.
check_and_skip_token(state, "=")
Expand Down
2 changes: 1 addition & 1 deletion src/luacheck/stages/detect_compound_operators.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ local reverse_compound_operators = {
}

local function check_node(chstate, node)
local operator = reverse_compound_operators[node[1]]
local operator = reverse_compound_operators[node[3]]
chstate:warn_range("033", node, {operator = operator})
end

Expand Down
2 changes: 1 addition & 1 deletion src/luacheck/stages/detect_globals.lua
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ local function detect_globals_in_line(chstate, line)
if item.rhs then
detect_in_nodes(chstate, item, item.rhs, is_top_line)
end
elseif item.tag == "Set" then
elseif item.tag == "Set" or item.tag == "OpSet" then
detect_in_nodes(chstate, item, item.lhs, is_top_line, true)
detect_in_nodes(chstate, item, item.rhs, is_top_line)
end
Expand Down
29 changes: 17 additions & 12 deletions src/luacheck/stages/linearize.lua
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ local function new_opset_item(node)
return {
tag = "OpSet",
node = node,
lhs = node[2],
rhs = node[3],
lhs = node[1],
rhs = node[2],
accesses = {},
mutations = {},
used_values = {},
Expand Down Expand Up @@ -530,18 +530,19 @@ end

function LinState:emit_stmt_OpSet(node)
local item = new_opset_item(node)
self:scan_expr(item, node[3])
self:scan_exprs(item, node[2])

local lhs = node[2]
if lhs.tag == "Id" then
local var = self:check_var(lhs)
for _, expr in ipairs(node[1]) do
if expr.tag == "Id" then
local var = self:check_var(expr)

if var then
self:register_upvalue_action(item, var, "set_upvalues")
if var then
self:register_upvalue_action(item, var, "set_upvalues")
end
else
assert(expr.tag == "Index")
self:scan_lhs_index(item, expr)
end
else
assert(lhs.tag == "Index")
self:scan_lhs_index(item, lhs)
end

self:emit(item)
Expand Down Expand Up @@ -650,7 +651,7 @@ function LinState:register_set_variables()
local line = self.lines.top

for _, item in ipairs(line.items) do
if item.tag == "Local" or item.tag == "Set" then
if item.tag == "Local" or item.tag == "Set" or item.tag == "OpSet" then
item.set_variables = {}

local is_init = item.tag == "Local"
Expand All @@ -674,6 +675,10 @@ function LinState:register_set_variables()
local value

if node.var then
-- OpSet also accesses
if item.tag == "OpSet" then
self:mark_access(item, node)
end
value = new_value(node, item.rhs and item.rhs[i] or unpacking_item, item, is_init)
item.set_variables[node.var] = value
table.insert(node.var.values, value)
Expand Down
11 changes: 8 additions & 3 deletions src/luacheck/stages/resolve_locals.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,24 @@ local function contains_call(node)
end

local function is_circular_reference(item, var)
-- OpSet is circular by definition
if not (item.tag == "Set" or item.tag == "Local") then
return false
end

-- No support for matching multiple assignment to the specific assignment
if not (item.tag == "Set" or item.tag == "Local" or item.tag == "OpSet") then
if not item.lhs or #item.lhs ~= 1 or not item.rhs or #item.rhs ~= 1 then
return false
end

-- Case t[t.function()] = t.func()
-- Functions can have side-effects, so this isn't purely circular
local right_assignment = item.tag == "OpSet" and item.rhs or item.rhs[1]
local right_assignment = item.rhs[1]
if contains_call(right_assignment) then
return false
end

local left_assignment = item.tag == "OpSet" and item.lhs or item.lhs[1]
local left_assignment = item.lhs[1]
if contains_call(left_assignment) then
return false
end
Expand Down
4 changes: 2 additions & 2 deletions src/luacheck/stages/unwrap_parens.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ local function handle_nodes(chstate, nodes, list_start)
if node[2] then
handle_nodes(chstate, node[2])
end
elseif tag == "Set" then
elseif tag == "Set" or tag == "OpSet" then
handle_nodes(chstate, node[1])
handle_nodes(chstate, node[2], 1)
else
Expand All @@ -67,7 +67,7 @@ local function handle_nodes(chstate, nodes, list_start)

-- warn that not (x == y) can become x ~= y
if tag == "Op" and node[1] == "not" and node[2].tag == "Op" and relational_operators[node[2][1]] then
chstate:warn_range("581", node, {
chstate:warn_range("581", node, {
operator = relational_operators[node[2][1]],
replacement_operator = replacements[node[2][1]]
})
Expand Down

0 comments on commit f7712ed

Please sign in to comment.