Skip to content

Commit

Permalink
make ml_matches return nothing when there are too many matches
Browse files Browse the repository at this point in the history
Continuation from <#44448 (comment)>.
Previously `ml_matches` (and its dependent utilities like `_methods_by_ftype`)
returned `false` for cases when there are too many matching method, but
its consumer like `findall(::Type, ::InternalMethodTable)` usually handles
such case as `missing`. This commit does a refactor so that they all use
the more consistent value `nothing` for representing that case.
  • Loading branch information
aviatesk committed Mar 7, 2022
1 parent 9a48dc1 commit 35c07f1
Show file tree
Hide file tree
Showing 7 changed files with 21 additions and 22 deletions.
4 changes: 2 additions & 2 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth
mt === nothing && return FailedMethodMatch("Could not identify method table for call")
mt = mt::Core.MethodTable
matches = findall(sig_n, method_table; limit = max_methods)
if matches === missing
if matches === nothing
return FailedMethodMatch("For one of the union split cases, too many methods matched")
end
push!(infos, MethodMatchInfo(matches))
Expand Down Expand Up @@ -296,7 +296,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth
end
mt = mt::Core.MethodTable
matches = findall(atype, method_table; limit = max_methods)
if matches === missing
if matches === nothing
# this means too many methods matched
# (assume this will always be true, so we don't compute / update valid age in this case)
return FailedMethodMatch("Too many methods matched")
Expand Down
3 changes: 2 additions & 1 deletion base/compiler/bootstrap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ let
else
tt = Tuple{typeof(f), Vararg{Any}}
end
for m in _methods_by_ftype(tt, 10, typemax(UInt))
for m in _methods_by_ftype(tt, 10, typemax(UInt))::Vector{Any}
# remove any TypeVars from the intersection
m = m::MethodMatch
typ = Any[m.spec_types.parameters...]
for i = 1:length(typ)
typ[i] = unwraptv(typ[i])
Expand Down
12 changes: 5 additions & 7 deletions base/compiler/methodtable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,20 @@ end
getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch

"""
findall(sig::Type, view::MethodTableView; limit::Int=typemax(Int)) -> MethodLookupResult or missing
findall(sig::Type, view::MethodTableView; limit::Int=typemax(Int)) -> MethodLookupResult or nothing
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.
`nothing` is returned.
"""
function findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=typemax(Int))
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
result === nothing && return nothing
if !isempty(result)
if all(match->match.fully_covers, result)
# no need to fall back to the internal method table
Expand All @@ -77,10 +77,8 @@ function _findall(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable},
_max_val = RefValue{UInt}(typemax(UInt))
_ambig = RefValue{Int32}(0)
ms = _methods_by_ftype(sig, mt, limit, 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)
isa(ms, Vector) || return nothing
return MethodLookupResult(ms, WorldRange(_min_val[], _max_val[]), _ambig[] != 0)
end

