- Sponsor
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Add edit, less and code_* macros, mirroring which #5832
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,11 +59,10 @@ function less(file::String, line::Integer) | |
run(`$pager +$(line)g $file`) | ||
end | ||
less(file::String) = less(file, 1) | ||
|
||
edit(f::Union(Function,DataType)) = edit(functionloc(f)...) | ||
edit(f::Union(Function,DataType), t) = edit(functionloc(f,t)...) | ||
less(f::Union(Function,DataType)) = less(functionloc(f)...) | ||
less(f::Union(Function,DataType), t) = less(functionloc(f,t)...) | ||
edit(f::Callable) = edit(functionloc(f)...) | ||
edit(f::Callable, t::(Type...)) = edit(functionloc(f,t)...) | ||
less(f::Callable) = less(functionloc(f)...) | ||
less(f::Callable, t::(Type...)) = less(functionloc(f,t)...) | ||
|
||
function edit( m::Method ) | ||
tv, decls, file, line = arg_decl_parts(m) | ||
|
@@ -195,53 +194,68 @@ versioninfo(verbose::Bool) = versioninfo(STDOUT,verbose) | |
|
||
# searching definitions | ||
|
||
function which(f::Callable, args...) | ||
function which(f::Callable, t::(Type...)) | ||
if !isgeneric(f) | ||
throw(ErrorException("not a generic function, no methods available")) | ||
end | ||
ms = methods(f, map(a->(isa(a,Type) ? Type{a} : typeof(a)), args)) | ||
isempty(ms) && throw(MethodError(f, args)) | ||
ms = methods(f, t) | ||
isempty(ms) && throw(MethodError(f, t)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit unfortunate --- There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunate indeed. Good catch. The others have to deal with this same issue: code_llvm/native throw: error("no method found for the specified argument types") |
||
ms[1] | ||
end | ||
|
||
macro which(ex0) | ||
if isa(ex0,Expr) && | ||
any(a->(Meta.isexpr(a,:kw) || Meta.isexpr(a,:parameters)), ex0.args) | ||
typesof(args...) = map(a->(isa(a,Type) ? Type{a} : typeof(a)), args) | ||
|
||
function gen_call_with_extracted_types(fcn, ex0) | ||
if isa(ex0, Expr) && | ||
any(a->(Meta.isexpr(a, :kw) || Meta.isexpr(a, :parameters)), ex0.args) | ||
# keyword args not used in dispatch, so just remove them | ||
args = filter(a->!(Meta.isexpr(a,:kw) || Meta.isexpr(a,:parameters)), ex0.args) | ||
return Expr(:call, :which, map(esc, args)...) | ||
args = filter(a->!(Meta.isexpr(a, :kw) || Meta.isexpr(a, :parameters)), ex0.args) | ||
return Expr(:call, fcn, esc(args[1]), | ||
Expr(:call, :typesof, map(esc, args[2:end])...)) | ||
end | ||
if isa(ex0, Expr) && ex0.head == :call | ||
return Expr(:call, :which, map(esc, ex0.args)...) | ||
return Expr(:call, fcn, esc(ex0.args[1]), | ||
Expr(:call, :typesof, map(esc, ex0.args[2:end])...)) | ||
end | ||
ex = expand(ex0) | ||
exret = Expr(:call, :error, "expression is not a function call") | ||
if !isa(ex, Expr) | ||
# do nothing -> error | ||
elseif ex.head == :call | ||
if any(e->(isa(e,Expr) && e.head==:(...)), ex0.args) && | ||
isa(ex.args[1],TopNode) && ex.args[1].name == :apply | ||
exret = Expr(:call, ex.args[1], :which, | ||
if any(e->(isa(e, Expr) && e.head==:(...)), ex0.args) && | ||
isa(ex.args[1], TopNode) && ex.args[1].name == :apply | ||
exret = Expr(:call, ex.args[1], fcn, | ||
Expr(:tuple, esc(ex.args[2])), | ||
map(esc, ex.args[3:end])...) | ||
Expr(:call, :typesof, map(esc, ex.args[3:end])...)) | ||
else | ||
exret = Expr(:call, :which, map(esc, ex.args)...) | ||
exret = Expr(:call, fcn, esc(ex.args[1]), | ||
Expr(:call, :typesof, map(esc, ex.args[2:end])...)) | ||
end | ||
elseif ex.head == :body | ||
a1 = ex.args[1] | ||
if isa(a1, Expr) && a1.head == :call | ||
a11 = a1.args[1] | ||
if a11 == :setindex! | ||
exret = Expr(:call, :which, a11, map(esc, a1.args[2:end])...) | ||
exret = Expr(:call, fcn, a11, | ||
Expr(:call, :typesof, map(esc, a1.args[2:end])...)) | ||
end | ||
end | ||
elseif ex.head == :thunk | ||
exret = Expr(:call, :error, "expression is not a function call, or is too complex for @which to analyze; " | ||
exret = Expr(:call, :error, "expression is not a function call, " | ||
* "or is too complex for @which to analyze; " | ||
* "break it down to simpler parts if possible") | ||
end | ||
exret | ||
end | ||
|
||
for fname in [:which, :less, :edit, :code_typed, :code_lowered, :code_llvm, :code_native] | ||
@eval begin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes. Something about having a macro-generating macro struck me as not right, but a better way didn't occur to me off the top of my head. That's much simpler. |
||
macro ($fname)(ex0) | ||
gen_call_with_extracted_types($fname, ex0) | ||
end | ||
end | ||
end | ||
|
||
# `methodswith` -- shows a list of methods using the type given | ||
|
||
function methodswith(t::Type, m::Module, showparents::Bool=false) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be deprecated. I'd still want to use the function form in various cases. And doesn't the macro generate calls to it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the macro generates calls to
which(f,t::(Type…))
. What I'm deprecating here is the previous definition ofwhich
, which determines the types of its arguments itself.Both could stay in base, but if the user called a function
which(f,(Int,))
there's an ambiguity between whether the user was looking for the method that would be called withf((Int,))
orf(1)
. It's a really slight corner-case, though, and it fails gracefully to the more common case.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, in the current definitions for all the methods (which, edit, less, code_...),
which
is the odd man out. All the others get the arguments as tuple of types. So for this macro to generically call all of them I needed to changewhich
's signature.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you are right.