Skip to content

Commit 93b666b

Browse files
RomanSpectorclaude
andcommitted
Fix type inference for bitwise operators on integer variables
Bitwise operators (<<, >>, &, |, ~) on integer-typed variables returned 'unknown' instead of 'integer'. For example: local a = 1 << 20 -- integer = 1048576 (OK) local b = a << 1 -- was: unknown, now: integer = 2097152 Two fixes: - operator.lua: add integer type fallback for bitwise ops when operands are integer-typed but not literal constants (matching existing behavior for +, -, *, % operators) - value.lua: vm.getInteger now traces through getlocal to the local definition's value when the compiled node doesn't preserve the literal, enabling constant folding for chained expressions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9d320a5 commit 93b666b

File tree

4 files changed

+34
-1
lines changed

4 files changed

+34
-1
lines changed

changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<!-- Add all new changes here. They will be moved under a version at release -->
55
* `CHG` Modified the `ResolveRequire` function to pass the source URI as a third argument.
66
* `CHG` Improved the output of test failures during development
7+
* `FIX` Fix type inference for bitwise operators (`<<`, `>>`, `&`, `|`, `~`) on integer variables
8+
* `FIX` Fix constant value computation for chained bitwise expressions in hover tooltips
79

810
## 3.17.1
911
`2026-01-20`

script/vm/operator.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,15 @@ vm.binarySwitch = util.switch()
267267
end
268268
if node then
269269
vm.setNode(source, node)
270+
return
271+
end
272+
-- Bitwise ops on integers always produce integer
273+
local uri = guide.getUri(source)
274+
local infer1 = vm.getInfer(source[1])
275+
local infer2 = vm.getInfer(source[2])
276+
if infer1:hasType(uri, 'integer')
277+
and infer2:hasType(uri, 'integer') then
278+
vm.setNode(source, vm.declareGlobal('type', 'integer'))
270279
end
271280
end
272281
end)

script/vm/value.lua

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ function vm.getInteger(v)
118118
end
119119
local node = vm.compileNode(v)
120120
local result
121+
local hasNonInteger = false
121122
for n in node:eachObject() do
122123
if n.type == 'integer' then
123124
if result then
@@ -135,7 +136,18 @@ function vm.getInteger(v)
135136
end
136137
elseif n.type ~= 'local'
137138
and n.type ~= 'global' then
138-
return nil
139+
hasNonInteger = true
140+
end
141+
end
142+
if hasNonInteger and not result then
143+
result = nil
144+
end
145+
-- If value not found via compiled node, try the local's
146+
-- definition value directly (tracer may not preserve literals)
147+
if result == nil and v.type == 'getlocal' then
148+
local loc = v.node
149+
if loc and loc.value then
150+
return vm.getInteger(loc.value)
139151
end
140152
end
141153
return result

test/type_inference/common.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,16 @@ TEST 'integer' [[
146146
<?x?> = 1 << 2
147147
]]
148148

149+
TEST 'integer' [[
150+
local a = 1 << 20
151+
local <?b?> = a << 1
152+
]]
153+
154+
TEST 'integer' [[
155+
local a = 1 << 20
156+
local <?b?> = (a << 1) - 1
157+
]]
158+
149159
TEST 'unknown' [[
150160
<?x?> = a .. b
151161
]]

0 commit comments

Comments
 (0)