diff --git a/src/Cthulhu.jl b/src/Cthulhu.jl index 295216af..a61d6ef9 100644 --- a/src/Cthulhu.jl +++ b/src/Cthulhu.jl @@ -33,6 +33,7 @@ Base.@kwdef mutable struct CthulhuConfig hide_type_stable::Bool = false remarks::Bool = false with_effects::Bool = false + exception_type::Bool = false inline_cost::Bool = false type_annotations::Bool = true annotate_source::Bool = true # overrides optimize, although the current setting is preserved @@ -63,6 +64,7 @@ end - `iswarn::Bool`: Initial state of "warn" toggle. Defaults to `false`. - `remarks::Bool` Initial state of "remarks" toggle. Defaults to `false`. - `with_effects::Bool` Intial state of "effects" toggle. Defaults to `false`. +- `exception_type::Bool` `Intial state of "exception type" toggle. Defaults to `false`. - `inline_cost::Bool` Initial state of "inlining costs" toggle. Defaults to `false`. - `type_annotations::Bool` Initial state of "type annnotations" toggle. Defaults to `true`. - `annotate_source::Bool` Initial state of "Source". Defaults to `true`. @@ -253,6 +255,14 @@ function cached_return_type(code::CodeInstance) end end +function cached_exception_type(code::CodeInstance) + @static if VERSION ≥ v"1.11.0-DEV.945" + return code.exctype + else + return nothing + end +end + get_effects(codeinst::CodeInstance) = CC.decode_effects(codeinst.ipo_purity_bits) get_effects(codeinst::CodeInfo) = CC.decode_effects(codeinst.purity) get_effects(src::InferredSource) = src.effects @@ -275,6 +285,7 @@ end function lookup_optimized(interp::CthulhuInterpreter, mi::MethodInstance, allow_no_src::Bool=false) codeinst = interp.opt[mi] rt = cached_return_type(codeinst) + exct = cached_exception_type(codeinst) opt = codeinst.inferred if opt !== nothing opt = opt::OptimizedSource @@ -296,19 +307,19 @@ function lookup_optimized(interp::CthulhuInterpreter, mi::MethodInstance, allow_ error("couldn't find the source; inspect `Main.interp` and `Main.mi`") end effects = get_effects(codeinst) - return (; src, rt, infos, slottypes, effects, codeinf) + return (; src, rt, exct, infos, slottypes, effects, codeinf) end function lookup_unoptimized(interp::CthulhuInterpreter, mi::MethodInstance) codeinf = src = copy(interp.unopt[mi].src) - rt = interp.unopt[mi].rt + (; rt, exct) = interp.unopt[mi] infos = interp.unopt[mi].stmt_info effects = get_effects(interp.unopt[mi]) slottypes = src.slottypes if isnothing(slottypes) slottypes = Any[ Any for i = 1:length(src.slotflags) ] end - return (; src, rt, infos, slottypes, effects, codeinf) + return (; src, rt, exct, infos, slottypes, effects, codeinf) end function lookup_constproped(interp::CthulhuInterpreter, override::InferenceResult, optimize::Bool) @@ -326,11 +337,12 @@ function lookup_constproped_optimized(interp::CthulhuInterpreter, override::Infe # e.g. when we switch from constant-prop' unoptimized source src = CC.copy(opt.ir) rt = override.result + exct = override.exc_result infos = src.stmts.info slottypes = src.argtypes codeinf = opt.src effects = opt.effects - return (; src, rt, infos, slottypes, effects, codeinf) + return (; src, rt, exct, infos, slottypes, effects, codeinf) else # the source might be unavailable at this point, # when a result is fully constant-folded etc. @@ -344,24 +356,25 @@ function lookup_constproped_unoptimized(interp::CthulhuInterpreter, override::In unopt = interp.unopt[override.linfo] end codeinf = src = copy(unopt.src) - rt = unopt.rt + (; rt, exct) = unopt infos = unopt.stmt_info effects = get_effects(unopt) slottypes = src.slottypes if isnothing(slottypes) slottypes = Any[ Any for i = 1:length(src.slotflags) ] end - return (; src, rt, infos, slottypes, effects, codeinf) + return (; src, rt, exct, infos, slottypes, effects, codeinf) end function lookup_semiconcrete(interp::CthulhuInterpreter, override::SemiConcreteCallInfo, optimize::Bool) src = CC.copy(override.ir) rt = get_rt(override) + exct = Any # TODO infos = src.stmts.info slottypes = src.argtypes effects = get_effects(override) (; codeinf) = lookup(interp, get_mi(override), optimize) - return (; src, rt, infos, slottypes, effects, codeinf) + return (; src, rt, exct, infos, slottypes, effects, codeinf) end function get_override(@nospecialize(info)) @@ -378,20 +391,21 @@ end ## function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::AbstractCursor; override::Union{Nothing,InferenceResult,SemiConcreteCallInfo} = nothing, - debuginfo::Union{Symbol,DebugInfo} = CONFIG.debuginfo, # default is compact debuginfo - optimize::Bool = CONFIG.optimize, # default is true - interruptexc::Bool = CONFIG.interruptexc, - iswarn::Bool = CONFIG.iswarn, # default is false - hide_type_stable::Union{Nothing,Bool} = CONFIG.hide_type_stable, - verbose::Union{Nothing,Bool} = nothing, - remarks::Bool = CONFIG.remarks&!CONFIG.optimize, # default is false - with_effects::Bool = CONFIG.with_effects, # default is false - inline_cost::Bool = CONFIG.inline_cost&CONFIG.optimize, # default is false - type_annotations::Bool = CONFIG.type_annotations, # default is true - annotate_source::Bool = CONFIG.annotate_source, # default is true - inlay_types_vscode::Bool = CONFIG.inlay_types_vscode, # default is true - diagnostics_vscode::Bool = CONFIG.diagnostics_vscode, # default is true - jump_always::Bool = CONFIG.jump_always, # default is false + debuginfo::Union{Symbol,DebugInfo} = CONFIG.debuginfo, # default is compact debuginfo + optimize::Bool = CONFIG.optimize, # default is true + interruptexc::Bool = CONFIG.interruptexc, + iswarn::Bool = CONFIG.iswarn, # default is false + hide_type_stable::Union{Nothing,Bool} = CONFIG.hide_type_stable, + verbose::Union{Nothing,Bool} = nothing, + remarks::Bool = CONFIG.remarks&!CONFIG.optimize, # default is false + with_effects::Bool = CONFIG.with_effects, # default is false + exception_type::Bool = CONFIG.exception_type, # default is false + inline_cost::Bool = CONFIG.inline_cost&CONFIG.optimize, # default is false + type_annotations::Bool = CONFIG.type_annotations, # default is true + annotate_source::Bool = CONFIG.annotate_source, # default is true + inlay_types_vscode::Bool = CONFIG.inlay_types_vscode, # default is true + diagnostics_vscode::Bool = CONFIG.diagnostics_vscode, # default is true + jump_always::Bool = CONFIG.jump_always, # default is false ) if isnothing(hide_type_stable) @@ -413,7 +427,9 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs do_typeinf!(new_interp, new_mi) _descend(term, new_interp, new_mi; debuginfo, optimize, interruptexc, iswarn, hide_type_stable, remarks, - with_effects, inline_cost, type_annotations, annotate_source, inlay_types_vscode, diagnostics_vscode) + with_effects, exception_type, + inline_cost, type_annotations, annotate_source, + inlay_types_vscode, diagnostics_vscode) end custom_toggles = Cthulhu.custom_toggles(interp) if !(custom_toggles isa Vector{CustomToggle}) @@ -424,9 +440,9 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs end while true if isa(override, InferenceResult) - (; src, rt, infos, slottypes, codeinf, effects) = lookup_constproped(interp, curs, override, optimize & !annotate_source) + (; src, rt, exct, infos, slottypes, codeinf, effects) = lookup_constproped(interp, curs, override, optimize & !annotate_source) elseif isa(override, SemiConcreteCallInfo) - (; src, rt, infos, slottypes, codeinf, effects) = lookup_semiconcrete(interp, curs, override, optimize & !annotate_source) + (; src, rt, exct, infos, slottypes, codeinf, effects) = lookup_semiconcrete(interp, curs, override, optimize & !annotate_source) else if optimize && !annotate_source codeinst = get_optimized_codeinst(interp, curs) @@ -436,7 +452,8 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs # but make something up that looks plausible. callsites = Callsite[] if display_CI - callsite = Callsite(-1, MICallInfo(codeinst.def, codeinst.rettype, get_effects(codeinst)), :invoke) + exct = @static VERSION ≥ v"1.11.0-DEV.945" ? codeinst.exct : nothing + callsite = Callsite(-1, MICallInfo(codeinst.def, codeinst.rettype, get_effects(codeinst), exct), :invoke) println(iostream) println(iostream, "│ ─ $callsite") println(iostream, "│ return ", Const(codeinst.rettype_const)) @@ -453,7 +470,7 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs end end end - (; src, rt, infos, slottypes, effects, codeinf) = lookup(interp, curs, optimize & !annotate_source) + (; src, rt, exct, infos, slottypes, effects, codeinf) = lookup(interp, curs, optimize & !annotate_source) end mi = get_mi(curs) src = preprocess_ci!(src, mi, optimize & !annotate_source, CONFIG) @@ -462,7 +479,16 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs else @assert length(src.code) == length(infos) end - callsites, sourcenodes = find_callsites(interp, src, infos, mi, slottypes, optimize & !annotate_source, annotate_source) + infkey = override isa InferenceResult ? override : mi + @static if VERSION ≥ v"1.11.0-DEV.1127" + pc2excts = exception_type ? get_excts(interp, infkey) : nothing + else + if exception_type + @warn "Statement-wise and call-wise exception type information is available only on v\"1.11.0-DEV.1127\" and later" + end + pc2excts = nothing + end + callsites, sourcenodes = find_callsites(interp, src, infos, mi, slottypes, optimize & !annotate_source, annotate_source, pc2excts) if jump_always if isdefined(Main, :VSCodeServer) && Main.VSCodeServer isa Module && isdefined(Main.VSCodeServer, :openfile) @@ -473,8 +499,8 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs end if display_CI - pc2remarks = remarks ? get_remarks(interp, override !== nothing ? override : mi) : nothing - pc2effects = with_effects ? get_effects(interp, override !== nothing ? override : mi) : nothing + pc2remarks = remarks ? get_remarks(interp, infkey) : nothing + pc2effects = with_effects ? get_effects(interp, infkey) : nothing printstyled(IOContext(iostream, :limit=>true), mi.def, '\n'; bold=true) if debuginfo == DInfo.compact str = let debuginfo=debuginfo, src=src, codeinf=codeinf, rt=rt, mi=mi, @@ -484,11 +510,12 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs :color => true, :displaysize => displaysize(iostream), # displaysize doesn't propagate otherwise :SOURCE_SLOTNAMES => codeinf === nothing ? false : Base.sourceinfo_slotnames(codeinf), - :with_effects => with_effects) + :with_effects => with_effects, + :exception_type => exception_type) stringify(ioctx) do lambda_io - cthulhu_typed(lambda_io, debuginfo, annotate_source ? codeinf : src, rt, effects, mi; + cthulhu_typed(lambda_io, debuginfo, annotate_source ? codeinf : src, rt, exct, effects, mi; iswarn, optimize, hide_type_stable, - pc2remarks, pc2effects, + pc2remarks, pc2effects, pc2excts, inline_cost, type_annotations, annotate_source, inlay_types_vscode, diagnostics_vscode, jump_always, interp) end @@ -502,10 +529,11 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs else lambda_io = IOContext(iostream, :SOURCE_SLOTNAMES => Base.sourceinfo_slotnames(codeinf), - :with_effects => with_effects) - cthulhu_typed(lambda_io, debuginfo, src, rt, effects, mi; + :with_effects => with_effects, + :exception_type => exception_type) + cthulhu_typed(lambda_io, debuginfo, src, rt, exct, effects, mi; iswarn, optimize, hide_type_stable, - pc2remarks, pc2effects, + pc2remarks, pc2effects, pc2excts, inline_cost, type_annotations, annotate_source, inlay_types_vscode, diagnostics_vscode, jump_always, interp) end @@ -517,9 +545,14 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs @label show_menu shown_callsites = annotate_source ? sourcenodes : callsites - menu = CthulhuMenu(shown_callsites, with_effects, optimize & !annotate_source, iswarn&get(iostream, :color, false)::Bool, hide_type_stable, custom_toggles; menu_options...) - usg = usage(view_cmd, annotate_source, optimize, iswarn, hide_type_stable, debuginfo, remarks, with_effects, inline_cost, type_annotations, - CONFIG.enable_highlighter, inlay_types_vscode, diagnostics_vscode, jump_always, custom_toggles) + menu = CthulhuMenu(shown_callsites, with_effects, exception_type, + optimize & !annotate_source, + iswarn&get(iostream, :color, false)::Bool, + hide_type_stable, custom_toggles; menu_options...) + usg = usage(view_cmd, annotate_source, optimize, iswarn, hide_type_stable, + debuginfo, remarks, with_effects, exception_type, inline_cost, + type_annotations, CONFIG.enable_highlighter, inlay_types_vscode, + diagnostics_vscode, jump_always, custom_toggles) cid = request(term, usg, menu) toggle = menu.toggle @@ -563,7 +596,9 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs end end end - menu = CthulhuMenu(show_sub_callsites, with_effects, optimize & !annotate_source, false, false, custom_toggles; sub_menu=true, menu_options...) + menu = CthulhuMenu(show_sub_callsites, with_effects, exception_type, + optimize & !annotate_source, false, false, custom_toggles; + sub_menu=true, menu_options...) cid = request(term, "", menu) if cid == length(sub_callsites) + 1 continue @@ -608,7 +643,7 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs override = get_override(info), debuginfo, optimize, interruptexc, iswarn, hide_type_stable, - remarks, with_effects, inline_cost, + remarks, with_effects, exception_type, inline_cost, type_annotations, annotate_source, inlay_types_vscode, diagnostics_vscode, jump_always) @@ -617,6 +652,8 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs iswarn ⊻= true elseif toggle === :with_effects with_effects ⊻= true + elseif toggle === :exception_type + exception_type ⊻= true elseif toggle === :hide_type_stable hide_type_stable ⊻= true elseif toggle === :inlay_types_vscode diff --git a/src/callsite.jl b/src/callsite.jl index 6ac77cc0..afa7ce93 100644 --- a/src/callsite.jl +++ b/src/callsite.jl @@ -7,17 +7,19 @@ struct MICallInfo <: CallInfo mi::MethodInstance rt effects::Effects - function MICallInfo(mi::MethodInstance, @nospecialize(rt), effects) + exct + function MICallInfo(mi::MethodInstance, @nospecialize(rt), effects, @nospecialize(exct=nothing)) if isa(rt, LimitedAccuracy) - return LimitedCallInfo(new(mi, ignorelimited(rt), effects)) + return LimitedCallInfo(new(mi, ignorelimited(rt), effects, exct)) else - return new(mi, rt, effects) + return new(mi, rt, effects, exct) end end end get_mi(ci::MICallInfo) = ci.mi -get_rt(ci::CallInfo) = ci.rt +get_rt(ci::MICallInfo) = ci.rt get_effects(ci::MICallInfo) = ci.effects +get_exct(ci::MICallInfo) = ci.exct abstract type WrappedCallInfo <: CallInfo end @@ -27,6 +29,7 @@ ignorewrappers(ci::WrappedCallInfo) = ignorewrappers(get_wrapped(ci)) get_mi(ci::WrappedCallInfo) = get_mi(ignorewrappers(ci)) get_rt(ci::WrappedCallInfo) = get_rt(ignorewrappers(ci)) get_effects(ci::WrappedCallInfo) = get_effects(ignorewrappers(ci)) +get_exct(ci::WrappedCallInfo) = get_exct(ignorewrappers(ci)) # only appears when inspecting pre-optimization states struct LimitedCallInfo <: WrappedCallInfo @@ -38,9 +41,12 @@ struct RTCallInfo <: CallInfo f argtyps rt + exct end +get_rt(ci::RTCallInfo) = ci.rt get_mi(ci::RTCallInfo) = nothing get_effects(ci::RTCallInfo) = Effects() +get_exct(ci::RTCallInfo) = ci.exct # uncached callsite, we can't recurse into this call struct UncachedCallInfo <: WrappedCallInfo @@ -56,6 +62,7 @@ end get_mi(::PureCallInfo) = nothing get_rt(pci::PureCallInfo) = pci.rt get_effects(::PureCallInfo) = EFFECTS_TOTAL +get_exct(::PureCallInfo) = Union{} # Failed struct FailedCallInfo <: CallInfo @@ -64,7 +71,8 @@ struct FailedCallInfo <: CallInfo end get_mi(ci::FailedCallInfo) = fail(ci) get_rt(ci::FailedCallInfo) = fail(ci) -get_effects(ci::FailedCallInfo) = Effects() +get_effects(ci::FailedCallInfo) = fail(ci) +get_exct(ci::FailedCallInfo) = fail(ci) function fail(ci::FailedCallInfo) @warn "MethodInstance extraction failed." ci.sig ci.rt return nothing @@ -77,7 +85,8 @@ struct GeneratedCallInfo <: CallInfo end get_mi(genci::GeneratedCallInfo) = fail(genci) get_rt(genci::GeneratedCallInfo) = fail(genci) -get_effects(genci::GeneratedCallInfo) = Effects() +get_effects(genci::GeneratedCallInfo) = fail(genci) +get_exct(genci::GeneratedCallInfo) = fail(genci) function fail(genci::GeneratedCallInfo) @warn "Can't extract MethodInstance from call to generated functions." genci.sig genci.rt return nothing @@ -86,11 +95,16 @@ end struct MultiCallInfo <: CallInfo sig rt + exct callinfos::Vector{CallInfo} + MultiCallInfo(@nospecialize(sig), @nospecialize(rt), callinfos::Vector{CallInfo}, + @nospecialize(exct=nothing)) = + new(sig, rt, exct, callinfos) end -# actual code-error get_mi(ci::MultiCallInfo) = error("Can't extract MethodInstance from multiple call informations") +get_rt(ci::MultiCallInfo) = ci.rt get_effects(mci::MultiCallInfo) = mapreduce(get_effects, CC.merge_effects, mci.callinfos) +get_exct(ci::MultiCallInfo) = ci.exct struct TaskCallInfo <: CallInfo ci::CallInfo @@ -98,6 +112,7 @@ end get_mi(tci::TaskCallInfo) = get_mi(tci.ci) get_rt(tci::TaskCallInfo) = get_rt(tci.ci) get_effects(tci::TaskCallInfo) = get_effects(tci.ci) +get_exct(tci::TaskCallInfo) = get_exct(tci.ci) struct InvokeCallInfo <: CallInfo ci::CallInfo @@ -106,6 +121,7 @@ end get_mi(ici::InvokeCallInfo) = get_mi(ici.ci) get_rt(ici::InvokeCallInfo) = get_rt(ici.ci) get_effects(ici::InvokeCallInfo) = get_effects(ici.ci) +get_exct(ici::InvokeCallInfo) = get_exct(ici.ci) # OpaqueClosure CallInfo struct OCCallInfo <: CallInfo @@ -115,6 +131,7 @@ end get_mi(occi::OCCallInfo) = get_mi(occi.ci) get_rt(occi::OCCallInfo) = get_rt(occi.ci) get_effects(occi::OCCallInfo) = get_effects(occi.ci) +get_exct(occi::OCCallInfo) = get_exct(occi.ci) # Special handling for ReturnTypeCall struct ReturnTypeCallInfo <: CallInfo @@ -123,6 +140,7 @@ end get_mi((; vmi)::ReturnTypeCallInfo) = isa(vmi, FailedCallInfo) ? nothing : get_mi(vmi) get_rt((; vmi)::ReturnTypeCallInfo) = Type{isa(vmi, FailedCallInfo) ? Union{} : widenconst(get_rt(vmi))} get_effects(::ReturnTypeCallInfo) = EFFECTS_TOTAL +get_exct(::ReturnTypeCallInfo) = Union{} # FIXME struct ConstPropCallInfo <: CallInfo mi::CallInfo @@ -131,6 +149,7 @@ end get_mi(cpci::ConstPropCallInfo) = cpci.result.linfo get_rt(cpci::ConstPropCallInfo) = get_rt(cpci.mi) get_effects(cpci::ConstPropCallInfo) = get_effects(cpci.result) +get_exct(cpci::ConstPropCallInfo) = get_exct(cpci.mi) struct ConcreteCallInfo <: CallInfo mi::CallInfo @@ -139,6 +158,7 @@ end get_mi(ceci::ConcreteCallInfo) = get_mi(ceci.mi) get_rt(ceci::ConcreteCallInfo) = get_rt(ceci.mi) get_effects(ceci::ConcreteCallInfo) = get_effects(ceci.mi) +get_exct(cici::ConcreteCallInfo) = get_exct(ceci.mi) struct SemiConcreteCallInfo <: CallInfo mi::CallInfo @@ -147,6 +167,7 @@ end get_mi(scci::SemiConcreteCallInfo) = get_mi(scci.mi) get_rt(scci::SemiConcreteCallInfo) = get_rt(scci.mi) get_effects(scci::SemiConcreteCallInfo) = get_effects(scci.mi) +get_exct(scci::SemiConcreteCallInfo) = get_exct(scci.mi) # CUDA callsite struct CuCallInfo <: CallInfo @@ -187,22 +208,22 @@ function headstring(@nospecialize(T)) end end -function __show_limited(limiter, name, tt, @nospecialize(rt), effects) +function __show_limited(limiter, name, tt, @nospecialize(rt), effects, @nospecialize(exct=nothing)) vastring(@nospecialize(T)) = (isvarargtype(T) ? headstring(T)*"..." : string(T)::String) # If effects are explicitly turned on, make sure to print them, even # if there otherwise isn't space for them, since the effects are the # most important piece of information if turned on. with_effects = get(limiter, :with_effects, false)::Bool + exception_type = get(limiter, :exception_type, false)::Bool && exct !== nothing - if with_effects - limiter.width += textwidth(repr(effects)) + 1 - end - + with_effects && (limiter.width += textwidth(repr(effects)) + 1) + exception_type && (limiter.width += textwidth(string(exct)) + 1) if !has_space(limiter, name) print(limiter, '…') @goto print_effects end + print(limiter, string(name)) pstrings = String[vastring(T) for T in tt] headstrings = String[ @@ -234,15 +255,28 @@ function __show_limited(limiter, name, tt, @nospecialize(rt), effects) print(limiter, "::…") end -@label print_effects + @label print_effects if with_effects # Print effects unlimited print(limiter.io, " ", effects) end + if exception_type + print(limiter.io, ' ', ExctWrapper(exct)) + end return nothing end +struct ExctWrapper + exct + ExctWrapper(@nospecialize exct) = new(exct) +end + +function Base.show(io::IO, (;exct)::ExctWrapper) + color = exct === Union{} ? :green : :yellow + printstyled(io, "(↑::", exct, ")"; color) +end + function show_callinfo(limiter, mici::MICallInfo) mi = mici.mi tt = (Base.unwrap_unionall(mi.specTypes)::DataType).parameters[2:end] @@ -252,7 +286,8 @@ function show_callinfo(limiter, mici::MICallInfo) name = mi.def.name end rt = get_rt(mici) - __show_limited(limiter, name, tt, rt, get_effects(mici)) + exct = get_exct(mici) + __show_limited(limiter, name, tt, rt, get_effects(mici), exct) end function show_callinfo(limiter, ci::Union{MultiCallInfo, FailedCallInfo, GeneratedCallInfo}) diff --git a/src/codeview.jl b/src/codeview.jl index af897e48..a1ccd4dc 100644 --- a/src/codeview.jl +++ b/src/codeview.jl @@ -106,7 +106,7 @@ function cthulhu_warntype(io::IO, debuginfo::AnyDebugInfo, if inline_cost isa(mi, MethodInstance) || error("Need a MethodInstance to show inlining costs. Call `cthulhu_typed` directly instead.") end - cthulhu_typed(io, debuginfo, src, rt, effects, mi; iswarn=true, optimize, hide_type_stable, inline_cost, interp) + cthulhu_typed(io, debuginfo, src, rt, nothing, effects, mi; iswarn=true, optimize, hide_type_stable, inline_cost, interp) return nothing end @@ -121,9 +121,12 @@ end cthulhu_typed(io::IO, debuginfo::DebugInfo, args...; kwargs...) = cthulhu_typed(io, Symbol(debuginfo), args...; kwargs...) function cthulhu_typed(io::IO, debuginfo::Symbol, - src::Union{CodeInfo,IRCode}, @nospecialize(rt), effects::Effects, mi::Union{Nothing,MethodInstance}; + src::Union{CodeInfo,IRCode}, @nospecialize(rt), @nospecialize(exct), + effects::Effects, mi::Union{Nothing,MethodInstance}; iswarn::Bool=false, hide_type_stable::Bool=false, optimize::Bool=true, - pc2remarks::Union{Nothing,PC2Remarks}=nothing, pc2effects::Union{Nothing,PC2Effects}=nothing, + pc2remarks::Union{Nothing,PC2Remarks}=nothing, + pc2effects::Union{Nothing,PC2Effects}=nothing, + pc2excts::Union{Nothing,PC2Excts}=nothing, inline_cost::Bool=false, type_annotations::Bool=true, annotate_source::Bool=false, inlay_types_vscode::Bool=false, diagnostics_vscode::Bool=false, jump_always::Bool=false, interp::AbstractInterpreter=CthulhuInterpreter()) @@ -248,18 +251,28 @@ function cthulhu_typed(io::IO, debuginfo::Symbol, end end # postprinter configuration - __postprinter = if type_annotations + ___postprinter = if type_annotations iswarn ? InteractiveUtils.warntype_type_printer : IRShow.default_expr_type_printer else Returns(nothing) end - _postprinter = if isa(src, CodeInfo) && !isnothing(pc2effects) + __postprinter = if isa(src, CodeInfo) && !isnothing(pc2effects) function (io::IO; idx::Int, @nospecialize(kws...)) - __postprinter(io; idx, kws...) + ___postprinter(io; idx, kws...) local effects = get(pc2effects, idx, nothing) effects === nothing && return print(io, ' ', effects) end + else + ___postprinter + end + _postprinter = if isa(src, CodeInfo) && !isnothing(pc2excts) + function (io::IO; idx::Int, @nospecialize(kws...)) + __postprinter(io; idx, kws...) + local exct = get(pc2excts, idx, nothing) + exct === nothing && return + print(io, ' ', ExctWrapper(exct)) + end else __postprinter end @@ -293,7 +306,7 @@ function cthulhu_typed(io::IO, debuginfo::Symbol, cfg = src isa IRCode ? src.cfg : Core.Compiler.compute_basic_blocks(src.code) max_bb_idx_size = length(string(length(cfg.blocks))) str = irshow_config.line_info_preprinter(lambda_io, " "^(max_bb_idx_size + 2), -1) - callsite = Callsite(0, MICallInfo(mi, rettype, effects), :invoke) + callsite = Callsite(0, MICallInfo(mi, rettype, effects, exct), :invoke) println(lambda_io, "∘ ", "─"^(max_bb_idx_size), str, " ", callsite) end @@ -444,7 +457,7 @@ function Base.show( return end println(io, "Cthulhu.Bookmark (world: ", world, ")") - cthulhu_typed(io, debuginfo, CI, rt, effects, b.mi; iswarn, optimize, hide_type_stable, b.interp) + cthulhu_typed(io, debuginfo, CI, rt, nothing, effects, b.mi; iswarn, optimize, hide_type_stable, b.interp) end function InteractiveUtils.code_typed(b::Bookmark; optimize::Bool=true) diff --git a/src/interface.jl b/src/interface.jl index c7e5e04c..ba37f03a 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -68,13 +68,14 @@ missing `$AbstractCursor` API: """) navigate(curs::CthulhuCursor, callsite::Callsite) = CthulhuCursor(get_mi(callsite)) -get_remarks(::AbstractInterpreter, ::Union{MethodInstance,InferenceResult}) = nothing -get_remarks(interp::CthulhuInterpreter, key::Union{MethodInstance,InferenceResult}) = get(interp.remarks, key, nothing) -get_remarks(::AbstractInterpreter, ::SemiConcreteCallInfo) = PC2Remarks() +get_remarks(::AbstractInterpreter, ::InferenceKey) = nothing +get_remarks(interp::CthulhuInterpreter, key::InferenceKey) = get(interp.remarks, key, nothing) -get_effects(::AbstractInterpreter, ::Union{MethodInstance,InferenceResult}) = nothing -get_effects(interp::CthulhuInterpreter, key::Union{MethodInstance,InferenceResult}) = get(interp.effects, key, nothing) -get_effects(::AbstractInterpreter, ::SemiConcreteCallInfo) = PC2Effects() +get_effects(::AbstractInterpreter, ::InferenceKey) = nothing +get_effects(interp::CthulhuInterpreter, key::InferenceKey) = get(interp.effects, key, nothing) + +get_excts(::AbstractInterpreter, ::InferenceKey) = nothing +get_excts(interp::CthulhuInterpreter, key::InferenceKey) = get(interp.exception_types, key, nothing) # This method is optional, but should be implemented if there is # a sensible default cursor for a MethodInstance diff --git a/src/interpreter.jl b/src/interpreter.jl index 546a7d45..b03e1d4d 100644 --- a/src/interpreter.jl +++ b/src/interpreter.jl @@ -9,8 +9,10 @@ struct InferredSource stmt_info::Vector{CCCallInfo} effects::Effects rt::Any - InferredSource(src::CodeInfo, stmt_info::Vector{CCCallInfo}, effects, @nospecialize(rt)) = - new(src, stmt_info, effects, rt) + exct::Any + InferredSource(src::CodeInfo, stmt_info::Vector{CCCallInfo}, effects, @nospecialize(rt), + @nospecialize(exct)) = + new(src, stmt_info, effects, rt, exct) end struct OptimizedSource @@ -20,26 +22,31 @@ struct OptimizedSource effects::Effects end +const InferenceKey = Union{MethodInstance,InferenceResult} +const InferenceDict{T} = Dict{InferenceKey, T} const PC2Remarks = Vector{Pair{Int, String}} const PC2Effects = Dict{Int, Effects} +const PC2Excts = Dict{Int, Any} struct CthulhuInterpreter <: AbstractInterpreter native::AbstractInterpreter - unopt::Dict{Union{MethodInstance,InferenceResult}, InferredSource} + unopt::InferenceDict{InferredSource} opt::Dict{MethodInstance, CodeInstance} - remarks::Dict{Union{MethodInstance,InferenceResult}, PC2Remarks} - effects::Dict{Union{MethodInstance,InferenceResult}, PC2Effects} + remarks::InferenceDict{PC2Remarks} + effects::InferenceDict{PC2Effects} + exception_types::InferenceDict{PC2Excts} end function CthulhuInterpreter(interp::AbstractInterpreter=NativeInterpreter()) return CthulhuInterpreter( interp, - Dict{Union{MethodInstance,InferenceResult}, InferredSource}(), + InferenceDict{InferredSource}(), Dict{MethodInstance, CodeInstance}(), - Dict{Union{MethodInstance,InferenceResult}, PC2Remarks}(), - Dict{Union{MethodInstance,InferenceResult}, PC2Effects}()) + InferenceDict{PC2Remarks}(), + InferenceDict{PC2Effects}(), + InferenceDict{PC2Excts}()) end import .CC: InferenceParams, OptimizationParams, get_world_counter, @@ -138,11 +145,13 @@ function InferredSource(state::InferenceState) slottypes === nothing ? nothing : copy(slottypes) end end + exct = @static VERSION ≥ v"1.11.0-DEV.207" ? state.result.exc_result : nothing return InferredSource( unoptsrc, copy(state.stmt_info), isdefined(CC, :Effects) ? state.ipo_effects : nothing, - state.result.result) + state.result.result, + exct) end function CC.finish(state::InferenceState, interp::CthulhuInterpreter) @@ -236,3 +245,14 @@ function CC.finish!(interp::CthulhuInterpreter, caller::InferenceResult) caller.src = create_cthulhu_source(caller.src, caller.ipo_effects) end end + +@static if VERSION ≥ v"1.11.0-DEV.1127" +function CC.update_exc_bestguess!(interp::CthulhuInterpreter, @nospecialize(exct), + frame::InferenceState) + key = CC.any(frame.result.overridden_by_const) ? frame.result : frame.linfo + pc2excts = get!(PC2Excts, interp.exception_types, key) + pc2excts[frame.currpc] = CC.tmerge(CC.typeinf_lattice(interp), exct, get(pc2excts, frame.currpc, Union{})) + return @invoke CC.update_exc_bestguess!(interp::AbstractInterpreter, exct::Any, + frame::InferenceState) +end +end diff --git a/src/reflection.jl b/src/reflection.jl index 4e3501d0..eee04004 100644 --- a/src/reflection.jl +++ b/src/reflection.jl @@ -20,7 +20,8 @@ end function find_callsites(interp::AbstractInterpreter, CI::Union{Core.CodeInfo, IRCode}, stmt_infos::Union{Vector{CCCallInfo}, Nothing}, mi::Core.MethodInstance, - slottypes::Vector{Any}, optimize::Bool=true, annotate_source::Bool=false) + slottypes::Vector{Any}, optimize::Bool=true, annotate_source::Bool=false, + pc2excts::Union{Nothing,PC2Excts}=nothing) sptypes = sptypes_from_meth_instance(mi) callsites, sourcenodes = Callsite[], Union{TypedSyntax.MaybeTypedSyntaxNode,Callsite}[] if isa(CI, IRCode) @@ -53,7 +54,8 @@ function find_callsites(interp::AbstractInterpreter, CI::Union{Core.CodeInfo, IR t = argextype(arg, CI, sptypes, slottypes) return ignorelimited(t) end, args) - callinfos = process_info(interp, info, argtypes, rt, optimize) + exct = isnothing(pc2excts) ? nothing : get(pc2excts, id, nothing) + callinfos = process_info(interp, info, argtypes, rt, optimize, exct) isempty(callinfos) && continue callsite = let if length(callinfos) == 1 @@ -116,7 +118,8 @@ function find_callsites(interp::AbstractInterpreter, CI::Union{Core.CodeInfo, IR end function process_const_info(interp::AbstractInterpreter, @nospecialize(thisinfo), - argtypes::ArgTypes, @nospecialize(rt), @nospecialize(result), optimize::Bool) + argtypes::ArgTypes, @nospecialize(rt), @nospecialize(result), optimize::Bool, + @nospecialize(exct)) is_cached(@nospecialize(key)) = can_descend(interp, key, optimize) if isnothing(result) @@ -128,55 +131,57 @@ function process_const_info(interp::AbstractInterpreter, @nospecialize(thisinfo) elseif isa(result, CC.ConcreteResult) linfo = result.mi effects = get_effects(result) - mici = MICallInfo(linfo, rt, effects) + mici = MICallInfo(linfo, rt, effects, exct) return ConcreteCallInfo(mici, argtypes) elseif isa(result, CC.ConstPropResult) result = result.result linfo = result.linfo effects = get_effects(result) - mici = MICallInfo(linfo, rt, effects) + mici = MICallInfo(linfo, rt, effects, exct) return ConstPropCallInfo(is_cached(optimize ? linfo : result) ? mici : UncachedCallInfo(mici), result) elseif isa(result, CC.SemiConcreteResult) linfo = result.mi effects = get_effects(result) - mici = MICallInfo(linfo, rt, effects) + mici = MICallInfo(linfo, rt, effects, exct) return SemiConcreteCallInfo(mici, result.ir) else @assert isa(result, CC.InferenceResult) linfo = result.linfo effects = get_effects(result) - mici = MICallInfo(linfo, rt, effects) + mici = MICallInfo(linfo, rt, effects, exct) return ConstPropCallInfo(is_cached(optimize ? linfo : result) ? mici : UncachedCallInfo(mici), result) end end -function process_info(interp::AbstractInterpreter, @nospecialize(info::CCCallInfo), argtypes::ArgTypes, @nospecialize(rt), optimize::Bool) +function process_info(interp::AbstractInterpreter, @nospecialize(info::CCCallInfo), + argtypes::ArgTypes, @nospecialize(rt), optimize::Bool, + @nospecialize(exct)) is_cached(@nospecialize(key)) = can_descend(interp, key, optimize) - process_recursive(@nospecialize(newinfo)) = process_info(interp, newinfo, argtypes, rt, optimize) + process_recursive(@nospecialize(newinfo)) = process_info(interp, newinfo, argtypes, rt, optimize, exct) if isa(info, MethodResultPure) if isa(info.info, CC.ReturnTypeCallInfo) # xref: https://github.com/JuliaLang/julia/pull/45299#discussion_r871939049 info = info.info # cascade to the special handling below else - return Any[PureCallInfo(argtypes, rt)] + return CallInfo[PureCallInfo(argtypes, rt)] end end if isa(info, MethodMatchInfo) if info.results === missing - return [] + return CallInfo[] end matches = info.results.matches - return mapany(matches) do match::Core.MethodMatch + return CallInfo[let mi = specialize_method(match) effects = get_effects(interp, mi, false) - mici = MICallInfo(mi, rt, effects) - return is_cached(mi) ? mici : UncachedCallInfo(mici) - end + mici = MICallInfo(mi, rt, effects, exct) + is_cached(mi) ? mici : UncachedCallInfo(mici) + end for match::Core.MethodMatch in matches] elseif isa(info, UnionSplitInfo) - return mapreduce(process_recursive, vcat, info.matches; init=[])::Vector{Any} + return mapreduce(process_recursive, vcat, info.matches; init=CallInfo[])::Vector{CallInfo} elseif isa(info, UnionSplitApplyCallInfo) - return mapreduce(process_recursive, vcat, info.infos; init=[])::Vector{Any} + return mapreduce(process_recursive, vcat, info.infos; init=CallInfo[])::Vector{CallInfo} elseif isa(info, ApplyCallInfo) # XXX: This could probably use its own info. For now, # we ignore any implicit iterate calls. @@ -184,32 +189,32 @@ function process_info(interp::AbstractInterpreter, @nospecialize(info::CCCallInf elseif isa(info, ConstCallInfo) infos = process_recursive(info.call) @assert length(infos) == length(info.results) - return mapany(enumerate(info.results)) do (i, result) - process_const_info(interp, infos[i], argtypes, rt, result, optimize) - end + return CallInfo[let + process_const_info(interp, infos[i], argtypes, rt, result, optimize, exct) + end for (i, result) in enumerate(info.results)] elseif isa(info, CC.InvokeCallInfo) mi = specialize_method(info.match; preexisting=true) effects = get_effects(interp, mi, false) thisinfo = MICallInfo(mi, rt, effects) - innerinfo = process_const_info(interp, thisinfo, argtypes, rt, info.result, optimize) + innerinfo = process_const_info(interp, thisinfo, argtypes, rt, info.result, optimize, exct) info = InvokeCallInfo(innerinfo) - return Any[info] + return CallInfo[info] elseif isa(info, CC.OpaqueClosureCallInfo) mi = specialize_method(info.match; preexisting=true) effects = get_effects(interp, mi, false) thisinfo = MICallInfo(mi, rt, effects) - innerinfo = process_const_info(interp, thisinfo, argtypes, rt, info.result, optimize) + innerinfo = process_const_info(interp, thisinfo, argtypes, rt, info.result, optimize, exct) info = OCCallInfo(innerinfo) - return Any[info] + return CallInfo[info] elseif isa(info, CC.OpaqueClosureCreateInfo) # TODO: Add ability to descend into OCs at creation site - return [] + return CallInfo[] elseif isa(info, CC.FinalizerInfo) # TODO: Add ability to descend into finalizers at creation site - return [] + return CallInfo[] elseif isa(info, CC.ReturnTypeCallInfo) newargtypes = argtypes[2:end] - callinfos = process_info(interp, info.info, newargtypes, unwrapType(widenconst(rt)), optimize) + callinfos = process_info(interp, info.info, newargtypes, unwrapType(widenconst(rt)), optimize, exct) if length(callinfos) == 1 vmi = only(callinfos) else @@ -218,13 +223,13 @@ function process_info(interp::AbstractInterpreter, @nospecialize(info::CCCallInf sig = Tuple{widenconst(newargtypes[1]), argt.parameters...} vmi = FailedCallInfo(sig, Union{}) end - return Any[ReturnTypeCallInfo(vmi)] + return CallInfo[ReturnTypeCallInfo(vmi)] elseif info == NoCallInfo() f = unwrapconst(argtypes[1]) - isa(f, Core.Builtin) && return [] - return [RTCallInfo(f, argtypes[2:end], rt)] + isa(f, Core.Builtin) && return CallInfo[] + return CallInfo[RTCallInfo(f, argtypes[2:end], rt, exct)] elseif info === false - return [] + return CallInfo[] else @eval Main begin interp = $interp @@ -352,7 +357,6 @@ function get_typed_sourcetext(mi::MethodInstance, src::CodeInfo, @nospecialize(r meth = mi.def::Method tsn, mappings = TypedSyntax.tsn_and_mappings(meth, src, rt; warn, strip_macros=true) return truncate_if_defaultargs!(tsn, mappings, meth) - return tsn, mappings end function get_typed_sourcetext(mi::MethodInstance, ::IRCode, @nospecialize(rt); kwargs...) diff --git a/src/ui.jl b/src/ui.jl index df02462e..18ff7ee9 100644 --- a/src/ui.jl +++ b/src/ui.jl @@ -13,7 +13,7 @@ mutable struct CthulhuMenu <: TerminalMenus.ConfiguredMenu{TerminalMenus.Config} custom_toggles::Vector{CustomToggle} end -function show_as_line(callsite::Callsite, with_effects::Bool, optimize::Bool, iswarn::Bool) +function show_as_line(callsite::Callsite, with_effects::Bool, exception_type::Bool, optimize::Bool, iswarn::Bool) reduced_displaysize = displaysize(stdout)::Tuple{Int,Int} .- (0, 3) sprint() do io show(IOContext(io, @@ -21,15 +21,17 @@ function show_as_line(callsite::Callsite, with_effects::Bool, optimize::Bool, is :displaysize => reduced_displaysize, :optimize => optimize, :iswarn => iswarn, - :color => iswarn | with_effects, - :with_effects => with_effects), + :color => iswarn | with_effects | exception_type, + :with_effects => with_effects, + :exception_type => exception_type), callsite) end end -function CthulhuMenu(callsites, with_effects::Bool, optimize::Bool, iswarn::Bool, hide_type_stable::Bool, +function CthulhuMenu(callsites, with_effects::Bool, exception_type::Bool, + optimize::Bool, iswarn::Bool, hide_type_stable::Bool, custom_toggles::Vector{CustomToggle}; pagesize::Int=10, sub_menu = false, kwargs...) - options = build_options(callsites, with_effects, optimize, iswarn, hide_type_stable) + options = build_options(callsites, with_effects, exception_type, optimize, iswarn, hide_type_stable) length(options) < 1 && error("CthulhuMenu must have at least one option") # if pagesize is -1, use automatic paging @@ -47,15 +49,15 @@ function CthulhuMenu(callsites, with_effects::Bool, optimize::Bool, iswarn::Bool return CthulhuMenu(options, pagesize, pageoffset, selected, nothing, sub_menu, config, custom_toggles) end -build_options(callsites::Vector{Callsite}, with_effects::Bool, optimize::Bool, iswarn::Bool, ::Bool) = - vcat(map(callsite->show_as_line(callsite, with_effects, optimize, iswarn), callsites), ["↩"]) -function build_options(callsites, with_effects::Bool, optimize::Bool, iswarn::Bool, hide_type_stable::Bool) +build_options(callsites::Vector{Callsite}, with_effects::Bool, exception_type::Bool, optimize::Bool, iswarn::Bool, ::Bool) = + vcat(map(callsite->show_as_line(callsite, with_effects, exception_type, optimize, iswarn), callsites), ["↩"]) +function build_options(callsites, with_effects::Bool, exception_type::Bool, optimize::Bool, iswarn::Bool, hide_type_stable::Bool) reduced_displaysize::Int = (displaysize(stdout)::Tuple{Int,Int})[2] - 3 nd::Int = -1 shown_callsites = map(callsites) do node if isa(node, Callsite) - show_as_line(node, with_effects, optimize, iswarn) + show_as_line(node, with_effects, exception_type, optimize, iswarn) else if nd == -1 nd = TypedSyntax.ndigits_linenumbers(node) @@ -92,8 +94,10 @@ function stringify(@nospecialize(f), context::IOContext) end const debugcolors = (:nothing, :light_black, :yellow) -function usage(@nospecialize(view_cmd), annotate_source, optimize, iswarn, hide_type_stable, debuginfo, remarks, with_effects, inline_cost, type_annotations, highlight, - inlay_types_vscode, diagnostics_vscode, jump_always, custom_toggles::Vector{CustomToggle}) +function usage(@nospecialize(view_cmd), annotate_source, optimize, iswarn, hide_type_stable, + debuginfo, remarks, with_effects, exception_type, inline_cost, + type_annotations, highlight, inlay_types_vscode, diagnostics_vscode, + jump_always, custom_toggles::Vector{CustomToggle}) colorize(use_color::Bool, c::Char) = stringify() do io use_color ? printstyled(io, c; color=:cyan) : print(io, c) end @@ -123,7 +127,8 @@ function usage(@nospecialize(view_cmd), annotate_source, optimize, iswarn, hide_ printstyled(io, 'd'; color=debugcolors[Int(debuginfo)+1]) end, "]ebuginfo, [", colorize(remarks, 'r'), "]emarks, [", - colorize(with_effects, 'e'), "]ffects, [", + colorize(with_effects, 'e'), "]ffects, ", + "e[", colorize(exception_type, 'x'), "]ception types, [", colorize(inline_cost, 'i'), "]nlining costs") end for i = 1:length(custom_toggles) @@ -157,6 +162,7 @@ const TOGGLES = Dict( UInt32('d') => :debuginfo, UInt32('r') => :remarks, UInt32('e') => :with_effects, + UInt32('x') => :exception_type, UInt32('i') => :inline_cost, UInt32('t') => :type_annotations, UInt32('s') => :highlighter, diff --git a/test/generate_irshow.jl b/test/generate_irshow.jl index 0e2ddc1d..2a95722e 100644 --- a/test/generate_irshow.jl +++ b/test/generate_irshow.jl @@ -11,7 +11,7 @@ function generate_test_cases(f, tt, fname=string(nameof(f))) outputs = Dict() tf = (true, false) for optimize in tf - (; src, infos, mi, rt, effects, slottypes) = cthulhu_info(f, tt; optimize); + (; src, infos, mi, rt, exct, effects, slottypes) = cthulhu_info(f, tt; optimize); for (debuginfo, iswarn, hide_type_stable, inline_cost, type_annotations) in Iterators.product( instances(Cthulhu.DInfo.DebugInfo), tf, tf, tf, tf, ) @@ -20,7 +20,7 @@ function generate_test_cases(f, tt, fname=string(nameof(f))) s = sprint(; context=:color=>true) do io Cthulhu.cthulhu_typed(io, debuginfo, - src, rt, effects, mi; + src, rt, exct, effects, mi; iswarn, hide_type_stable, inline_cost, type_annotations) end s = strip_base_linenums(s) diff --git a/test/setup.jl b/test/setup.jl index 90d9c067..8e0dfd87 100644 --- a/test/setup.jl +++ b/test/setup.jl @@ -5,11 +5,11 @@ end function cthulhu_info(@nospecialize(f), @nospecialize(TT=()); optimize=true) (interp, mi) = Cthulhu.mkinterp(Core.Compiler.NativeInterpreter(), f, TT) - (; src, rt, infos, slottypes, effects) = Cthulhu.lookup(interp, mi, optimize; allow_no_src=true) + (; src, rt, exct, infos, slottypes, effects) = Cthulhu.lookup(interp, mi, optimize; allow_no_src=true) if src !== nothing src = Cthulhu.preprocess_ci!(src, mi, optimize, Cthulhu.CthulhuConfig(dead_code_elimination=true)) end - (; interp, src, infos, mi, rt, slottypes, effects) + (; interp, src, infos, mi, rt, exct, slottypes, effects) end function find_callsites_by_ftt(@nospecialize(f), @nospecialize(TT=Tuple{}); optimize=true) diff --git a/test/test_Cthulhu.jl b/test/test_Cthulhu.jl index 4951abc3..2f902252 100644 --- a/test/test_Cthulhu.jl +++ b/test/test_Cthulhu.jl @@ -357,11 +357,7 @@ end callsites, _ = Cthulhu.find_callsites(interp, src, infos, mi, slottypes, false) @test isa(callsites[1].info, Cthulhu.SemiConcreteCallInfo) @test occursin("= < semi-concrete eval > getproperty(::ComplexF64,::Core.Const(:re))::Float64", string(callsites[1])) - @test Cthulhu.get_rt(callsites[end].info) == Core.Const(sin(1.0)) - - @test Cthulhu.get_remarks(interp, callsites[1].info) == Cthulhu.PC2Remarks() - @test Cthulhu.get_effects(interp, callsites[1].info) == Cthulhu.PC2Effects() end end @@ -677,9 +673,9 @@ end end end function doprint(f) - (; src, mi, rt, effects) = cthulhu_info(f) + (; src, mi, rt, exct, effects) = cthulhu_info(f) io = IOBuffer() - Cthulhu.cthulhu_typed(io, :none, src, rt, effects, mi; iswarn=false) + Cthulhu.cthulhu_typed(io, :none, src, rt, exct, effects, mi; iswarn=false) return String(take!(io)) end @test occursin("invoke f1()::…\n", doprint(getfield(m, :f1))) diff --git a/test/test_codeview.jl b/test/test_codeview.jl index 02058fde..8e531011 100644 --- a/test/test_codeview.jl +++ b/test/test_codeview.jl @@ -10,7 +10,7 @@ using .TestCodeViewSandbox Revise.track(TestCodeViewSandbox, normpath(@__DIR__, "TestCodeViewSandbox.jl")) @testset "printer test" begin - (; interp, src, infos, mi, rt, effects, slottypes) = cthulhu_info(testf_revise); + (; interp, src, infos, mi, rt, exct, effects, slottypes) = cthulhu_info(testf_revise); tf = (true, false) @testset "codeview: $codeview" for codeview in Cthulhu.CODEVIEWS @@ -35,7 +35,7 @@ Revise.track(TestCodeViewSandbox, normpath(@__DIR__, "TestCodeViewSandbox.jl")) @testset "type_annotations: $type_annotations" for type_annotations in tf io = IOBuffer() Cthulhu.cthulhu_typed(io, debuginfo, - src, rt, effects, mi; + src, rt, exct, effects, mi; iswarn, hide_type_stable, inline_cost, type_annotations) @test !isempty(String(take!(io))) # just check it works end @@ -47,7 +47,7 @@ end @testset "hide type-stable statements" begin let # optimize code - (; src, infos, mi, rt, effects, slottypes) = @eval Module() begin + (; src, infos, mi, rt, exct, effects, slottypes) = @eval Module() begin const globalvar = Ref(42) $cthulhu_info() do a = sin(globalvar[]) @@ -57,7 +57,7 @@ end end function prints(; kwargs...) io = IOBuffer() - Cthulhu.cthulhu_typed(io, :none, src, rt, effects, mi; kwargs...) + Cthulhu.cthulhu_typed(io, :none, src, rt, exct, effects, mi; kwargs...) return String(take!(io)) end @@ -74,7 +74,7 @@ end end let # unoptimize code - (; src, infos, mi, rt, effects, slottypes) = @eval Module() begin + (; src, infos, mi, rt, exct, effects, slottypes) = @eval Module() begin const globalvar = Ref(42) $cthulhu_info(; optimize=false) do a = sin(globalvar[]) @@ -84,7 +84,7 @@ end end function prints(; kwargs...) io = IOBuffer() - Cthulhu.cthulhu_typed(io, :none, src, rt, effects, mi; kwargs...) + Cthulhu.cthulhu_typed(io, :none, src, rt, exct, effects, mi; kwargs...) return String(take!(io)) end diff --git a/test/test_irshow.jl b/test/test_irshow.jl index 22e2870a..b9418a10 100644 --- a/test/test_irshow.jl +++ b/test/test_irshow.jl @@ -10,7 +10,7 @@ include("IRShowSandbox.jl") tf = (true, false) @testset "optimize: $optimize" for optimize in tf - (; src, infos, mi, rt, effects, slottypes) = cthulhu_info(IRShowSandbox.foo, (Int, Int); optimize); + (; src, infos, mi, rt, exct, effects, slottypes) = cthulhu_info(IRShowSandbox.foo, (Int, Int); optimize); @testset "debuginfo: $debuginfo" for debuginfo in instances(Cthulhu.DInfo.DebugInfo) @testset "iswarn: $iswarn" for iswarn in tf @@ -22,7 +22,7 @@ include("IRShowSandbox.jl") s = sprint(; context=:color=>true) do io Cthulhu.cthulhu_typed(io, debuginfo, - src, rt, effects, mi; + src, rt, exct, effects, mi; iswarn, hide_type_stable, inline_cost, type_annotations) end s = strip_base_linenums(s)