From 6a9653703c21aa5dcde906aea564c940fc44e452 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 12 Sep 2018 16:59:24 -0400 Subject: [PATCH] fix #25474, support more forms in edit, which, etc. macros --- stdlib/InteractiveUtils/src/macros.jl | 48 +++++++++++++++++++----- stdlib/InteractiveUtils/test/runtests.jl | 25 ++++++------ 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/stdlib/InteractiveUtils/src/macros.jl b/stdlib/InteractiveUtils/src/macros.jl index 1d13e7020a3e1..6415bb68c64af 100644 --- a/stdlib/InteractiveUtils/src/macros.jl +++ b/stdlib/InteractiveUtils/src/macros.jl @@ -15,22 +15,50 @@ function gen_call_with_extracted_types(__module__, fcn, ex0) $(fcn)(Core.kwfunc(arg1), Tuple{typeof(kwargs), Core.Typeof(arg1), map(Core.Typeof, args)...}) end - elseif ex0.head == :call + elseif ex0.head === :call return Expr(:call, fcn, esc(ex0.args[1]), Expr(:call, typesof, map(esc, ex0.args[2:end])...)) - elseif ex0.head == :(=) && length(ex0.args) == 2 && ex0.args[1].head == :(.) - return Expr(:call, fcn, Base.setproperty!, - Expr(:call, typesof, map(esc, [ex0.args[1].args..., ex0.args[2]])...)) + elseif ex0.head === :(=) && length(ex0.args) == 2 + lhs, rhs = ex0.args + if isa(lhs, Expr) + if lhs.head === :(.) + return Expr(:call, fcn, Base.setproperty!, + Expr(:call, typesof, map(esc, lhs.args)..., esc(rhs))) + elseif lhs.head === :ref + return Expr(:call, fcn, Base.setindex!, + Expr(:call, typesof, esc(lhs.args[1]), esc(rhs), map(esc, lhs.args[2:end])...)) + end + end + elseif ex0.head === :vcat || ex0.head === :typed_vcat + if ex0.head === :vcat + f, hf = Base.vcat, Base.hvcat + args = ex0.args + else + f, hf = Base.typed_vcat, Base.typed_hvcat + args = ex0.args[2:end] + end + if any(a->isa(a,Expr) && a.head === :row, args) + rows = Any[ (isa(x,Expr) && x.head === :row ? x.args : Any[x]) for x in args ] + lens = map(length, rows) + return Expr(:call, fcn, hf, + Expr(:call, typesof, + (ex0.head === :vcat ? [] : Any[esc(ex0.args[1])])..., + Expr(:tuple, lens...), + map(esc, vcat(rows...))...)) + else + return Expr(:call, fcn, f, + Expr(:call, typesof, map(esc, ex0.args)...)) + end else - for (head, f) in (:ref => Base.getindex, :vcat => Base.vcat, :hcat => Base.hcat, :(.) => Base.getproperty, :vect => Base.vect) - if ex0.head == head + for (head, f) in (:ref => Base.getindex, :hcat => Base.hcat, :(.) => Base.getproperty, :vect => Base.vect, Symbol("'") => Base.adjoint, :typed_hcat => Base.typed_hcat, :string => string) + if ex0.head === head return Expr(:call, fcn, f, Expr(:call, typesof, map(esc, ex0.args)...)) end end end end - if isa(ex0, Expr) && ex0.head == :macrocall # Make @edit @time 1+2 edit the macro by using the types of the *expressions* + if isa(ex0, Expr) && ex0.head === :macrocall # Make @edit @time 1+2 edit the macro by using the types of the *expressions* return Expr(:call, fcn, esc(ex0.args[1]), Tuple{#=__source__=#LineNumberNode, #=__module__=#Module, Any[ Core.Typeof(a) for a in ex0.args[3:end] ]...}) end @@ -40,8 +68,8 @@ function gen_call_with_extracted_types(__module__, fcn, ex0) end exret = Expr(:none) - if ex.head == :call - if any(e->(isa(e, Expr) && e.head==:(...)), ex0.args) && + if ex.head === :call + if any(e->(isa(e, Expr) && e.head === :(...)), ex0.args) && (ex.args[1] === GlobalRef(Core,:_apply) || ex.args[1] === GlobalRef(Base,:_apply)) # check for splatting @@ -53,7 +81,7 @@ function gen_call_with_extracted_types(__module__, fcn, ex0) Expr(:call, typesof, map(esc, ex.args[2:end])...)) end end - if ex.head == :thunk || exret.head == :none + if 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") diff --git a/stdlib/InteractiveUtils/test/runtests.jl b/stdlib/InteractiveUtils/test/runtests.jl index 14a5068c36c6d..3e522ce24a54e 100644 --- a/stdlib/InteractiveUtils/test/runtests.jl +++ b/stdlib/InteractiveUtils/test/runtests.jl @@ -198,20 +198,23 @@ const curmod_str = curmod === Main ? "Main" : join(curmod_name, ".") # issue #13264 @test (@which vcat(1...)).name == :vcat -# PR #28122 +# PR #28122, issue #25474 @test (@which [1][1]).name === :getindex -@test (@which [1 2]).name == :hcat -@test (@which [1; 2]).name == :vcat -@test (@which [1]).name == :vect +@test (@which [1][1] = 2).name === :setindex! +@test (@which [1]).name === :vect +@test (@which [1 2]).name === :hcat +@test (@which [1; 2]).name === :vcat +@test (@which Int[1 2]).name === :typed_hcat +@test (@which Int[1; 2]).name === :typed_vcat +@test (@which [1 2;3 4]).name === :hvcat +@test (@which Int[1 2;3 4]).name === :typed_hvcat # issue #13464 -let t13464 = "hey there sailor" - try - @which t13464[1,1] = (1.0,true) - error("unexpected") - catch err13464 - @test startswith(err13464.msg, "expression is not a function call, or is too complex") - end +try + @which x = 1 + error("unexpected") +catch err13464 + @test startswith(err13464.msg, "expression is not a function call, or is too complex") end module MacroTest