I'm coding a Luau producer/consumer pattern, where the consumer runs in a coroutine. I was getting "attempt to yield across metamethod/C-call boundary" errors despite the fact that my code uses no metamethods and no C calls (of mine anyway). Code:
-- wrap coroutine.resume() to expose errors in resumed coroutine
function resume(...)
ok_result = table.pack(coroutine.resume(...))
if not ok_result[1] then
error(ok_result[2])
end
return table.unpack(ok_result, 2)
end
-- loop using generic 'for'; should work, yes?
function consumer()
print('generic for loop')
for item in coroutine.yield do
print(item)
end
print('generic for done')
end
array = {'loop', 'over', 'yield', 'calls'}
-- just pump array into consumer coroutine
conco = coroutine.create(consumer)
-- run conco up to first yield()
resume(conco)
for _, word in pairs(array) do
resume(conco, word)
end
-- finish with nil to exit the consumer loop
resume(conco)
coroutine.close(conco)
After considerable flailing, I discovered that this change works:
Tentative conclusion: using a Luau generic
forloop stitches an internal C function call into the call of the iterator function?That was so opaque that it seems worth sharing the discovery.