Skip to content

Commit

Permalink
allow passing a module to methods (#33403)
Browse files Browse the repository at this point in the history
* allow passing a module to methods

* add missing `=nothing` (ararslan)

Co-Authored-By: Alex Arslan <[email protected]>

* allow specifying multiple modules

* add NEWS and compat annotations

* use `nothing` instead of `()` as a default value
  • Loading branch information
rfourquet authored and KristofferC committed Apr 11, 2020
1 parent 3aa7bca commit c034812
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 7 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,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
Expand Down
26 changes: 19 additions & 7 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -862,19 +862,29 @@ 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.
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))
function methods(@nospecialize(f), @nospecialize(t),
@nospecialize(mod::Union{Module,AbstractArray{Module},Tuple{Vararg{Module}},Nothing}=nothing))
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)
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 in mod],
typeof(f).name.mt)
end

methods(f::Core.Builtin) = MethodList(Method[], typeof(f).name.mt)
Expand All @@ -887,9 +897,11 @@ 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),
@nospecialize(mod::Union{Module,AbstractArray{Module},Tuple{Vararg{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)
Expand Down
27 changes: 27 additions & 0 deletions test/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit c034812

Please sign in to comment.