Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a keyword name checking method to hasmethod #30712

Merged
merged 1 commit into from
Jan 25, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add a keyword name checking method to hasmethod
With this change, `hasmethod` now accepts a tuple of symbols
corresponding to keyword argument names to check for when finding a
matching method.
ararslan committed Jan 18, 2019

Verified

This commit was signed with the committer’s verified signature.
ararslan Alex Arslan
commit f7ece4dae54c04e99fdab96eb22f52d73d0504a8
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ New language features

* The `extrema` function now accepts a function argument in the same manner as `minimum` and
`maximum` ([#30323]).
* `hasmethod` can now check for matching keyword argument names ([#30712]).

Multi-threading changes
-----------------------
34 changes: 33 additions & 1 deletion base/reflection.jl
Original file line number Diff line number Diff line change
@@ -1084,17 +1084,37 @@ function parentmodule(@nospecialize(f), @nospecialize(types))
end

"""
hasmethod(f, Tuple type; world = typemax(UInt)) -> Bool
hasmethod(f, t::Type{<:Tuple}[, kwnames]; world=typemax(UInt)) -> Bool

Determine whether the given generic function has a method matching the given
`Tuple` of argument types with the upper bound of world age given by `world`.

If a tuple of keyword argument names `kwnames` is provided, this also checks
whether the method of `f` matching `t` has the given keyword argument names.
If the matching method accepts a variable number of keyword arguments, e.g.
with `kwargs...`, any names given in `kwnames` are considered valid. Otherwise
the provided names must be a subset of the method's keyword arguments.

See also [`applicable`](@ref).

!!! compat "Julia 1.2"
Providing keyword argument names requires Julia 1.2 or later.

# Examples
```jldoctest
julia> hasmethod(length, Tuple{Array})
true

julia> hasmethod(sum, Tuple{Function, Array}, (:dims,))
true

julia> hasmethod(sum, Tuple{Function, Array}, (:apples, :bananas))
false

julia> g(; xs...) = 4;

julia> hasmethod(g, Tuple{}, (:a, :b, :c, :d)) # g accepts arbitrary kwargs
true
```
"""
function hasmethod(@nospecialize(f), @nospecialize(t); world = typemax(UInt))
@@ -1103,6 +1123,18 @@ function hasmethod(@nospecialize(f), @nospecialize(t); world = typemax(UInt))
return ccall(:jl_method_exists, Cint, (Any, Any, UInt), typeof(f).name.mt, t, world) != 0
end

function hasmethod(@nospecialize(f), @nospecialize(t), kwnames::Tuple{Vararg{Symbol}}; world=typemax(UInt))
hasmethod(f, t, world=world) || return false
isempty(kwnames) && return true
m = which(f, t)
max_world(m) <= world || return false
kws = kwarg_decl(m, Core.kwftype(typeof(f)))
for kw in kws
endswith(String(kw), "...") && return true
end
issubset(kwnames, kws)
end

"""
isambiguous(m1, m2; ambiguous_bottom=false) -> Bool

21 changes: 21 additions & 0 deletions test/reflection.jl
Original file line number Diff line number Diff line change
@@ -796,6 +796,27 @@ Base.delete_method(m)

end

module HasmethodKwargs
using Test
f(x::Int; y=3) = x + y
@test hasmethod(f, Tuple{Int})
@test hasmethod(f, Tuple{Int}, ())
@test hasmethod(f, Tuple{Int}, (:y,))
@test !hasmethod(f, Tuple{Int}, (:jeff,))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😹

@test !hasmethod(f, Tuple{Int}, (:y,), world=typemin(UInt))
g(; b, c, a) = a + b + c
h(; kwargs...) = 4
for gh = (g, h)
@test hasmethod(gh, Tuple{})
@test hasmethod(gh, Tuple{}, ())
@test hasmethod(gh, Tuple{}, (:a,))
@test hasmethod(gh, Tuple{}, (:a, :b))
@test hasmethod(gh, Tuple{}, (:a, :b, :c))
end
@test !hasmethod(g, Tuple{}, (:a, :b, :c, :d))
@test hasmethod(h, Tuple{}, (:a, :b, :c, :d))
end

# issue #26267
module M26267
import Test