-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
#48766 changed generated functions, requiring manual expansion of @generated in order to get access to the world argument that's now mandatory to pass to reflection methods. This is enforced by the current world being set to -1 during generator expansion, triggering an error (code reflection cannot be used from generated functions) when using using world=-1.
However, this change makes generators that do use reflection very hard to debug when they do anything wrong (i.e. not necessarily reflection-related). Take the following example:
function generator(world, source, self, f, tt)
tt = tt.parameters[1]
sig = Tuple{f, tt.parameters...}
mi = Base._which(sig; world)
error("oh no")
stub = Core.GeneratedFunctionStub(identity, Core.svec(:methodinstance, :ctx, :x, :f), Core.svec())
stub(world, source, :(nothing))
end
@eval function doit(f, tt)
$(Expr(:meta, :generated, generator))
$(Expr(:meta, :generated_only))
end
doit(sin, Tuple{Int})This generator correctly passes the codegen world to _which, but after that triggers some arbitrary unrelated exception (say, you have a typo in the generator). This results in the generator running again at run time, however, at that point it runs with the world argument also set to -1, resulting in:
ERROR: LoadError: code reflection cannot be used from generated functions
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] _which(tt::Type; method_table::Nothing, world::UInt64, raise::Bool)
@ Base ./reflection.jl:1644
That makes it very hard to debug generators. In fact, in order to get IRTools and Zygote working again with this change, I've been running with a patch a la:
diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl
index 836c370b98..35049b14f8 100644
--- a/base/compiler/utilities.jl
+++ b/base/compiler/utilities.jl
@@ -120,7 +120,9 @@ function get_staged(mi::MethodInstance, world::UInt)
# user code might throw errors – ignore them
ci = ccall(:jl_code_for_staged, Any, (Any, UInt), mi, world)::CodeInfo
return ci
- catch
+ catch err
+ Core.println(Core.stderr, "Internal error: encountered unexpected ", err, " during expansion of @generated ", mi, ":")
+ ccall(:jl_print_backtrace, Nothing, ())
return nothing
end
endInternal error: encountered unexpected ErrorException("oh no") during expansion of @generated doit(typeof(Base.sin), Type{Tuple{Int64}}) from doit(Any, Any):
error at ./error.jl:35
generator at /home/tim/Julia/tmp/Zygote.jl/wip3.jl:8
unknown function (ip: 0x7f0aefb00de9)
This at least shows me why the generator failed during compilation, because the run-time exception is useless.
@vtjnash This would have been avoided using a simpler API, #48766 (comment). I get your argument for making the breakage more obvious, but fixing the ecosystem has been a pain.