Always shadow for-loop control variables in macro bodies - #1158
Conversation
|
Thank you for looking into this!
Thanks for disclosing. I am not keen on reviewing large AI-generated PRs (and their very long PR descriptions 😅 ), but I'm happy to review contributor code and answer questions.
This experimental macro feature still has some rough edges in the design. One of them is the Lua version that the macro bodies use: for now we assumed that 5.1 would be a usable "lowest common denominator". But if we start using the running Lua version, we risk that we'll start to have Teal modules including macros that only work in one specific Lua version. So I think we should keep targeting a single Lua version, effectively forcing a "Lua subset" for macro code, like we already do for the standard library availability inside macros. This would make macro code stable across target Lua VMs. For this specific problem of the |
|
Thanks for your detailed review! I was planning a backend framework for lua 5.3+ with Teal support. I think I understand what you mean, and what i should do now. I'll simplify the implementation and keep the macro code compatible with the Lua 5.1 subset. I'd appreciate one more chance to revise the PR based on your feedback. :) |
|
Pushed the rewrite. The macro body still targets the 5.1 subset; the shadow is (Force-pushed, so the history changed. :)) |
|
Hmm, I could see this continue to cause issues in the future, it is pretty clear that a blanket just "target lua 5.1" really won't work. I think we need to just target whatever Lua version that is running the macro. @hishamhm Thoughts? |
Problem
A macro whose body writes to the control variable of a
forloop fails tocompile when the compiler itself runs on Lua 5.5:
Numeric
forin a macro body fails the same way. The file works on 5.1, 5.3and 5.4 — 5.5 is the first version to make the control variable a constant.
Fix
Macro bodies keep targeting the 5.1 subset, as discussed. Instead of detecting
whether a body writes to a control variable,
macro_evalnow inserts theshadowing local into every
forin the macro body before parsing.local x = xis valid in every supported target and is a no-op when nothing writes to it, so
no detection is needed and the traversal from the previous revision is gone.
Both
forinandfornumare covered. 39 lines inteal/macro_eval.tl; noother source file is touched.
Tests
spec/lang/macro/for_control_var_spec.luaadds three cases: a numericforbody that writes its control variable, a generic
forbody that writes itscontrol variable, and a loop that never writes one. Each asserts the expanded
output rather than just that parsing succeeded, so the number of iterations the
macro body actually performed is encoded in the result.
Two of the three fail on Lua 5.5 without this change. On 5.1–5.4 they pass
either way, since those versions allow the assignment — which is also why CI
does not catch this today (
lua-version: ["5.4", "5.3", "5.2", "5.1", "luajit"]).make selfbuildis clean andbusted --suppress-pending spec/passes.Related
Numeric
forhas the same problem outside macros:lua_compat.adjust_codehasno
fornumcase, so ordinary Teal code that writes to a numeric loop variabletype checks and then emits invalid Lua on 5.5. That is the issue @bjornbm ran
into in #1159; it reproduces on master without this change and needs
lua_compatandvisitorschanges, so it is out of scope here. Happy to takeit separately if nobody else is on it.