Skip to content

Commit

Permalink
Merge pull request #180 from timholy/teh/methdel_union
Browse files Browse the repository at this point in the history
Swap the order of deletion and evaluation
  • Loading branch information
timholy authored Sep 5, 2018
2 parents 2f8b937 + e2237b0 commit ee2a6c6
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 37 deletions.
75 changes: 42 additions & 33 deletions src/Revise.jl
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,28 @@ function eval_revised!(fmmrep::FMMaps, mod::Module,
# Update to the state of fmmnew, preventing any unnecessary evaluation
with_logger(_debug_logger) do
@debug "Diff" _group="Parsing" activemodule=fullname(mod) newexprs=setdiff(keys(fmmnew.defmap), keys(fmmref.defmap)) oldexprs=setdiff(keys(fmmref.defmap), keys(fmmnew.defmap))
# Delete any methods missing in fmmnew
# Because we haven't yet evaled and gotten signature types, let's do this "from scratch" using method signatures.
# (It might be more efficient to eval first and delete later, but this proves to be safer.)
oldsigs, newsigs = filter_signatures(mod, keys(fmmref.defmap)), filter_signatures(mod, keys(fmmnew.defmap))
for sig in oldsigs
sig newsigs && continue
for sigt in sigex2sigts(mod, sig)
m = get_method(sigt)
if isa(m, Method)
Base.delete_method(m)
@debug "DeleteMethod" _group="Action" time=time() deltainfo=(sigt, MethodSummary(m))
else
mths = Base._methods_by_ftype(sigt, -1, typemax(UInt))
io = IOBuffer()
println(io, "Extracted method table:")
println(io, mths)
info = String(take!(io))
@warn "Revise failed to find any methods for signature $sigt\n Perhaps it was already deleted.\n$info"
end
end
end
# Eval any expressions unique to fmmnew
for (def,val) in fmmnew.defmap
@assert def != nothing
defref = getkey(fmmref.defmap, def, nothing)
Expand All @@ -234,27 +256,29 @@ function eval_revised!(fmmrep::FMMaps, mod::Module,
eval_and_insert!(fmmrep, mod, def=>val)
end
end
# Delete any methods missing in fmmnew
for (sigt,_) in fmmref.sigtmap
if !haskey(fmmrep.sigtmap, sigt)
m = get_method(sigt)
if isa(m, Method)
Base.delete_method(m)
@debug "DeleteMethod" _group="Action" time=time() deltainfo=(sigt, MethodSummary(m))
else
mths = Base._methods_by_ftype(sigt, -1, typemax(UInt))
io = IOBuffer()
println(io, "Extracted method table:")
println(io, mths)
info = String(take!(io))
@warn "Revise failed to find any methods for signature $sigt\n Perhaps it was already deleted.\n$info"
end
end
end
end
return fmmrep
end

function filter_signatures(mod::Module, defs)
sigs = Set{Expr}()
for def in defs
while is_trivial_block_wrapper(def)
def = def.args[end]
end
def isa ExLike || continue
if def.head == :macrocall
_, def = macexpand(mod, convert(Expr, def))
def isa ExLike || continue
end
def.head == :function || def.head == :(=) || continue
sig = get_signature(def)
sig isa ExLike || continue
push!(sigs, convert(Expr, sig))
end
return sigs
end

eval_revised_dummy!(mod::Module, fmmnew::FMMaps, fmmref::FMMaps) =
eval_revised!(FMMaps(), mod, fmmnew, fmmref)

Expand Down Expand Up @@ -413,29 +437,14 @@ function instantiate_sigs!(fmm::FMMaps, mod::Module)
end

function instantiate_sigs!(fmm::FMMaps, def::RelocatableExpr, sig::RelocatableExpr, mod::Module)
# Generate the signature-types
local sigtexs
try
sigtexs = sig_type_exprs(mod, sig)
catch err
sigwarn(mod, sig, def)
rethrow(err)
end
local sigts
try
sigts = Any[Core.eval(mod, s) for s in sigtexs]
catch err
sigwarn(mod, sigtexs, def)
rethrow(err)
end
sigts = sigex2sigts(mod, sig, def)
# Insert into the maps
fmm.defmap[def] = (sigts, 0)
for sigt in sigts
fmm.sigtmap[sigt] = def
end
return def
end
@noinline sigwarn(mod, sigtexs, def) = @warn "error processing module $mod signature expressions $sigtexs from $def"

"""
revise()
Expand Down
23 changes: 23 additions & 0 deletions src/exprutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,29 @@ function get_signature(ex::E) where E <: ExLike
nothing
end

@noinline sigwarn(mod, sigtexs, def) = @warn "error processing module $mod signature expressions $sigtexs from $def"
@noinline sigwarn(mod, sigtexs, ::Nothing) = @warn "error processing module $mod signature expressions $sigtexs"

function sigex2sigts(mod::Module, sig::ExLike, def=nothing)
# Generate the signature-types
local sigtexs
try
sigtexs = sig_type_exprs(sig)
catch err
sigwarn(mod, sig, def)
rethrow(err)
end
local sigts
try
sigts = Any[Core.eval(mod, s) for s in sigtexs]
catch err
sigwarn(mod, sigtexs, def)
rethrow(err)
end
return sigts
end


"""
callex = get_callexpr(sigex::ExLike)
Expand Down
39 changes: 35 additions & 4 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,10 @@ k(x) = 4
@test length(logs) == 6
cmpdiff(logs[1], "Eval"; deltainfo=(ReviseTest, Revise.relocatable!(:(cube(x) = x^3))))
cmpdiff(logs[2], "Eval"; deltainfo=(ReviseTest, Revise.relocatable!(:(fourth(x) = x^4))))
cmpdiff(logs[3], "LineOffset"; deltainfo=(Any[Tuple{typeof(ReviseTest.Internal.mult2),Any}], 13, 0 => 2))
cmpdiff(logs[4], "Eval"; deltainfo=(ReviseTest.Internal, Revise.relocatable!(:(mult3(x) = 3*x))))
cmpdiff(logs[5], "LineOffset"; deltainfo=(Any[Tuple{typeof(ReviseTest.Internal.unchanged),Any}], 19, 0 => 1))
cmpdiff(logs[6], "DeleteMethod"; deltainfo=(Tuple{typeof(ReviseTest.Internal.mult4),Any}, MethodSummary(delmeth)))
cmpdiff(logs[3], "DeleteMethod"; deltainfo=(Tuple{typeof(ReviseTest.Internal.mult4),Any}, MethodSummary(delmeth)))
cmpdiff(logs[4], "LineOffset"; deltainfo=(Any[Tuple{typeof(ReviseTest.Internal.mult2),Any}], 13, 0 => 2))
cmpdiff(logs[5], "Eval"; deltainfo=(ReviseTest.Internal, Revise.relocatable!(:(mult3(x) = 3*x))))
cmpdiff(logs[6], "LineOffset"; deltainfo=(Any[Tuple{typeof(ReviseTest.Internal.unchanged),Any}], 19, 0 => 1))
@test length(Revise.actions(rlogger)) == 4 # by default LineOffset is skipped
@test length(Revise.actions(rlogger; line=true)) == 6
@test length(Revise.diffs(rlogger)) == 2
Expand Down Expand Up @@ -1061,6 +1061,16 @@ hasmacro3(@nospecialize(x::Int), y::Float64) = x
hasdestructure1(x, (count, name)) = name^count
hasdestructure2(x, (count, name)::Tuple{Int,Any}) = name^count
struct A end
struct B end
checkunion(a::Union{Nothing, A}) = 1
methgensym(::Vector{<:Integer}) = 1
mapf(fs, x) = (fs[1](x), mapf(Base.tail(fs), x)...)
mapf(::Tuple{}, x) = ()
end
""")
end
Expand All @@ -1084,6 +1094,10 @@ end
@test MethDel.dfltargs(Int8(2)) == 3.0f0
@test MethDel.dfltargs(Int8(2), 5) == 8.0f0
@test MethDel.dfltargs(Int8(2), 5, -17.0f0) == -10.0f0
@test MethDel.checkunion(nothing) == 1
@test MethDel.methgensym([1]) == 1
@test_throws MethodError MethDel.methgensym([1.0])
@test MethDel.mapf((x->x+1, x->x+0.1), 3) == (4, 3.1)
sleep(0.1) # ensure watching is set up
open(joinpath(dn, "MethDel.jl"), "w") do io
println(io, """
Expand All @@ -1093,6 +1107,17 @@ g(x::Array{T,N}, y::T) where N where T = 2
h(x::Array{T}, y::T) where T = g(x, y)
k(::Int; goodchoice=-1) = goodchoice
dfltargs(x::Int8, yz::Tuple{Int,Float32}=(0,1.0f0)) = x+yz[1]+yz[2]
struct A end
struct B end
checkunion(a::Union{Nothing, B}) = 2
methgensym(::Vector{<:Real}) = 1
mapf(fs::F, x) where F = (fs[1](x), mapf(Base.tail(fs), x)...)
mapf(::Tuple{}, x) = ()
end
""")
end
Expand All @@ -1118,6 +1143,12 @@ end
@test MethDel.dfltargs(Int8(2), (5,-17.0f0)) == -10.0f0
@test_throws MethodError MethDel.dfltargs(Int8(2), 5) == 8.0f0
@test_throws MethodError MethDel.dfltargs(Int8(2), 5, -17.0f0) == -10.0f0
@test MethDel.checkunion(nothing) == 2
@test MethDel.methgensym([1]) == 1
@test MethDel.methgensym([1.0]) == 1
@test length(methods(MethDel.methgensym)) == 1
@test MethDel.mapf((x->x+1, x->x+0.1), 3) == (4, 3.1)
@test length(methods(MethDel.mapf)) == 2

Base.delete_method(first(methods(Base.revisefoo)))
end
Expand Down

0 comments on commit ee2a6c6

Please sign in to comment.