Skip to content

Commit 461bed8

Browse files
authored
Error: improve no type error message (#2719)
* Error: improve no type error message * Add more information * fix links
1 parent becaa86 commit 461bed8

File tree

1 file changed

+91
-12
lines changed

1 file changed

+91
-12
lines changed

src/errors.jl

Lines changed: 91 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -291,18 +291,74 @@ function InteractiveUtils.code_typed(ece::EnzymeRuntimeActivityError; interactiv
291291
end
292292
end
293293

294-
295-
struct EnzymeNoTypeError <: EnzymeError
294+
struct EnzymeNoTypeError{MT,WT} <: EnzymeError
296295
msg::Cstring
296+
mi::MT
297+
world::WT
297298
end
298299

299300
function Base.showerror(io::IO, ece::EnzymeNoTypeError)
300301
if isdefined(Base.Experimental, :show_error_hints)
301302
Base.Experimental.show_error_hints(io, ece)
302303
end
303-
print(io, "Enzyme cannot deduce type\n")
304-
msg = Base.unsafe_string(ece.msg)
305-
print(io, msg, '\n')
304+
print(io, "Enzyme cannot statically prove the type of a value being differentiated and risks a correctness error if it gets it wrong.\n")
305+
print(io, " Generally this shouldn't occur as Enzyme records type information from julia, but may be expected if you, for example copy untyped data.\n")
306+
print(io, " or alternatively emit very large sized registers that exceed the maximum size of Enzyme's type analysis. If it seems reasonable to differentiate\n")
307+
print(io, " this code, open an issue! If the cause of the error is too large of a register, you can request Enzyme increase the size (https://enzyme.mit.edu/julia/dev/api/#Enzyme.API.maxtypeoffset!-Tuple{Any})\n")
308+
print(io, " or depth (https://enzyme.mit.edu/julia/dev/api/#Enzyme.API.maxtypedepth!-Tuple{Any}) of its type analysis.\n");
309+
print(io, " Alternatively, you can tell Enzyme to take its best guess from context with (https://enzyme.mit.edu/julia/dev/api/#Enzyme.API.looseTypeAnalysis!-Tuple{Any})\n")
310+
print(io, " All of these settings are global configurations that need to be set immeidately after loading Enzyme, before any differentiation occurs\n")
311+
print(io, " To toggle more information for debugging (needed for bug reports), set Enzyme.Compiler.VERBOSE_ERRORS[] = true (default false)\n")
312+
if VERBOSE_ERRORS[]
313+
msg = Base.unsafe_string(ece.msg)
314+
print(io, msg, '\n')
315+
end
316+
if ece.mi !== nothing
317+
print(io, " Failure within method: ", ece.mi, "\n")
318+
printstyled(io, "Hint"; bold = true, color = :cyan)
319+
printstyled(
320+
io,
321+
": catch this exception as `err` and call `code_typed(err)` to inspect the errornous code.\nIf you have Cthulu.jl loaded you can also use `code_typed(err; interactive = true)` to interactively introspect the code.\n";
322+
color = :cyan,
323+
)
324+
end
325+
end
326+
327+
function InteractiveUtils.code_typed(ece::EnzymeNoTypeError; interactive::Bool=false, kwargs...)
328+
mi = ece.mi
329+
if mi === nothing
330+
throw(AssertionError("code_typed(::EnzymeNoTypeError; interactive::Bool=false, kwargs...) not supported for error without mi"))
331+
end
332+
world = ece.world::UInt
333+
mode = Enzyme.API.DEM_ReverseModeCombined
334+
335+
CT = @static if VERSION >= v"1.11.0-DEV.1552"
336+
EnzymeCacheToken(
337+
typeof(DefaultCompilerTarget()),
338+
false,
339+
GPUCompiler.GLOBAL_METHOD_TABLE, #=job.config.always_inline=#
340+
EnzymeCompilerParams,
341+
world,
342+
false,
343+
true,
344+
true
345+
)
346+
else
347+
Enzyme.Compiler.GLOBAL_REV_CACHE
348+
end
349+
350+
interp = Enzyme.Compiler.Interpreter.EnzymeInterpreter(CT, nothing, world, mode, true)
351+
352+
sig = mi.specTypes # XXX: can we just use the method instance?
353+
if interactive
354+
# call Cthulhu without introducing a dependency on Cthulhu
355+
mod = get(Base.loaded_modules, Cthulhu, nothing)
356+
mod===nothing && error("Interactive code reflection requires Cthulhu; please install and load this package first.")
357+
descend_code_typed = getfield(mod, :descend_code_typed)
358+
descend_code_typed(sig; interp, kwargs...)
359+
else
360+
Base.code_typed_by_type(sig; interp, kwargs...)
361+
end
306362
end
307363

308364
struct EnzymeNoShadowError <: EnzymeError
@@ -506,7 +562,30 @@ function julia_error(
506562
println(io, "within ", mi)
507563
end
508564
end
509-
emit_error(B, nothing, msg2, EnzymeNoTypeError)
565+
566+
mi = nothing
567+
world = nothing
568+
569+
if isa(val, LLVM.Instruction)
570+
f = LLVM.parent(LLVM.parent(val))::LLVM.Function
571+
mi, rt = enzyme_custom_extract_mi(
572+
f,
573+
false,
574+
) #=error=#
575+
world = enzyme_extract_world(f)
576+
elseif isa(val, LLVM.Argument)
577+
f = parent_scope(val)::LLVM.Function
578+
mi, rt = enzyme_custom_extract_mi(
579+
f,
580+
false,
581+
) #=error=#
582+
world = enzyme_extract_world(f)
583+
end
584+
if mi !== nothing
585+
emit_error(B, nothing, (msg2, mi, world), EnzymeNoTypeError{Core.MethodInstance, UInt})
586+
else
587+
emit_error(B, nothing, msg2, EnzymeNoTypeError{Nothing, Nothing})
588+
end
510589
return C_NULL
511590
elseif errtype == API.ET_IllegalFirstPointer
512591
throw(IllegalFirstPointerException(msg, ir, bt))
@@ -944,7 +1023,7 @@ end
9441023
end
9451024
end
9461025

947-
mi = nothing
1026+
mi = nothing
9481027
world = nothing
9491028

9501029
if isa(val, LLVM.Instruction)
@@ -964,11 +1043,11 @@ end
9641043
end
9651044
mode = Enzyme.API.DEM_ReverseModeCombined
9661045

967-
if mi !== nothing
968-
emit_error(b, nothing, (msg2, mi, world), EnzymeRuntimeActivityError{Core.MethodInstance, UInt})
969-
else
970-
emit_error(b, nothing, msg2, EnzymeRuntimeActivityError{Nothing, Nothing})
971-
end
1046+
if mi !== nothing
1047+
emit_error(b, nothing, (msg2, mi, world), EnzymeRuntimeActivityError{Core.MethodInstance, UInt})
1048+
else
1049+
emit_error(b, nothing, msg2, EnzymeRuntimeActivityError{Nothing, Nothing})
1050+
end
9721051
return C_NULL
9731052
elseif errtype == API.ET_GetIndexError
9741053
@assert B != C_NULL

0 commit comments

Comments
 (0)