Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: clean up method reflection #16123

Merged
merged 2 commits into from
May 2, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add back sig and tvars fields to Method
return Method objects for reflection instead of TypeMapEntry
  • Loading branch information
JeffBezanson committed Apr 29, 2016
commit 92eafc0b8730ef04a5ff10bc8473ed589f7dd7a5
4 changes: 2 additions & 2 deletions base/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ function get_type_call(expr::Expr)
length(mt) == 1 || return (Any, false)
m = first(mt)
# Typeinference
linfo = Base.func_for_method_checked(m[3].func, Tuple{args...})
linfo = Base.func_for_method_checked(m[3], Tuple{args...})
(tree, return_type) = Core.Inference.typeinf(linfo, m[1], m[2])
return return_type, true
end
Expand Down Expand Up @@ -321,7 +321,7 @@ function complete_methods(ex_org::Expr)
out = UTF8String[]
t_in = Tuple{Core.Typeof(func), args_ex...} # Input types
na = length(args_ex)+1
Base.visit(methods(func)) do method
for method in methods(func)
# Check if the method's type signature intersects the input types
typeintersect(Tuple{method.sig.parameters[1 : min(na, end)]...}, t_in) != Union{} &&
push!(out,string(method))
Expand Down
2 changes: 1 addition & 1 deletion base/docs/helpdb/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6916,7 +6916,7 @@ less(f::AbstractString, ?)
Show the definition of a function using the default pager, optionally specifying a tuple of
types to indicate which method to see.
"""
less(m::TypeMapEntry, ?)
less(func, ?)

"""
sqrtm(A)
Expand Down
2 changes: 1 addition & 1 deletion base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ macro generated(f)
end


tuple_type_head(::Type{Union{}}) = throw(MethodError(tuple_type_head, (Type{Union{}},)))
tuple_type_head(::Type{Union{}}) = throw(MethodError(tuple_type_head, (Union{},)))
function tuple_type_head{T<:Tuple}(::Type{T})
@_pure_meta
T.parameters[1]
Expand Down
23 changes: 11 additions & 12 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -602,13 +602,14 @@ function invoke_tfunc(f::ANY, types::ANY, argtype::ANY, sv::InferenceState)
ft = type_typeof(f)
types = Tuple{ft, types.parameters...}
argtype = Tuple{ft, argtype.parameters...}
meth = ccall(:jl_gf_invoke_lookup, Any, (Any,), types)
if is(meth, nothing)
entry = ccall(:jl_gf_invoke_lookup, Any, (Any,), types)
if is(entry, nothing)
return Any
end
meth = entry.func
(ti, env) = ccall(:jl_match_method, Any, (Any, Any, Any),
argtype, meth.sig, meth.tvars)::SimpleVector
return typeinf_edge(meth.func::Method, ti, env, sv)[2]
return typeinf_edge(meth::Method, ti, env, sv)[2]
end

function tuple_tfunc(argtype::ANY)
Expand Down Expand Up @@ -751,7 +752,7 @@ function abstract_call_gf_by_type(f::ANY, argtype::ANY, sv)
end
for (m::SimpleVector) in x
sig = m[1]
method = m[3].func::Method
method = m[3]::Method

# limit argument type tuple growth
lsig = length(m[3].sig.parameters)
Expand Down Expand Up @@ -923,7 +924,7 @@ function pure_eval_call(f::ANY, argtypes::ANY, atype, sv)
return false
end
meth = meth[1]::SimpleVector
method = meth[3].func::Method
method = meth[3]::Method
# TODO: check pure on the inferred thunk
if method.isstaged || !method.lambda_template.pure
return false
Expand Down Expand Up @@ -2268,7 +2269,6 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
return NF
end

local methfunc
atype = argtypes_to_type(atypes)
if length(atype.parameters) - 1 > MAX_TUPLETYPE_LEN
atype = limit_tuple_type(atype)
Expand All @@ -2280,7 +2280,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
meth = meth[1]::SimpleVector
metharg = meth[1]::Type
methsp = meth[2]
method = meth[3].func::Method
method = meth[3]::Method
if isa(f, widenconst(ft)) && !method.isstaged && method.lambda_template.pure && (isType(e.typ) || isa(e.typ,Const))
# check if any arguments aren't effect_free and need to be kept around
stmts = Any[]
Expand All @@ -2301,8 +2301,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
end
end

