From 759b26b9a20e32ed3d4377c15066696e5c6ed148 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 2 Jan 2021 10:32:58 -0600 Subject: [PATCH] Add a convenience utility for locating the origin of methods This can be handy when trying to figure out where some `var"#31#32"` function was defined. --- src/Observables.jl | 20 ++++++++++++++++++++ test/runtests.jl | 28 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/Observables.jl b/src/Observables.jl index c1bfb44..afbaf43 100644 --- a/src/Observables.jl +++ b/src/Observables.jl @@ -439,4 +439,24 @@ include("flatten.jl") include("time.jl") include("macros.jl") +# Look up the source location of `do` block Observable MethodInstances +function methodlist(@nospecialize(ft::Type)) + if ft <: OnUpdate + ft = Base.unwrap_unionall(Base.unwrap_unionall(ft).parameters[1]) + if ft <: MapUpdater + ft = Base.unwrap_unionall(Base.unwrap_unionall(ft).parameters[1]) + end + end + mt = ft.name.mt + ms = Method[] + Base.visit(mt) do m + push!(ms, m) + end + return Base.MethodList(ms, mt) +end + +methodlist(mi::Core.MethodInstance) = methodlist(Base.unwrap_unionall(mi.specTypes).parameters[1]) +methodlist(obsf::ObserverFunction) = methodlist(obsf.f) +methodlist(@nospecialize(f::Function)) = methodlist(typeof(f)) + end # module diff --git a/test/runtests.jl b/test/runtests.jl index 4a62208..c3a762f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -336,3 +336,31 @@ end obs[] = 1 @test obs_copy[] == 1 end + +@testset "methodlist" begin + _only(list) = (@assert length(list) == 1; return list[1]) # `only` is avail in Julia 1.4+ + obs = Observable(1) + obsf = on(obs) do x + x + 1 + end + line1 = -2 + @__LINE__ + obs2 = map(obs) do x + x + 1 + end + line2 = -2 + @__LINE__ + obsflist = onany(obs, 5) do x, y + x + y + end + line3 = -2 + @__LINE__ + obsf2 = _only(obsflist) + m = _only(Observables.methodlist(obsf).ms) + @test occursin("runtests.jl:$line1", string(m)) + m = _only(Observables.methodlist(obsf.f).ms) + @test occursin("runtests.jl:$line1", string(m)) + m = _only(Observables.methodlist(obs.listeners[2]).ms) + @test occursin("runtests.jl:$line2", string(m)) + m = _only(Observables.methodlist(obsf2).ms) + @test occursin("runtests.jl:$line3", string(m)) + obsf3 = on(sqrt, obs) + @test Observables.methodlist(obsf3).mt.name === :sqrt +end