Consider the following vim9script code:
vim9script
var Foo = true ? (x: number): number => x : (x: number): number => x
echo Foo(10)
(this returns 10 in Vim 9)
This is currently compiled into this Lua code:
local vim9 = require('_vim9script')
local M = {}
local Foo = nil
-- vim9script
Foo = vim9.ternary(true, function(x)
return x
end, function(x)
return x
end)
print(Foo(10))
return M
... which throws an error for me:
Error detected while processing /Users/joomy/work/vim9jit/ex/bug.vim:
line 3:
E5108: Error executing lua ./bug.lua:19: attempt to call local 'Foo' (a nil value)
stack traceback:
./bug.lua:19: in function 'autoload'
[string "luaeval()"]:1: in main chunk
(line 19 is the print(Foo(10)) line)
Given how ternary is implemented in _vim9script.lua, as long as the inputs to ternary are functions, they are called with no arguments:
|
M.ternary = function(cond, if_true, if_false) |
|
if cond then |
|
if type(if_true) == 'function' then |
|
return if_true() |
|
else |
|
return if_true |
|
end |
|
else |
|
if type(if_false) == 'function' then |
|
return if_false() |
|
else |
|
return if_false |
|
end |
|
end |
|
end |
And the "suspender" functions are only used if the branches of the ternary expressions have side effects:
|
impl Generate for Ternary { |
|
fn write_default(&self, state: &mut State, output: &mut Output) { |
|
let if_true = if expr_utils::has_possible_sideffects(&self.if_true) { |
|
format!("function() return {} end", self.if_true.gen(state)) |
|
} else { |
|
self.if_true.gen(state) |
|
}; |
|
|
|
let if_false = if expr_utils::has_possible_sideffects(&self.if_false) { |
|
format!("function() return {} end", self.if_false.gen(state)) |
|
} else { |
|
self.if_false.gen(state) |
|
}; |
|
|
|
output.write_lua(&format!( |
|
"vim9.ternary({}, {if_true}, {if_false})", |
|
self.cond.gen(state), |
|
)) |
|
} |
|
} |
and lambda expressions are considered not to have side effects:
|
Expression::Lambda(_) => false, |
But even without that, even an identifier can evaluate to a function, which will make type(if_true) == 'function' true in the ternary implementation in Lua. This identifier can come from outside, so you cannot determine whether a term has side effects syntactically.
The solution seems to be making ternary expression generation wrap the branches in function() return .. end all the time. (Lua doesn't seem to have lazy and/or either so that also doesn't work).
Consider the following vim9script code:
(this returns 10 in Vim 9)
This is currently compiled into this Lua code:
... which throws an error for me:
(line 19 is the
print(Foo(10))line)Given how
ternaryis implemented in_vim9script.lua, as long as the inputs to ternary are functions, they are called with no arguments:vim9jit/lua/_vim9script.lua
Lines 14 to 28 in af7d608
And the "suspender" functions are only used if the branches of the ternary expressions have side effects:
vim9jit/crates/vim9-gen/src/lib.rs
Lines 1275 to 1294 in af7d608
and lambda expressions are considered not to have side effects:
vim9jit/crates/vim9-gen/src/lib.rs
Line 1249 in af7d608
But even without that, even an identifier can evaluate to a function, which will make
type(if_true) == 'function'true in theternaryimplementation in Lua. This identifier can come from outside, so you cannot determine whether a term has side effects syntactically.The solution seems to be making ternary expression generation wrap the branches in
function() return .. endall the time. (Lua doesn't seem to have lazyand/oreither so that also doesn't work).