methfunc = meth[3].func
methsig = meth[3].sig
methsig = method.sig
incompletematch = false
if !(atype <: metharg)
incompletematch = true
Expand Down Expand Up @@ -3409,13 +3408,13 @@ end
# make sure that typeinf is executed before turning on typeinf_ext
# this ensures that typeinf_ext doesn't recurse before it can add the item to the workq

precompile(methods(typeinf_edge).defs.sig)
precompile(typeof(typeinf_edge).name.mt.defs.sig)
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't matter now, but eventually we should delete this line (it's been a no-op ever since inference0.ji was eliminated)


for m in _methods_by_ftype(Tuple{typeof(typeinf_loop), Vararg{Any}}, 10)
typeinf(m[3].func, m[1], m[2], true)
typeinf(m[3], m[1], m[2], true)
end
for m in _methods_by_ftype(Tuple{typeof(typeinf_edge), Vararg{Any}}, 10)
typeinf(m[3].func, m[1], m[2], true)
typeinf(m[3], m[1], m[2], true)
end

ccall(:jl_set_typeinf_func, Void, (Any,), typeinf_ext)
9 changes: 4 additions & 5 deletions base/interactiveutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -383,9 +383,8 @@ function type_close_enough(x::ANY, t::ANY)
end

# `methodswith` -- shows a list of methods using the type given
function methodswith(t::Type, f::Function, showparents::Bool=false, meths = TypeMapEntry[])
mt = typeof(f).name.mt
visit(mt) do d
function methodswith(t::Type, f::Function, showparents::Bool=false, meths = Method[])
for d in methods(f)
if any(x -> (type_close_enough(x, t) ||
(showparents ? (t <: x && (!isa(x,TypeVar) || x.ub != Any)) :
(isa(x,TypeVar) && x.ub != Any && t == x.ub)) &&
Expand All @@ -398,7 +397,7 @@ function methodswith(t::Type, f::Function, showparents::Bool=false, meths = Type
end

function methodswith(t::Type, m::Module, showparents::Bool=false)
meths = TypeMapEntry[]
meths = Method[]
for nm in names(m)
if isdefined(m, nm)
f = getfield(m, nm)
Expand All @@ -411,7 +410,7 @@ function methodswith(t::Type, m::Module, showparents::Bool=false)
end

function methodswith(t::Type, showparents::Bool=false)
meths = TypeMapEntry[]
meths = Method[]
mainmod = current_module()
# find modules in Main
for nm in names(mainmod)
Expand Down
40 changes: 16 additions & 24 deletions base/methodshow.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
# This file is a part of Julia. License is MIT: http:https://julialang.org/license

# Method and method-table pretty-printing

function get_lambda(m::TypeMapEntry)
isdefined(m, :func) || return nothing
isa(m.func, Method) && return m.func.lambda_template
isa(m.func, LambdaInfo) && return m.func
return nothing
end
# Method and method table pretty-printing

function argtype_decl(env, n, t) # -> (argname, argtype)
if isa(n,Expr)
Expand All @@ -33,14 +26,14 @@ function argtype_decl(env, n, t) # -> (argname, argtype)
return s, string_with_env(env, t)
end

function arg_decl_parts(m::TypeMapEntry)
function arg_decl_parts(m::Method)
tv = m.tvars
if !isa(tv,SimpleVector)
tv = Any[tv]
else
tv = Any[tv...]
end
li = get_lambda(m)
li = m.lambda_template
file, line = "", 0
if li !== nothing
argnames = li.slotnames[1:li.nargs]
Expand All @@ -56,8 +49,8 @@ function arg_decl_parts(m::TypeMapEntry)
return tv, decls, file, line
end

function kwarg_decl(m::TypeMapEntry, kwtype::DataType)
sig = Tuple{kwtype, Array, m.sig.parameters...}
function kwarg_decl(sig::ANY, kwtype::DataType)
sig = Tuple{kwtype, Array, sig.parameters...}
kwli = ccall(:jl_methtable_lookup, Any, (Any, Any), kwtype.name.mt, sig)
if kwli !== nothing
kwli = kwli::Method
Expand All @@ -66,11 +59,11 @@ function kwarg_decl(m::TypeMapEntry, kwtype::DataType)
return ()
end

function show(io::IO, m::Method)
print(io, m.module, '.', m.name, m.isstaged ? " [@generated] at " : " at ", m.file, ":", m.line)
end
#function show(io::IO, m::Method)
# print(io, m.module, '.', m.name, m.isstaged ? " [@generated] at " : " at ", m.file, ":", m.line)
#end

function show(io::IO, m::TypeMapEntry; kwtype::Nullable{DataType}=Nullable{DataType}())
function show(io::IO, m::Method; kwtype::Nullable{DataType}=Nullable{DataType}())
tv, decls, file, line = arg_decl_parts(m)
ft = m.sig.parameters[1]
d1 = decls[1]
Expand All @@ -95,7 +88,7 @@ function show(io::IO, m::TypeMapEntry; kwtype::Nullable{DataType}=Nullable{DataT
print_joined(io, [isempty(d[2]) ? d[1] : d[1]*"::"*d[2] for d in decls[2:end]],
", ", ", ")
if !isnull(kwtype)
kwargs = kwarg_decl(m, get(kwtype))
kwargs = kwarg_decl(m.sig, get(kwtype))
if !isempty(kwargs)
print(io, "; ")
print_joined(io, kwargs, ", ", ", ")
Expand Down Expand Up @@ -153,7 +146,6 @@ function inbase(m::Module)
end
fileurl(file) = let f = find_source_file(file); f === nothing ? "" : "file:https://"*f; end

url(m::TypeMapEntry) = url(m.func)
function url(m::Method)
M = m.module
(m.file == :null || m.file == :string) && return ""
Expand Down Expand Up @@ -189,7 +181,7 @@ function url(m::Method)
end
end

function writemime(io::IO, ::MIME"text/html", m::TypeMapEntry; kwtype::Nullable{DataType}=Nullable{DataType}())
function writemime(io::IO, ::MIME"text/html", m::Method; kwtype::Nullable{DataType}=Nullable{DataType}())
tv, decls, file, line = arg_decl_parts(m)
ft = m.sig.parameters[1]
d1 = decls[1]
Expand All @@ -216,7 +208,7 @@ function writemime(io::IO, ::MIME"text/html", m::TypeMapEntry; kwtype::Nullable{
print_joined(io, [isempty(d[2]) ? d[1] : d[1]*"::<b>"*d[2]*"</b>"
for d in decls[2:end]], ", ", ", ")
if !isnull(kwtype)
kwargs = kwarg_decl(m, get(kwtype))
kwargs = kwarg_decl(m.sig, get(kwtype))
if !isempty(kwargs)
print(io, "; <i>")
print_joined(io, kwargs, ", ", ", ")
Expand Down Expand Up @@ -251,9 +243,9 @@ function writemime(io::IO, mime::MIME"text/html", mt::MethodTable)
print(io, "</ul>")
end

# pretty-printing of Vector{TypeMapEntry} for output of methodswith:
# pretty-printing of Vector{Method} for output of methodswith:

function writemime(io::IO, mime::MIME"text/html", mt::AbstractVector{TypeMapEntry})
function writemime(io::IO, mime::MIME"text/html", mt::AbstractVector{Method})
print(io, summary(mt))
if !isempty(mt)
print(io, ":<ul>")
Expand All @@ -265,6 +257,6 @@ function writemime(io::IO, mime::MIME"text/html", mt::AbstractVector{TypeMapEntr
end
end

# override usual show method for Vector{TypeMapEntry}: don't abbreviate long lists
writemime(io::IO, mime::MIME"text/plain", mt::AbstractVector{TypeMapEntry}) =
# override usual show method for Vector{Method}: don't abbreviate long lists
writemime(io::IO, mime::MIME"text/plain", mt::AbstractVector{Method}) =
showarray(IOContext(io, :limit_output => false), mt)
41 changes: 15 additions & 26 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,14 @@ end

tt_cons(t::ANY, tup::ANY) = (@_pure_meta; Tuple{t, (isa(tup, Type) ? tup.parameters : tup)...})

code_lowered(f, t::ANY=Tuple) = map(m -> (m.func::Method).lambda_template, methods(f, t))
code_lowered(f, t::ANY=Tuple) = map(m -> (m::Method).lambda_template, methods(f, t))

function methods(f::ANY, t::ANY)
if isa(f,Builtin)
throw(ArgumentError("argument is not a generic function"))
end
t = to_tuple_type(t)
return Any[m[3] for m in _methods(f,t,-1)]
return Method[m[3] for m in _methods(f,t,-1)]
end
function _methods(f::ANY,t::ANY,lim)
ft = isa(f,Type) ? Type{f} : typeof(f)
Expand Down Expand Up @@ -225,14 +225,8 @@ function _methods(t::Array,i,lim::Integer,matching::Array{Any,1})
end

function methods(f::ANY)
ft = typeof(f)
if ft <: Type || !isempty(ft.parameters)
# for these types of `f`, not every method in the table will necessarily
# match, so we need to filter based on its type.
return methods(f, Tuple{Vararg{Any}})
else
return ft.name.mt
end
# return all matches
return methods(f, Tuple{Vararg{Any}})
end

function visit(f, mt::MethodTable)
Expand All @@ -257,7 +251,7 @@ function visit(f, mc::TypeMapLevel)
end
function visit(f, d::TypeMapEntry)
while !is(d, nothing)
f(d)
f(d.func)
d = d.next
end
nothing
Expand Down Expand Up @@ -320,7 +314,7 @@ function code_typed(f::ANY, types::ANY=Tuple; optimize=true)
types = to_tuple_type(types)
asts = []
for x in _methods(f,types,-1)
linfo = func_for_method_checked(x[3].func, types)
linfo = func_for_method_checked(x[3], types)
if optimize
(li, ty, inf) = Core.Inference.typeinf(linfo, x[1], x[2], true)
else
Expand All @@ -337,7 +331,7 @@ function return_types(f::ANY, types::ANY=Tuple)
types = to_tuple_type(types)
rt = []
for x in _methods(f,types,-1)
linfo = func_for_method_checked(x[3].func,types)
linfo = func_for_method_checked(x[3], types)
(_li, ty, inf) = Core.Inference.typeinf(linfo, x[1], x[2])
inf || error("inference not successful") # Inference disabled
push!(rt, ty)
Expand All @@ -354,14 +348,14 @@ function which(f::ANY, t::ANY)
ms = methods(f, t)
isempty(ms) && error("no method found for the specified argument types")
length(ms)!=1 && error("no unique matching method for the specified argument types")
ms[1]
return ms[1]
else
ft = isa(f,Type) ? Type{f} : typeof(f)
m = ccall(:jl_gf_invoke_lookup, Any, (Any,), Tuple{ft, t.parameters...})
if m === nothing
error("no method found for the specified argument types")
end
return m::TypeMapEntry
return m.func::Method
end
end

Expand All @@ -374,7 +368,6 @@ function which_module(m::Module, s::Symbol)
binding_module(m, s)
end

functionloc(m::TypeMapEntry) = functionloc(m.func)
functionloc(m::LambdaInfo) = functionloc(m.def)
function functionloc(m::Method)
ln = m.line
Expand All @@ -388,29 +381,25 @@ functionloc(f::ANY, types::ANY) = functionloc(which(f,types))

function functionloc(f)
mt = methods(f)
local thef = nothing
visit(mt) do f
if thef !== nothing
error("function has multiple methods; please specify a type signature")
end
thef = f
end
if thef === nothing
if isempty(mt)
if isa(f,Function)
error("function has no definitions")
else
error("object is not callable")
end
end
functionloc(thef)
if length(mt) > 1
error("function has multiple methods; please specify a type signature")
end
functionloc(mt[1])
end

function function_module(f, types::ANY)
m = methods(f, types)
if isempty(m)
error("no matching methods")
end
m[1].func.module
m[1].module
end

function method_exists(f::ANY, t::ANY)
Expand Down
Loading