"""
Expand Down
2 changes: 1 addition & 1 deletion base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ function _methods_by_ftype(@nospecialize(t), mt::Union{Core.MethodTable, Nothing
return _methods_by_ftype(t, mt, lim, world, false, RefValue{UInt}(typemin(UInt)), RefValue{UInt}(typemax(UInt)), Ptr{Int32}(C_NULL))
end
function _methods_by_ftype(@nospecialize(t), mt::Union{Core.MethodTable, Nothing}, lim::Int, world::UInt, ambig::Bool, min::Ref{UInt}, max::Ref{UInt}, has_ambig::Ref{Int32})
return ccall(:jl_matching_methods, Any, (Any, Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}, Ptr{Int32}), t, mt, lim, ambig, world, min, max, has_ambig)::Union{Array{Any,1}, Bool}
return ccall(:jl_matching_methods, Any, (Any, Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}, Ptr{Int32}), t, mt, lim, ambig, world, min, max, has_ambig)::Union{Vector{Any},Nothing}
end

# high-level, more convenient method lookup functions
Expand Down
4 changes: 2 additions & 2 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,7 @@ static void jl_collect_backedges( /* edges */ jl_array_t *s, /* ext_targets */ j
size_t max_valid = ~(size_t)0;
int ambig = 0;
jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, jl_nothing, -1, 0, jl_atomic_load_acquire(&jl_world_counter), &min_valid, &max_valid, &ambig);
if (matches == jl_false) {
if (matches == jl_nothing) {
valid = 0;
break;
}
Expand Down Expand Up @@ -2339,7 +2339,7 @@ static void jl_verify_edges(jl_array_t *targets, jl_array_t **pvalids)
int ambig = 0;
// TODO: possibly need to included ambiguities too (for the optimizer correctness)?
jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, jl_nothing, -1, 0, jl_atomic_load_acquire(&jl_world_counter), &min_valid, &max_valid, &ambig);
if (matches == jl_false || jl_array_len(matches) != jl_array_len(expected)) {
if (matches == jl_nothing || jl_array_len(matches) != jl_array_len(expected)) {
valid = 0;
}
else {
Expand Down
14 changes: 7 additions & 7 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,7 @@ static jl_method_instance_t *cache_method(
size_t max_valid2 = ~(size_t)0;
temp = ml_matches(mt, compilationsig, MAX_UNSPECIALIZED_CONFLICTS, 1, 1, world, 0, &min_valid2, &max_valid2, NULL);
int guards = 0;
if (temp == jl_false) {
if (temp == jl_nothing) {
cache_with_orig = 1;
}
else {
Expand Down Expand Up @@ -2559,7 +2559,7 @@ static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT
if (mt == jl_nothing)
mt = NULL;
jl_value_t *matches = ml_matches((jl_methtable_t*)mt, (jl_tupletype_t*)types, 1, 0, 0, world, 1, min_valid, max_valid, NULL);
if (matches == jl_false || jl_array_len(matches) != 1)
if (matches == jl_nothing || jl_array_len(matches) != 1)
return NULL;
jl_method_match_t *matc = (jl_method_match_t*)jl_array_ptr_ref(matches, 0);
return matc;
Expand Down Expand Up @@ -2887,14 +2887,14 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
}
if (!jl_typemap_intersection_visitor(mt->defs, 0, &env.match)) {
JL_GC_POP();
return jl_false;
return jl_nothing;
}
}
else {
// else: scan everything
if (!jl_foreach_reachable_mtable(ml_mtable_visitor, &env.match)) {
JL_GC_POP();
return jl_false;
return jl_nothing;
}
}
*min_valid = env.min_valid;
Expand Down Expand Up @@ -2976,7 +2976,7 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
}
else if (lim == 1) {
JL_GC_POP();
return jl_false;
return jl_nothing;
}
}
else {
Expand Down Expand Up @@ -3120,7 +3120,7 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
ndisjoint += 1;
if (ndisjoint > lim) {
JL_GC_POP();
return jl_false;
return jl_nothing;
}
}
}
Expand Down Expand Up @@ -3271,7 +3271,7 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
*ambig = has_ambiguity;
JL_GC_POP();
if (lim >= 0 && len > lim)
return jl_false;
return jl_nothing;
return env.t;
}

Expand Down
4 changes: 2 additions & 2 deletions stdlib/REPL/src/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -613,10 +613,10 @@ function complete_methods!(out::Vector{Completion}, @nospecialize(funct), args_e
t_in = Tuple{funct, args_ex...}
m = Base._methods_by_ftype(t_in, nothing, max_method_completions, Base.get_world_counter(),
#=ambig=# true, Ref(typemin(UInt)), Ref(typemax(UInt)), Ptr{Int32}(C_NULL))
if m === false
if !isa(m, Vector)
push!(out, TextCompletion(sprint(Base.show_signature_function, funct) * "( too many methods to show )"))
return
end
m isa Vector || return
for match in m
# TODO: if kwargs_ex, filter out methods without kwargs?
push!(out, MethodCompletion(match.spec_types, match.method))
Expand Down

0 comments on commit 35c07f1

Please sign in to comment.