From 4b0c3e4cbf9fdb6bdb180535a7c995b140077ecb Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Fri, 27 Sep 2019 16:29:56 +0200 Subject: [PATCH 1/5] allow passing a module to methods --- base/reflection.jl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index ae38fb1e78537..437309fa3b381 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -862,19 +862,21 @@ function MethodList(mt::Core.MethodTable) end """ - methods(f, [types]) + methods(f, [types], [module]) -Returns the method table for `f`. +Return the method table for `f`. -If `types` is specified, returns an array of methods whose types match. +If `types` is specified, return an array of methods whose types match. +If `module` is specified, return an array of methods defined in this module. """ -function methods(@nospecialize(f), @nospecialize(t)) +function methods(@nospecialize(f), @nospecialize(t), mod::Union{Module,Nothing}) if isa(f, Core.Builtin) throw(ArgumentError("argument is not a generic function")) end t = to_tuple_type(t) world = typemax(UInt) - return MethodList(Method[m[3] for m in _methods(f, t, -1, world)], typeof(f).name.mt) + MethodList(Method[m[3] for m in _methods(f, t, -1, world) if mod === nothing || m[3].module == mod], + typeof(f).name.mt) end methods(f::Core.Builtin) = MethodList(Method[], typeof(f).name.mt) @@ -887,9 +889,10 @@ function methods_including_ambiguous(@nospecialize(f), @nospecialize(t)) ms = ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}), tt, -1, 1, world, min, max)::Array{Any,1} return MethodList(Method[m[3] for m in ms], typeof(f).name.mt) end -function methods(@nospecialize(f)) + +function methods(@nospecialize(f), mod::Union{Module,Nothing}=nothing) # return all matches - return methods(f, Tuple{Vararg{Any}}) + return methods(f, Tuple{Vararg{Any}}, mod) end function visit(f, mt::Core.MethodTable) From 38527a8a47ccd6865cebb51f9faa36f4887edb8b Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Mon, 30 Sep 2019 10:22:23 +0200 Subject: [PATCH 2/5] add missing `=nothing` (ararslan) Co-Authored-By: Alex Arslan --- base/reflection.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/reflection.jl b/base/reflection.jl index 437309fa3b381..63a1ffc306e9a 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -869,7 +869,7 @@ Return the method table for `f`. If `types` is specified, return an array of methods whose types match. If `module` is specified, return an array of methods defined in this module. """ -function methods(@nospecialize(f), @nospecialize(t), mod::Union{Module,Nothing}) +function methods(@nospecialize(f), @nospecialize(t), mod::Union{Module,Nothing}=nothing) if isa(f, Core.Builtin) throw(ArgumentError("argument is not a generic function")) end From 2583ccb0ea8c18160670d56bc10bfea6fe242e47 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Mon, 28 Oct 2019 18:30:10 +0100 Subject: [PATCH 3/5] allow specifying multiple modules --- base/reflection.jl | 12 +++++++++--- test/reflection.jl | 27 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index 63a1ffc306e9a..781b263fc7a7e 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -868,14 +868,19 @@ Return the method table for `f`. If `types` is specified, return an array of methods whose types match. If `module` is specified, return an array of methods defined in this module. +A list of modules can also be specified as an array or tuple. """ -function methods(@nospecialize(f), @nospecialize(t), mod::Union{Module,Nothing}=nothing) +function methods(@nospecialize(f), @nospecialize(t), + @nospecialize(mod::Union{Module,AbstractArray{Module},Tuple{Vararg{Module}}}=())) + if mod isa Module + mod = (mod,) + end if isa(f, Core.Builtin) throw(ArgumentError("argument is not a generic function")) end t = to_tuple_type(t) world = typemax(UInt) - MethodList(Method[m[3] for m in _methods(f, t, -1, world) if mod === nothing || m[3].module == mod], + MethodList(Method[m[3] for m in _methods(f, t, -1, world) if isempty(mod) || m[3].module in mod], typeof(f).name.mt) end @@ -890,7 +895,8 @@ function methods_including_ambiguous(@nospecialize(f), @nospecialize(t)) return MethodList(Method[m[3] for m in ms], typeof(f).name.mt) end -function methods(@nospecialize(f), mod::Union{Module,Nothing}=nothing) +function methods(@nospecialize(f), + @nospecialize(mod::Union{Module,AbstractArray{Module},Tuple{Vararg{Module}}}=())) # return all matches return methods(f, Tuple{Vararg{Any}}, mod) end diff --git a/test/reflection.jl b/test/reflection.jl index 306e66d651614..09592bbada17a 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -893,3 +893,30 @@ end @test nameof(:) === :Colon @test nameof(Core.Intrinsics.mul_int) === :mul_int @test nameof(Core.Intrinsics.arraylen) === :arraylen + +module TestMod33403 +f(x) = 1 +f(x::Int) = 2 + +module Sub +import ..TestMod33403: f +f(x::Char) = 3 +end +end + +@testset "methods with module" begin + using .TestMod33403: f + @test length(methods(f)) == 3 + @test length(methods(f, (Int,))) == 1 + + @test length(methods(f, TestMod33403)) == 2 + @test length(methods(f, (TestMod33403,))) == 2 + @test length(methods(f, [TestMod33403])) == 2 + @test length(methods(f, (Int,), TestMod33403)) == 1 + @test length(methods(f, (Int,), (TestMod33403,))) == 1 + + @test length(methods(f, TestMod33403.Sub)) == 1 + @test length(methods(f, (TestMod33403.Sub,))) == 1 + @test length(methods(f, (Char,), TestMod33403.Sub)) == 1 + @test length(methods(f, (Int,), TestMod33403.Sub)) == 0 +end From 69d9c045d42b81ce106f33e16b5b6f25c827fdb6 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Mon, 28 Oct 2019 18:50:39 +0100 Subject: [PATCH 4/5] add NEWS and compat annotations --- NEWS.md | 2 ++ base/reflection.jl | 3 +++ 2 files changed, 5 insertions(+) diff --git a/NEWS.md b/NEWS.md index a753fb9e7421d..76593a4fe5d53 100644 --- a/NEWS.md +++ b/NEWS.md @@ -52,6 +52,8 @@ Standard library changes * Sets are now displayed less compactly in the REPL, as a column of elements, like vectors and dictionaries ([#33300]). +* `methods` now accepts passing a module (or a list thereof) to filter methods defined in it ([#33403]). + #### Libdl #### LinearAlgebra diff --git a/base/reflection.jl b/base/reflection.jl index 781b263fc7a7e..eabc3cfcadd00 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -869,6 +869,9 @@ Return the method table for `f`. If `types` is specified, return an array of methods whose types match. If `module` is specified, return an array of methods defined in this module. A list of modules can also be specified as an array or tuple. + +!!! compat "Julia 1.4" + At least Julia 1.4 is required for specifying a module. """ function methods(@nospecialize(f), @nospecialize(t), @nospecialize(mod::Union{Module,AbstractArray{Module},Tuple{Vararg{Module}}}=())) From fe3bc37df7c88e8be724e74e6b04defc5b253068 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Sat, 16 Nov 2019 10:14:10 +0100 Subject: [PATCH 5/5] use `nothing` instead of `()` as a default value --- base/reflection.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index eabc3cfcadd00..42b5f11a505dc 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -874,7 +874,7 @@ A list of modules can also be specified as an array or tuple. At least Julia 1.4 is required for specifying a module. """ function methods(@nospecialize(f), @nospecialize(t), - @nospecialize(mod::Union{Module,AbstractArray{Module},Tuple{Vararg{Module}}}=())) + @nospecialize(mod::Union{Module,AbstractArray{Module},Tuple{Vararg{Module}},Nothing}=nothing)) if mod isa Module mod = (mod,) end @@ -883,7 +883,7 @@ function methods(@nospecialize(f), @nospecialize(t), end t = to_tuple_type(t) world = typemax(UInt) - MethodList(Method[m[3] for m in _methods(f, t, -1, world) if isempty(mod) || m[3].module in mod], + MethodList(Method[m[3] for m in _methods(f, t, -1, world) if mod === nothing || m[3].module in mod], typeof(f).name.mt) end @@ -899,7 +899,7 @@ function methods_including_ambiguous(@nospecialize(f), @nospecialize(t)) end function methods(@nospecialize(f), - @nospecialize(mod::Union{Module,AbstractArray{Module},Tuple{Vararg{Module}}}=())) + @nospecialize(mod::Union{Module,AbstractArray{Module},Tuple{Vararg{Module}},Nothing}=nothing)) # return all matches return methods(f, Tuple{Vararg{Any}}, mod) end