Skip to content

Commit

Permalink
un-deprecate which, and if the argument type is abstract return wha…
Browse files Browse the repository at this point in the history
…t `invoke` would call

fixes JuliaLang#9589

add `functionloc(::Method)`, and deprecate `functionlocs`, which can
now be done by `map(functionloc, methods(f,t))`.

this also improves the method searching done by `less` and `edit`
  • Loading branch information
JeffBezanson committed Jan 5, 2015
1 parent 4afd63e commit e140b62
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 34 deletions.
4 changes: 2 additions & 2 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,6 @@ const base64 = base64encode
@deprecate randbool(r::AbstractRNG, dims::Dims) bitrand(r, dims)
@deprecate randbool(r::AbstractRNG, dims::Int...) bitrand(r, dims)

@deprecate which(f, t::(Type...)) methods(f, t)[1]

@deprecate beginswith startswith

@deprecate functionlocs(f,t) map(functionloc, methods(f,t))
2 changes: 1 addition & 1 deletion base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,6 @@ export
code_native,
fullname,
functionloc,
functionlocs,
help,
isconst,
isgeneric,
Expand All @@ -1092,6 +1091,7 @@ export
module_parent,
names,
versioninfo,
which,
whos,
workspace,

Expand Down
39 changes: 28 additions & 11 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -160,22 +160,39 @@ code_llvm(f::Function, types::(Type...)) = code_llvm(STDOUT, f, types)
code_native(io::IO, f::Function, types::(Type...)) = print(io, _dump_function(f, types, true, false))
code_native(f::Function, types::(Type...)) = code_native(STDOUT, f, types)

function functionlocs(f::ANY, types=(Type...))
locs = Any[]
for m in methods(f, types)
lsd = m.func.code::LambdaStaticData
ln = lsd.line
if ln > 0
push!(locs, (find_source_file(string(lsd.file)), ln))
function which(f::ANY, t::(Type...))
if isleaftype(t)
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]
else
if !isa(f,Function)
t = tuple(isa(f,Type) ? Type{f} : typeof(f), t...)
f = call
else
if !isgeneric(f)
error("argument is not a generic function")
end
end
m = ccall(:jl_gf_invoke_lookup, Any, (Any, Any), f, t)
if m === nothing
error("no method found for the specified argument types")
end
m
end
if length(locs) == 0
error("could not find function definition")
end

function functionloc(m::Method)
lsd = m.func.code::LambdaStaticData
ln = lsd.line
if ln <= 0
error("could not determine location of method definition")
end
locs
(find_source_file(string(lsd.file)), ln)
end

functionloc(f::ANY, types=(Any...)) = functionlocs(f, types)[1]
functionloc(f::ANY, types=(Any...)) = functionloc(which(f,types))

function function_module(f, types=(Any...))
m = methods(f, types)
Expand Down
16 changes: 10 additions & 6 deletions doc/stdlib/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,21 @@ Getting Around

.. function:: which(f, types)

Return the method of ``f`` (a ``Method`` object) that will be called for arguments with the given types.
Returns the method of ``f`` (a ``Method`` object) that would be called for arguments of the given types.

If ``types`` is an abstract type, then the method that would be called by ``invoke``
is returned.

.. function:: @which

Evaluates the arguments to the function call, determines their types, and calls the ``which`` function on the resulting expression
Evaluates the arguments to the specified function call, and returns the ``Method`` object
for the method that would be called for those arguments.

.. function:: methods(f, [types])

Show all methods of ``f`` with their argument types.
Returns the method table for ``f``.

If ``types`` is specified, an array of methods whose types match is returned.
If ``types`` is specified, returns an array of methods whose types match.

.. function:: methodswith(typ[, module or function][, showparents])

Expand Down Expand Up @@ -889,9 +893,9 @@ Reflection

Returns a tuple ``(filename,line)`` giving the location of a method definition.

.. function:: functionlocs(f::Function, types)
.. function:: functionloc(m::Method)

Returns an array of the results of ``functionloc`` for all matching definitions.
Returns a tuple ``(filename,line)`` giving the location of a method definition.

Internals
---------
Expand Down
38 changes: 24 additions & 14 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1645,24 +1645,12 @@ JL_CALLABLE(jl_apply_generic)
return res;
}

// invoke()
// this does method dispatch with a set of types to match other than the
// types of the actual arguments. this means it sometimes does NOT call the
// most specific method for the argument types, so we need different logic.
// first we use the given types to look up a definition, then we perform
// caching and specialization within just that definition.
// every definition has its own private method table for this purpose.
//
// NOTE: assumes argument type is a subtype of the lookup type.
jl_value_t *jl_gf_invoke(jl_function_t *gf, jl_tuple_t *types,
jl_value_t **args, size_t nargs)
DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_function_t *gf, jl_tuple_t *types)
{
assert(jl_is_gf(gf));
jl_methtable_t *mt = jl_gf_mtable(gf);

jl_methlist_t *m = mt->defs;
size_t typelen = jl_tuple_len(types);
size_t i;
jl_value_t *env = (jl_value_t*)jl_false;

while (m != JL_NULL) {
Expand All @@ -1678,7 +1666,29 @@ jl_value_t *jl_gf_invoke(jl_function_t *gf, jl_tuple_t *types,
m = m->next;
}

if (m == JL_NULL) {
if (m == JL_NULL)
return jl_nothing;
return (jl_value_t*)m;
}

// invoke()
// this does method dispatch with a set of types to match other than the
// types of the actual arguments. this means it sometimes does NOT call the
// most specific method for the argument types, so we need different logic.
// first we use the given types to look up a definition, then we perform
// caching and specialization within just that definition.
// every definition has its own private method table for this purpose.
//
// NOTE: assumes argument type is a subtype of the lookup type.
jl_value_t *jl_gf_invoke(jl_function_t *gf, jl_tuple_t *types,
jl_value_t **args, size_t nargs)
{
assert(jl_is_gf(gf));
jl_methtable_t *mt = jl_gf_mtable(gf);
jl_methlist_t *m = (jl_methlist_t*)jl_gf_invoke_lookup(gf, types);
size_t i;

if ((jl_value_t*)m == jl_nothing) {
jl_no_method_error(gf, args, nargs);
// unreachable
}
Expand Down

0 comments on commit e140b62

Please sign in to comment.