purescript-lua
purescript-lua copied to clipboard
Undefined variable in compiled code
A compilation in some cases may produce invalid lua that is fails at runtime. I have not figured out what exactly causes this behavior but succeeded to catch some example.
Example
I tried my best to minimize it but can't find a way to make it smaller.
module Example (baz) where
import Effect (Effect)
import Prelude (class Monad, Unit, bind, discard, pure, unit)
baz ∷ Effect Unit
baz = bar (pure unit)
bar ∷ ∀ f. Monad f ⇒ f Unit → f Unit
bar f = do
f
_ ← pure [ foo f ]
pure unit
foo ∷ ∀ f. Monad f ⇒ f Unit → f Unit
foo fn1 = do
_ ← fn1
fn1
fn1
fn1
Run via:
pslua --foreign-path . --ps-output output--lua-output-file out.lua --entry Example
Generated code
...
return {
baz = (function()
return function(f)
local Bind1 = M.Effect_monadEffect.Bind1()
local pure = M.Control_Applicative_pure(M.Effect_monadEffect.Applicative0())
return M.Example_discard(Bind1)(f)(function()
return M.Control_Bind_bind(Bind1)(pure({
[1] = (function()
return function(fn1)
local discard1 = M.Example_discard(Bind11) -- Bind11 is not in scope
return M.Control_Bind_bind(M.Effect_monadEffect.Bind1())(fn1)(function( )
return discard1(fn1)(function()
return discard1(fn1)(function() return fn1 end)
end)
end)
end
end)()(f)
}))(function() return pure(M.Data_Unit_foreign.unit) end)
end)
end
end)()(M.Control_Applicative_pure(M.Effect_applicativeEffect)(M.Data_Unit_foreign.unit))
}
Version
pslua: 684b8d2c32524394c51577636a258e71d00cfefb (actual master)
Thanks for putting effort in reproduction and bug-reporting!
Unfortunately and strangely, I am not able to reproduce the failure as a golden test, check this PR out.
I have also tried running this command from test/ps dir:
yura/issue-37-repro cabal run pslua -- --foreign-path . --ps-output output --entry Golden.Issue37.Test
PS Lua: compiling ...
Wrote linked modules to /home/yura/projects/purescript/purescript-lua/purescript-lua/test/ps/main.lua
and it produces main.lua:
local function PSLUA_runtime_lazy(name)
return function(init)
return function()
local state = 0
local val = nil
if state == 2 then
return val
else
if state == 1 then
return error(name .. " was needed before it finished initializing")
else
state = 1
val = init()
state = 2
return val
end
end
end
end
end
local M = {}
M.Data_Unit_foreign = { unit = {} }
M.Effect_foreign = {
pureE = function(a)
return function()
return a
end
end,
bindE = function(a)
return function(f)
return function()
return f(a())()
end
end
end
}
M.Control_Applicative_pure = function(dict) return dict.pure end
M.Control_Bind_bind = function(dict) return dict.bind end
M.Effect_monadEffect = {
Applicative0 = function() return M.Effect_applicativeEffect end,
Bind1 = function() return M.Effect_bindEffect end
}
M.Effect_bindEffect = {
bind = M.Effect_foreign.bindE,
Apply0 = function() return M.Effect_Lazy_applyEffect(0) end
}
M.Effect_applicativeEffect = {
pure = M.Effect_foreign.pureE,
Apply0 = function() return M.Effect_Lazy_applyEffect(0) end
}
M.Effect_Lazy_functorEffect = PSLUA_runtime_lazy("functorEffect")(function()
return {
map = function(f)
return (M.Effect_applicativeEffect.Apply0()).apply(M.Control_Applicative_pure(M.Effect_applicativeEffect)(f))
end
}
end)
M.Effect_Lazy_applyEffect = PSLUA_runtime_lazy("applyEffect")(function()
return {
apply = (function()
return function(f)
local bind = M.Control_Bind_bind(M.Effect_monadEffect.Bind1())
return function(a)
return bind(f)(function(fPrime)
return bind(a)(function(aPrime)
return M.Control_Applicative_pure(M.Effect_monadEffect.Applicative0())(fPrime(aPrime))
end)
end)
end
end
end)(),
Functor0 = function() return M.Effect_Lazy_functorEffect(0) end
}
end)
M.Golden_Issue37_Test_discard = M.Control_Bind_bind
M.Golden_Issue37_Test_foo = function(dictMonad)
return function(fn1)
local Bind1 = dictMonad.Bind1()
local discard1 = M.Golden_Issue37_Test_discard(Bind1)
return M.Control_Bind_bind(dictMonad.Bind1())(fn1)(function()
return discard1(fn1)(function()
return discard1(fn1)(function() return fn1 end)
end)
end)
end
end
M.Golden_Issue37_Test_bar = function(dictMonad)
return function(f)
local Bind1 = dictMonad.Bind1()
local pure = M.Control_Applicative_pure(dictMonad.Applicative0())
return M.Golden_Issue37_Test_discard(Bind1)(f)(function()
return M.Control_Bind_bind(Bind1)(pure({
[1] = M.Golden_Issue37_Test_foo(dictMonad)(f)
}))(function() return pure(M.Data_Unit_foreign.unit) end)
end)
end
end
return {
baz = M.Golden_Issue37_Test_bar(M.Effect_monadEffect)(M.Control_Applicative_pure(M.Effect_applicativeEffect)(M.Data_Unit_foreign.unit)),
bar = M.Golden_Issue37_Test_bar,
foo = M.Golden_Issue37_Test_foo
}
Am I missing something?
@Unisay thanks for the quick response!
It seems to be crucial to export explicitly. This makes the bug go for me:
- module Example (baz) where
+ module Example where
So I think this change will help to reproduce it:
- module Golden.Issue37.Test where
+ module Golden.Issue37.Test (baz) where