tl icon indicating copy to clipboard operation
tl copied to clipboard

Lua 5.5 - for loop variables

Open catwell opened this issue 2 weeks ago • 1 comments

In the current version of Teal this is valid:

local t: {integer: integer} = { [2] = 4}
for k, v in pairs(t) do
  k = k * 2
  assert(k == v)
end

This will warn:

local t: {integer: integer} = { [2] = 4}
for k, v in pairs(t) do
  local k = k * 2
  assert(k == v)
end
foo.tl:3:9: variable shadows previous declaration of 'k' (originally declared at 2:5)

In Lua 5.5 the first snippet is invalid and the second one will become a common idiom as it has been suggested by Roberto.

For an example of a code base needing this kind of change see https://github.com/luarocks/luarocks/pull/1844

How should Teal deal with this change?

catwell avatar Dec 07 '25 12:12 catwell

I wonder if Teal should have a <shadow> annotation to allow variable shadowing, they're useful sometimes.

(Also, multi annotation, like <const, shadow>)

Andre-LA avatar Dec 07 '25 14:12 Andre-LA

Good questions. In Rust, for example, variable shadowing is super common, when extracting values from Options, etc. Given a statically-typed language, shadowing a variable is less often a mistake (because when it's a mistake they often have different types and the compiler catches misuses). Unlike Rust, Teal does (a little bit of) flow typing, so there ought to be less of that if let Some(foo) = foo shadowing that you see in Rust.

One simple option would be to lift Lua 5.5's restriction, and just translate for k, v in exp do block end to for k, v in exp do local k = k; block end (and we could do that efficiently, i.e., only when needed). That would produce Lua 5.3 semantics, if I'm not mistaken. In the 5.3 manual, the semantics of generic for state that writing to the control variable doesn't modify the loop:

https://www.lua.org/manual/5.3/manual.html#3.3.5

A for statement like
     for var_1, ···, var_n in explist do block end

is equivalent to the code:

     do
       local f, s, var = explist
       while true do
         local var_1, ···, var_n = f(s, var)
         if var_1 == nil then break end
         var = var_1
         block
       end
     end

The Lua 5.4 mysteriously says "You should not change the value of the control variable during the loop" but doesn't specify what happens. The 5.3 manual specification above seems to show that assigning to var_1 will not affect the internal variable var which actually controls the loop.

hishamhm avatar Dec 19 '25 19:12 hishamhm