lovejs errors with "attempt to yield across metamethod/C-call boundary" when you try to yield in a coroutine inside xpcall. love2d native (11.3) runs the same code without issue. I'm not sure why the behaviour is different and this use case doesn't seem super common, but it tripped me up so I thought I'd post an issue.
I ran into this because I was using batteries.async which wraps all coroutines in xpcall to capture the immediate callstack for errors instead of where the one at coroutine.resume.
An example of the issue (tested on 9e07fa0b1c50bb1c1132a843b5ede661f141ed53 using pfirsich/makelove to package compat):
local color = {
purple = {0.25, 0.09, 0.28, 1},
white = {0.89, 0.91, 0.90, 1},
}
local ball = {
x = 100,
y = 100,
r = 20,
}
local input = {
coro = 'v',
}
local S = {}
local function coro_fn()
S.async_running = true
for i=1,100 do
color.purple[4] = i / 100
coroutine.yield()
color.purple[4] = ten + 1
end
color.purple[4] = 1
S.async_running = false
return true
end
local function safety_wrap(f)
return function(...)
local results = {xpcall(f, debug.traceback, ...)}
local success = table.remove(results, 1)
if not success then
error(table.remove(results, 1))
end
return unpack(results)
end
end
function love.update(dt)
if S.coro then
local success, result = coroutine.resume(S.coro)
if not success then
error(result)
elseif result then
print("coroutine cleared")
S.coro = nil
end
end
if not S.async_running then
if love.keyboard.isDown(input.coro) then
S.coro = coroutine.create((coro_fn))
print("coroutine started")
end
end
end
function love.draw()
love.graphics.setColor(color.purple)
love.graphics.circle("fill", ball.x, ball.y, ball.r)
love.graphics.setColor(color.white)
love.graphics.printf("coro running: ".. tostring(S.coro or "no"), 5,5, 2000, "left")
local str = "To start a coroutine:"
for key,val in pairs(input) do
str = ("%s\n%s: %s"):format(str, key, val)
end
love.graphics.printf(str, 5,25, 200, "left")
end
Pressing v to start the coroutine in lovejs produces this error:
Error: main.lua:47: main.lua:37: attempt to yield across metamethod/C-call boundary
love.js:9 stack traceback:
love.js:9 [C]: in function 'yield'
love.js:9 main.lua:26: in function <main.lua:22>
love.js:9 [C]: in function 'xpcall'
love.js:9 main.lua:34: in function <main.lua:33>
love.js:9 stack traceback:
love.js:9 [string "boot.lua"]:777: in function <[string "boot.lua"]:773>
love.js:9 [C]: in function 'error'
love.js:9 main.lua:47: in function 'update'
love.js:9 [string "boot.lua"]:612: in function <[string "boot.lua"]:594>
love.js:9 [C]: in function 'xpcall'
lovejs errors with "attempt to yield across metamethod/C-call boundary" when you try to yield in a coroutine inside xpcall. love2d native (11.3) runs the same code without issue. I'm not sure why the behaviour is different and this use case doesn't seem super common, but it tripped me up so I thought I'd post an issue.
I ran into this because I was using batteries.async which wraps all coroutines in xpcall to capture the immediate callstack for errors instead of where the one at coroutine.resume.
An example of the issue (tested on 9e07fa0b1c50bb1c1132a843b5ede661f141ed53 using pfirsich/makelove to package compat):
Pressing
v
to start the coroutine in lovejs produces this error: