From dd6b9eec2d4465f1f12f6f88e362e0314ddf2b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8egh?= Date: Sun, 28 Feb 2016 21:06:27 +0100 Subject: [PATCH] Fix #3377. It allows for writing `@methods @time 1+1`, `@functionloc @time 1+1` plus the equivalent for `@which`, `@edit` and `@less`. The macros check for method specialization of the macro and return the dispatched macro. The `@functionloc` macro is exported and the documentation is updated. --- base/docs/helpdb/Base.jl | 65 ------------------------------ base/exports.jl | 1 + base/interactiveutil.jl | 86 ++++++++++++++++++++++++++++++++++++++-- doc/stdlib/base.rst | 22 ++++++---- test/reflection.jl | 19 +++++++++ 5 files changed, 116 insertions(+), 77 deletions(-) diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index f39911c9cc658..e11f30621b731 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -218,14 +218,6 @@ Bessel function of the first kind of order `nu`, ``J_\\nu(x)``. """ besselj -""" - @code_lowered - -Evaluates the arguments to the function call, determines their types, and calls -[`code_lowered`](:func:`code_lowered`) on the resulting expression. -""" -:@code_lowered - """ //(num, den) @@ -716,14 +708,6 @@ keyword arguments `addprocs` was called with. """ launch -""" - @code_typed - -Evaluates the arguments to the function call, determines their types, and calls -[`code_typed`](:func:`code_typed`) on the resulting expression. -""" -:@code_typed - """ invdigamma(x) @@ -3493,13 +3477,6 @@ Returns the lower triangle of `M` starting from the `k`th superdiagonal. """ tril(M,k) -""" - @edit - -Evaluates the arguments to the function call, determines their types, and calls the `edit` -function on the resulting expression. -""" -:@edit """ subtypes(T::DataType) @@ -3614,14 +3591,6 @@ not representable. """ trunc -""" - @less - -Evaluates the arguments to the function call, determines their types, and calls the `less` -function on the resulting expression. -""" -:@less - """ broadcast_function(f) @@ -5549,14 +5518,6 @@ Returns `string` with the first character converted to lowercase. """ lcfirst -""" - @code_native - -Evaluates the arguments to the function call, determines their types, and calls -[`code_native`](:func:`code_native`) on the resulting expression. -""" -:@code_native - """ flipbits!(B::BitArray{N}) -> BitArray{N} @@ -5571,14 +5532,6 @@ Returns the value of a symbolic link `path`. """ readlink -""" - @code_warntype - -Evaluates the arguments to the function call, determines their types, and calls -[`code_warntype`](:func:`code_warntype`) on the resulting expression. -""" -:@code_warntype - """ deg2rad(x) @@ -8257,16 +8210,6 @@ Converts a packed boolean array to an array of booleans. """ bitunpack -""" - @which - -Applied to a function call, it evaluates the arguments to the specified function call, and -returns the `Method` object for the method that would be called for those arguments. Applied -to a variable, it returns the module in which the variable was bound. It calls out to the -`which` function. -""" -:@which - """ size(A, [dim...]) @@ -8454,14 +8397,6 @@ address will be either IPv4 or IPv6 as appropriate. """ recvfrom -""" - @code_llvm - -Evaluates the arguments to the function call, determines their types, and calls -[`code_llvm`](:func:`code_llvm`) on the resulting expression. -""" -:@code_llvm - """ nextfloat(f) diff --git a/base/exports.jl b/base/exports.jl index 4f0601ca50fae..871b6d8df42ff 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1387,6 +1387,7 @@ export # reflection @which, @edit, + @functionloc, @less, @code_typed, @code_warntype, diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 494aa43994ac2..586ffcf936d86 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -256,8 +256,12 @@ function gen_call_with_extracted_types(fcn, ex0) Expr(:call, typesof, map(esc, args[2:end])...)) end exret = Expr(:none) + is_macro = false ex = expand(ex0) - if !isa(ex, Expr) + if isa(ex0, Expr) && ex0.head == :macrocall # Make @edit @time 1+2 edit the macro + is_macro = true + exret = Expr(:call, fcn, esc(ex0.args[1]), typesof(ex0.args[2:end]...)) + elseif !isa(ex, Expr) exret = Expr(:call, :error, "expression is not a function call or symbol") elseif ex.head == :call if any(e->(isa(e, Expr) && e.head==:(...)), ex0.args) && @@ -280,7 +284,7 @@ function gen_call_with_extracted_types(fcn, ex0) end end end - if ex.head == :thunk || exret.head == :none + if (!is_macro && ex.head == :thunk) || exret.head == :none exret = Expr(:call, :error, "expression is not a function call, " * "or is too complex for @$fcn to analyze; " * "break it down to simpler parts if possible") @@ -288,7 +292,7 @@ function gen_call_with_extracted_types(fcn, ex0) exret end -for fname in [:which, :less, :edit, :code_typed, :code_warntype, +for fname in [:which, :less, :edit, :functionloc, :code_typed, :code_warntype, :code_lowered, :code_llvm, :code_llvm_raw, :code_native] @eval begin macro ($fname)(ex0) @@ -297,7 +301,80 @@ for fname in [:which, :less, :edit, :code_typed, :code_warntype, end end -# `methodswith` -- shows a list of methods using the type given +""" + @which + +Applied to a function or macro call, it evaluates the arguments to the specified call, and +returns the `Method` object for the method that would be called for those arguments. Applied +to a variable, it returns the module in which the variable was bound. It calls out to the +`which` function. +""" +:@which + +""" + @less + +Evaluates the arguments to the function or macro call, determines their types, and calls the `less` +function on the resulting expression. +""" +:@less + +""" + @edit + +Evaluates the arguments to the function or macro call, determines their types, and calls the `edit` +function on the resulting expression. +""" +:@edit + +""" + @functionloc + +Applied to a function or macro call, it evaluates the arguments to the specified call, and +returns a tuple `(filename,line)` giving the location for the method that would be called for those arguments. +It calls out to the `functionloc` function. +""" +:@functionloc + +""" + @code_typed + +Evaluates the arguments to the function or macro call, determines their types, and calls +[`code_typed`](:func:`code_typed`) on the resulting expression. +""" +:@code_typed + +""" + @code_warntype + +Evaluates the arguments to the function or macro call, determines their types, and calls +[`code_warntype`](:func:`code_warntype`) on the resulting expression. +""" +:@code_warntype + +""" + @code_lowered + +Evaluates the arguments to the function or macro call, determines their types, and calls +[`code_lowered`](:func:`code_lowered`) on the resulting expression. +""" +:@code_lowered + +""" + @code_llvm + +Evaluates the arguments to the function or macro call, determines their types, and calls +[`code_llvm`](:func:`code_llvm`) on the resulting expression. +""" +:@code_llvm + +""" + @code_native + +Evaluates the arguments to the function or macro call, determines their types, and calls +[`code_native`](:func:`code_native`) on the resulting expression. +""" +:@code_native function type_close_enough(x::ANY, t::ANY) x == t && return true @@ -306,6 +383,7 @@ function type_close_enough(x::ANY, t::ANY) (isa(x,Union) && isa(t,DataType) && any(u -> is(u,t), x.types)) end +# `methodswith` -- shows a list of methods using the type given function methodswith(t::Type, f::Function, showparents::Bool=false, meths = Method[]) mt = typeof(f).name.mt d = mt.defs diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 684d6e62e99af..f83802b31db8a 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -80,7 +80,7 @@ Getting Around .. Docstring generated from Julia source - Evaluates the arguments to the function call, determines their types, and calls the ``edit`` function on the resulting expression. + Evaluates the arguments to the function or macro call, determines their types, and calls the ``edit`` function on the resulting expression. .. function:: less(file::AbstractString, [line]) @@ -98,7 +98,7 @@ Getting Around .. Docstring generated from Julia source - Evaluates the arguments to the function call, determines their types, and calls the ``less`` function on the resulting expression. + Evaluates the arguments to the function or macro call, determines their types, and calls the ``less`` function on the resulting expression. .. function:: clipboard(x) @@ -188,7 +188,7 @@ Getting Around .. Docstring generated from Julia source - Applied to a function call, it evaluates the arguments to the specified function call, and returns the ``Method`` object for the method that would be called for those arguments. Applied to a variable, it returns the module in which the variable was bound. It calls out to the ``which`` function. + Applied to a function or macro call, it evaluates the arguments to the specified call, and returns the ``Method`` object for the method that would be called for those arguments. Applied to a variable, it returns the module in which the variable was bound. It calls out to the ``which`` function. .. function:: methods(f, [types]) @@ -1326,6 +1326,12 @@ Reflection Returns a tuple ``(filename,line)`` giving the location of a ``Method`` definition. +.. function:: @functionloc + + .. Docstring generated from Julia source + + Applied to a function or macro call, it evaluates the arguments to the specified call, and returns a tuple ``(filename,line)`` giving the location for the method that would be called for those arguments. It calls out to the ``functionloc`` function. + Internals --------- @@ -1363,7 +1369,7 @@ Internals .. Docstring generated from Julia source - Evaluates the arguments to the function call, determines their types, and calls :func:`code_lowered` on the resulting expression. + Evaluates the arguments to the function or macro call, determines their types, and calls :func:`code_lowered` on the resulting expression. .. function:: code_typed(f, types; optimize=true) @@ -1375,7 +1381,7 @@ Internals .. Docstring generated from Julia source - Evaluates the arguments to the function call, determines their types, and calls :func:`code_typed` on the resulting expression. + Evaluates the arguments to the function or macro call, determines their types, and calls :func:`code_typed` on the resulting expression. .. function:: code_warntype(f, types) @@ -1387,7 +1393,7 @@ Internals .. Docstring generated from Julia source - Evaluates the arguments to the function call, determines their types, and calls :func:`code_warntype` on the resulting expression. + Evaluates the arguments to the function or macro call, determines their types, and calls :func:`code_warntype` on the resulting expression. .. function:: code_llvm(f, types) @@ -1401,7 +1407,7 @@ Internals .. Docstring generated from Julia source - Evaluates the arguments to the function call, determines their types, and calls :func:`code_llvm` on the resulting expression. + Evaluates the arguments to the function or macro call, determines their types, and calls :func:`code_llvm` on the resulting expression. .. function:: code_native(f, types) @@ -1413,7 +1419,7 @@ Internals .. Docstring generated from Julia source - Evaluates the arguments to the function call, determines their types, and calls :func:`code_native` on the resulting expression. + Evaluates the arguments to the function or macro call, determines their types, and calls :func:`code_native` on the resulting expression. .. function:: precompile(f,args::Tuple{Vararg{Any}}) diff --git a/test/reflection.jl b/test/reflection.jl index 491cc57aa30f8..e7c747a915769 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -259,3 +259,22 @@ for (f,t) in ((definitely_not_in_sysimg,Tuple{}), @test llvmf != C_NULL @test ccall(:jl_get_llvm_fptr, Ptr{Void}, (Ptr{Void},), llvmf) != C_NULL end + +module MacroTest +export @macrotest +macro macrotest(x::Int, y::Symbol) end +macro macrotest(x::Int, y::Int) + nothing #This is here because of #15280 +end +end + +let + using MacroTest + a = 1 + m = getfield(current_module(), Symbol("@macrotest")) + @test which(m, Tuple{Int,Symbol})==@which @macrotest 1 a + @test which(m, Tuple{Int,Int})==@which @macrotest 1 1 + + @test methods(m,Tuple{Int, Int})[1]==@which MacroTest.@macrotest 1 1 + @test functionloc(@which @macrotest 1 1) == @functionloc @macrotest 1 1 +end