-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
AbstractInterpreter
: implement findsup
for OverlayMethodTable
#44448
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,45 +40,51 @@ end | |
getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch | ||
|
||
""" | ||
findall(sig::Type, view::MethodTableView; limit=typemax(Int)) | ||
findall(sig::Type, view::MethodTableView; limit::Int=typemax(Int)) -> MethodLookupResult or missing | ||
|
||
Find all methods in the given method table `view` that are applicable to the | ||
given signature `sig`. If no applicable methods are found, an empty result is | ||
returned. If the number of applicable methods exceeded the specified limit, | ||
`missing` is returned. | ||
""" | ||
function findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=typemax(Int)) | ||
_min_val = RefValue{UInt}(typemin(UInt)) | ||
_max_val = RefValue{UInt}(typemax(UInt)) | ||
_ambig = RefValue{Int32}(0) | ||
ms = _methods_by_ftype(sig, nothing, limit, table.world, false, _min_val, _max_val, _ambig) | ||
if ms === false | ||
return missing | ||
end | ||
return MethodLookupResult(ms::Vector{Any}, WorldRange(_min_val[], _max_val[]), _ambig[] != 0) | ||
return _findall(sig, nothing, table.world, limit) | ||
end | ||
|
||
function findall(@nospecialize(sig::Type), table::OverlayMethodTable; limit::Int=typemax(Int)) | ||
result = _findall(sig, table.mt, table.world, limit) | ||
result === missing && return missing | ||
if !isempty(result) | ||
if all(match->match.fully_covers, result) | ||
# no need to fall back to the internal method table | ||
return result | ||
else | ||
# merge the match results with the internal method table | ||
fallback_result = _findall(sig, nothing, table.world, limit) | ||
return MethodLookupResult( | ||
vcat(result.matches, fallback_result.matches), | ||
WorldRange(min(result.valid_worlds.min_world, fallback_result.valid_worlds.min_world), | ||
max(result.valid_worlds.max_world, fallback_result.valid_worlds.max_world)), | ||
Comment on lines
+66
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you need the max of the min_worlds and the min of the max_worlds |
||
result.ambig | fallback_result.ambig) | ||
end | ||
end | ||
# fall back to the internal method table | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even if the result is empty, you are still required to return the |
||
return _findall(sig, nothing, table.world, limit) | ||
end | ||
|
||
function _findall(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, world::UInt, limit::Int) | ||
_min_val = RefValue{UInt}(typemin(UInt)) | ||
_max_val = RefValue{UInt}(typemax(UInt)) | ||
_ambig = RefValue{Int32}(0) | ||
ms = _methods_by_ftype(sig, table.mt, limit, table.world, false, _min_val, _max_val, _ambig) | ||
ms = _methods_by_ftype(sig, mt, limit, world, false, _min_val, _max_val, _ambig) | ||
if ms === false | ||
return missing | ||
elseif isempty(ms) | ||
# fall back to the internal method table | ||
_min_val[] = typemin(UInt) | ||
_max_val[] = typemax(UInt) | ||
ms = _methods_by_ftype(sig, nothing, limit, table.world, false, _min_val, _max_val, _ambig) | ||
if ms === false | ||
return missing | ||
end | ||
end | ||
return MethodLookupResult(ms::Vector{Any}, WorldRange(_min_val[], _max_val[]), _ambig[] != 0) | ||
end | ||
|
||
""" | ||
findsup(sig::Type, view::MethodTableView)::Union{Tuple{MethodMatch, WorldRange}, Nothing} | ||
findsup(sig::Type, view::MethodTableView) -> Tuple{MethodMatch, WorldRange} or nothing | ||
|
||
Find the (unique) method `m` such that `sig <: m.sig`, while being more | ||
specific than any other method with the same property. In other words, find | ||
|
@@ -92,12 +98,21 @@ upper bound of `sig`, or it is possible that among the upper bounds, there | |
is no least element. In both cases `nothing` is returned. | ||
""" | ||
function findsup(@nospecialize(sig::Type), table::InternalMethodTable) | ||
return _findsup(sig, nothing, table.world) | ||
end | ||
|
||
function findsup(@nospecialize(sig::Type), table::OverlayMethodTable) | ||
result = _findsup(sig, table.mt, table.world) | ||
result === nothing || return result | ||
return _findsup(sig, nothing, table.world) # fall back to the internal method table | ||
end | ||
|
||
function _findsup(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, world::UInt) | ||
min_valid = RefValue{UInt}(typemin(UInt)) | ||
max_valid = RefValue{UInt}(typemax(UInt)) | ||
result = ccall(:jl_gf_invoke_lookup_worlds, Any, (Any, UInt, Ptr{Csize_t}, Ptr{Csize_t}), | ||
sig, table.world, min_valid, max_valid)::Union{MethodMatch, Nothing} | ||
result === nothing && return nothing | ||
(result.method, WorldRange(min_valid[], max_valid[])) | ||
result = ccall(:jl_gf_invoke_lookup_worlds, Any, (Any, Any, UInt, Ptr{Csize_t}, Ptr{Csize_t}), | ||
sig, mt, world, min_valid, max_valid)::Union{MethodMatch, Nothing} | ||
return result === nothing ? result : (result, WorldRange(min_valid[], max_valid[])) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is conservatively correct currently (since we return |
||
end | ||
|
||
isoverlayed(::MethodTableView) = error("unsatisfied MethodTableView interface") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It only matters if
result[end].fully_covers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me check my understanding.
We can just look at
result[end].fully_covers
since:jl_matching_methods
returns matching methods in order of speciality(and so the last match is always the most general case)
fully_covers
, it means this call is assured to bedispatched to the last match when it's not dispatched with the other matches