diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index 0d7ee43cf618c..74f8695e111ec 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -176,29 +176,26 @@ function store_backedges(frame::InferenceState) if !toplevel && (frame.cached || frame.parent !== nothing) caller = frame.result.linfo for edges in frame.stmt_edges - edges === nothing && continue - i = 1 - while i <= length(edges) - to = edges[i] - if isa(to, MethodInstance) - ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any), to, caller) - i += 1 - else - typeassert(to, Core.MethodTable) - typ = edges[i + 1] - ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), to, typ, caller) - i += 2 - end - end + store_backedges(caller, edges) end - edges = frame.src.edges - if edges !== nothing - edges = edges::Vector{MethodInstance} - for edge in edges - @assert isa(edge, MethodInstance) - ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any), edge, caller) - end - frame.src.edges = nothing + store_backedges(caller, frame.src.edges) + frame.src.edges = nothing + end +end + +store_backedges(caller, edges::Nothing) = nothing +function store_backedges(caller, edges::Vector) + i = 1 + while i <= length(edges) + to = edges[i] + if isa(to, MethodInstance) + ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any), to, caller) + i += 1 + else + typeassert(to, Core.MethodTable) + typ = edges[i + 1] + ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), to, typ, caller) + i += 2 end end end diff --git a/base/essentials.jl b/base/essentials.jl index b028a07b64e2e..c3f370c34b687 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -234,10 +234,11 @@ function unwrap_unionall(@nospecialize(a)) end function rewrap_unionall(@nospecialize(t), @nospecialize(u)) - if !isa(u, UnionAll) + if isa(u, UnionAll) + return UnionAll(u.var, rewrap_unionall(t, u.body)) + else return t end - return UnionAll(u.var, rewrap_unionall(t, u.body)) end # replace TypeVars in all enclosing UnionAlls with fresh TypeVars diff --git a/base/reflection.jl b/base/reflection.jl index 421e843b05150..767d147fc75e0 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1238,12 +1238,68 @@ julia> hasmethod(g, Tuple{}, (:a, :b, :c, :d)) # g accepts arbitrary kwargs true ``` """ -function hasmethod(@nospecialize(f), @nospecialize(t); world=typemax(UInt)) +function hasmethod end + +# This is just declaring a simplified version of `@generated` earlier in bootstrappping +# to be used by hasmethod. TODO: Replace this with just using @eval ? +macro _early_generated(headsig, body) + return Expr(:escape, + Expr(:function, headsig, + Expr(:block, + Expr(:if, Expr(:generated), + body, + Expr(:block, + Expr(:meta, :generated_only), + Expr(:return, nothing)))))) +end + +# This is used to create the CodeInfo returned by hasmethod. +_hasmethod_false(@nospecialize(f), @nospecialize(t), @nospecialize(w)) = false +_hasmethod_true(@nospecialize(f), @nospecialize(t), @nospecialize(w)) = true + +@_early_generated( + static_hasmethod( + @nospecialize(f), + @nospecialize(t::Type{T}), + @nospecialize(world::Val{W}) + ) where {T<:Tuple, W}, + begin + # The signature type: + typ = rewrap_unionall(Tuple{f, unwrap_unionall(T).parameters...}, T) + + method_doesnot_exist = ccall(:jl_gf_invoke_lookup, Any, (Any, UInt), typ, W) === nothing + ret_func = method_doesnot_exist ? _hasmethod_false : _hasmethod_true + ci_orig = uncompressed_ast(typeof(ret_func).name.mt.defs.func) + ci = ccall(:jl_copy_code_info, Ref{CodeInfo}, (Any,), ci_orig) + + # Now we add the edges so if a method is defined this recompiles + if method_doesnot_exist + # No method so attach to method table + mt = f.name.mt + ci.edges = Core.Compiler.vect(mt, typ) + else # There is a method so need to attach to MethodInstance + # TODO: this case + + end + return ci + end +) + +function static_hasmethod(@nospecialize(f), @nospecialize(t); world=typemax(UInt)) + return static_hasmethod(f, t, Val{world}()) +end + + +function dynamic_hasmethod(@nospecialize(f), @nospecialize(t); world=typemax(UInt)) t = to_tuple_type(t) t = signature_type(f, t) return ccall(:jl_gf_invoke_lookup, Any, (Any, UInt), t, world) !== nothing end +function hasmethod(@nospecialize(f), @nospecialize(t); world=typemax(UInt)) + return static_hasmethod(f, t; world=world) +end + function hasmethod(@nospecialize(f), @nospecialize(t), kwnames::Tuple{Vararg{Symbol}}; world=typemax(UInt)) # TODO: this appears to be doing the wrong queries hasmethod(f, t, world=world) || return false