Skip to content

Commit 2cca0a4

Browse files
authored
Give MethodMatch its own type (#36702)
Every time I see any code dealing with the svecs we get back from the method match code, I think that it shouldn't really be an svec: 1. It's always the same length 2. Basically every use of it typeasserts the field type 3. Every use of it needs the same magic numbers to access the fields. All put together this should just be a type. This updates all the uses accordingly, but adds fallback getindex/iterate defintions for external users that expect this to be a SimpleVector (in deprecated.jl - hopefully by 2.0 all external users will upgraded).
1 parent 8f8604b commit 2cca0a4

File tree

22 files changed

+215
-155
lines changed

22 files changed

+215
-155
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
6464
end
6565
push!(infos, MethodMatchInfo(xapplicable, ambig))
6666
append!(applicable, xapplicable)
67-
thisfullmatch = _any(match->match[4], xapplicable)
67+
thisfullmatch = _any(match->(match::MethodMatch).fully_covers, xapplicable)
6868
found = false
6969
for (i, mt′) in enumerate(mts)
7070
if mt′ === mt
@@ -95,7 +95,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
9595
return CallMeta(Any, false)
9696
end
9797
push!(mts, mt)
98-
push!(fullmatch, _any(match->match[4], applicable))
98+
push!(fullmatch, _any(match->(match::MethodMatch).fully_covers, applicable))
9999
info = MethodMatchInfo(applicable, ambig)
100100
end
101101
update_valid_age!(min_valid[1], max_valid[1], sv)
@@ -109,17 +109,17 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
109109
istoplevel = sv.linfo.def isa Module
110110
multiple_matches = napplicable > 1
111111

112-
if f !== nothing && napplicable == 1 && is_method_pure(applicable[1][3], applicable[1][1], applicable[1][2])
112+
if f !== nothing && napplicable == 1 && is_method_pure(applicable[1]::MethodMatch)
113113
val = pure_eval_call(f, argtypes)
114114
if val !== false
115115
return CallMeta(val, info)
116116
end
117117
end
118118

119119
for i in 1:napplicable
120-
match = applicable[i]::SimpleVector
121-
method = match[3]::Method
122-
sig = match[1]
120+
match = applicable[i]::MethodMatch
121+
method = match.method
122+
sig = match.spec_types
123123
if istoplevel && !isdispatchtuple(sig)
124124
# only infer concrete call sites in top-level expressions
125125
add_remark!(interp, sv, "Refusing to infer non-concrete call site in top-level expression")
@@ -143,7 +143,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
143143
this_rt === Any && break
144144
end
145145
else
146-
this_rt, edgecycle1, edge = abstract_call_method(interp, method, sig, match[2]::SimpleVector, multiple_matches, sv)
146+
this_rt, edgecycle1, edge = abstract_call_method(interp, method, sig, match.sparams, multiple_matches, sv)
147147
edgecycle |= edgecycle1::Bool
148148
if edge !== nothing
149149
push!(edges, edge)
@@ -167,7 +167,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
167167
# if there's a possibility we could constant-propagate a better result
168168
# (hopefully without doing too much work), try to do that now
169169
# TODO: it feels like this could be better integrated into abstract_call_method / typeinf_edge
170-
const_rettype = abstract_call_method_with_const_args(interp, rettype, f, argtypes, applicable[nonbot]::SimpleVector, sv, edgecycle)
170+
const_rettype = abstract_call_method_with_const_args(interp, rettype, f, argtypes, applicable[nonbot]::MethodMatch, sv, edgecycle)
171171
if const_rettype rettype
172172
# use the better result, if it's a refinement of rettype
173173
rettype = const_rettype
@@ -214,8 +214,8 @@ function const_prop_profitable(@nospecialize(arg))
214214
return false
215215
end
216216

217-
function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nospecialize(rettype), @nospecialize(f), argtypes::Vector{Any}, match::SimpleVector, sv::InferenceState, edgecycle::Bool)
218-
method = match[3]::Method
217+
function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nospecialize(rettype), @nospecialize(f), argtypes::Vector{Any}, match::MethodMatch, sv::InferenceState, edgecycle::Bool)
218+
method = match.method
219219
nargs::Int = method.nargs
220220
method.isva && (nargs -= 1)
221221
length(argtypes) >= nargs || return Any
@@ -261,9 +261,7 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nosp
261261
if istopfunction(f, :getproperty) || istopfunction(f, :setproperty!)
262262
force_inference = true
263263
end
264-
sig = match[1]
265-
sparams = match[2]::SimpleVector
266-
mi = specialize_method(method, sig, sparams, !force_inference)
264+
mi = specialize_method(match, !force_inference)
267265
mi === nothing && return Any
268266
mi = mi::MethodInstance
269267
# decide if it's likely to be worthwhile
@@ -743,6 +741,7 @@ function is_method_pure(method::Method, @nospecialize(sig), sparams::SimpleVecto
743741
end
744742
return method.pure
745743
end
744+
is_method_pure(match::MethodMatch) = is_method_pure(match.method, match.spec_types, match.sparams)
746745

747746
function pure_eval_call(@nospecialize(f), argtypes::Vector{Any})
748747
for i = 2:length(argtypes)

base/compiler/bootstrap.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ let fs = Any[typeinf_ext, typeinf, typeinf_edge, pure_eval_call, run_passes],
2323
for f in fs
2424
for m in _methods_by_ftype(Tuple{typeof(f), Vararg{Any}}, 10, typemax(UInt))
2525
# remove any TypeVars from the intersection
26-
typ = Any[m[1].parameters...]
26+
typ = Any[m.spec_types.parameters...]
2727
for i = 1:length(typ)
2828
if isa(typ[i], TypeVar)
2929
typ[i] = typ[i].ub
3030
end
3131
end
32-
typeinf_type(interp, m[3], Tuple{typ...}, m[2])
32+
typeinf_type(interp, m.method, Tuple{typ...}, m.sparams)
3333
end
3434
end
3535
end

base/compiler/compiler.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ getfield(getfield(Main, :Core), :eval)(getfield(Main, :Core), :(baremodule Compi
55
using Core.Intrinsics, Core.IR
66

77
import Core: print, println, show, write, unsafe_write, stdout, stderr,
8-
_apply, _apply_iterate, svec, apply_type, Builtin, IntrinsicFunction, MethodInstance, CodeInstance
8+
_apply, _apply_iterate, svec, apply_type, Builtin, IntrinsicFunction,
9+
MethodInstance, CodeInstance, MethodMatch
910

1011
const getproperty = Core.getfield
1112
const setproperty! = Core.setfield!

base/compiler/ssair/inlining.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,15 +1080,15 @@ function analyze_single_call!(ir::IRCode, todo::Vector{Any}, idx::Int, @nospecia
10801080
continue
10811081
elseif length(meth) == 1 && only_method !== false
10821082
if only_method === nothing
1083-
only_method = meth[1][3]
1084-
elseif only_method !== meth[1][3]
1083+
only_method = meth[1].method
1084+
elseif only_method !== meth[1].method
10851085
only_method = false
10861086
end
10871087
else
10881088
only_method = false
10891089
end
10901090
for match in meth::Vector{Any}
1091-
(metharg, methsp, method) = (match[1]::Type, match[2]::SimpleVector, match[3]::Method)
1091+
(metharg, methsp, method) = (match.spec_types, match.sparams, match.method)
10921092
signature_union = Union{signature_union, metharg}
10931093
if !isdispatchtuple(metharg)
10941094
fully_covered = false
@@ -1119,7 +1119,7 @@ function analyze_single_call!(ir::IRCode, todo::Vector{Any}, idx::Int, @nospecia
11191119
sig.atype, method.sig)::SimpleVector
11201120
else
11211121
@assert length(meth) == 1
1122-
(metharg, methsp, method) = (meth[1][1]::Type, meth[1][2]::SimpleVector, meth[1][3]::Method)
1122+
(metharg, methsp, method) = (meth[1].spec_types, meth[1].sparams, meth[1].method)
11231123
end
11241124
fully_covered = true
11251125
case = analyze_method!(idx, sig, metharg, methsp, method,

base/compiler/typeinfer.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -683,8 +683,8 @@ function _return_type(interp::AbstractInterpreter, @nospecialize(f), @nospeciali
683683
rt = widenconst(rt)
684684
end
685685
else
686-
for m in _methods(f, t, -1, get_world_counter(interp))
687-
ty = typeinf_type(interp, m[3], m[1], m[2])
686+
for match in _methods(f, t, -1, get_world_counter(interp))
687+
ty = typeinf_type(interp, match.method, match.spec_types, match.sparams)
688688
ty === nothing && return Any
689689
rt = tmerge(rt, ty)
690690
rt === Any && break

base/compiler/utilities.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ function specialize_method(method::Method, @nospecialize(atypes), sparams::Simpl
128128
return ccall(:jl_specializations_get_linfo, Ref{MethodInstance}, (Any, Any, Any), method, atypes, sparams)
129129
end
130130

131+
function specialize_method(match::MethodMatch, preexisting::Bool=false)
132+
return specialize_method(match.method, match.spec_types, match.sparams, preexisting)
133+
end
134+
131135
# This function is used for computing alternate limit heuristics
132136
function method_for_inference_heuristics(method::Method, @nospecialize(sig), sparams::SimpleVector)
133137
if isdefined(method, :generator) && method.generator.expand_early && may_invoke_generator(method, sig, sparams)

base/deprecated.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,15 @@ macro get!(h, key0, default)
208208
end
209209

210210
# END 1.5 deprecations
211+
212+
# BEGIN 1.6 deprecations
213+
214+
# These changed from SimpleVector to `MethodMatch`. These definitions emulate
215+
# being a SimpleVector to ease transition for packages that make explicit
216+
# use of (internal) APIs that return raw method matches.
217+
iterate(match::Core.MethodMatch, field::Int=1) =
218+
field > nfields(match) ? nothing : (getfield(match, field), field+1)
219+
getindex(match::Core.MethodMatch, field::Int) =
220+
getfield(match, field)
221+
222+
# END 1.6 deprecations

base/reflection.jl

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,7 @@ function methods(@nospecialize(f), @nospecialize(t),
893893
end
894894
t = to_tuple_type(t)
895895
world = typemax(UInt)
896-
MethodList(Method[m[3] for m in _methods(f, t, -1, world) if mod === nothing || m[3].module in mod],
896+
MethodList(Method[m.method for m in _methods(f, t, -1, world) if mod === nothing || m.method.module in mod],
897897
typeof(f).name.mt)
898898
end
899899

@@ -907,7 +907,7 @@ function methods_including_ambiguous(@nospecialize(f), @nospecialize(t))
907907
has_ambig = Int32[0]
908908
ms = _methods_by_ftype(tt, -1, world, true, min, max, has_ambig)
909909
ms === false && return false
910-
return MethodList(Method[m[3] for m in ms], typeof(f).name.mt)
910+
return MethodList(Method[m.method for m in ms], typeof(f).name.mt)
911911
end
912912

913913
function methods(@nospecialize(f),
@@ -979,9 +979,9 @@ const _uncompressed_ast = _uncompressed_ir
979979
function method_instances(@nospecialize(f), @nospecialize(t), world::UInt = typemax(UInt))
980980
tt = signature_type(f, t)
981981
results = Core.MethodInstance[]
982-
for method_data in _methods_by_ftype(tt, -1, world)
983-
mtypes, msp, m = method_data
984-
instance = ccall(:jl_specializations_get_linfo, Ref{MethodInstance}, (Any, Any, Any), m, mtypes, msp)
982+
for match in _methods_by_ftype(tt, -1, world)
983+
instance = ccall(:jl_specializations_get_linfo, Ref{MethodInstance},
984+
(Any, Any, Any), match.method, match.spec_types, match.sparams)
985985
push!(results, instance)
986986
end
987987
return results
@@ -1142,14 +1142,14 @@ function code_typed_by_type(@nospecialize(tt::Type);
11421142
throw(ArgumentError("'debuginfo' must be either :source or :none"))
11431143
end
11441144
tt = to_tuple_type(tt)
1145-
meths = _methods_by_ftype(tt, -1, world)
1146-
if meths === false
1145+
matches = _methods_by_ftype(tt, -1, world)
1146+
if matches === false
11471147
error("signature does not correspond to a generic function")
11481148
end
11491149
asts = []
1150-
for x in meths
1151-
meth = func_for_method_checked(x[3], tt, x[2])
1152-
(code, ty) = Core.Compiler.typeinf_code(interp, meth, x[1], x[2], optimize)
1150+
for match in matches
1151+
meth = func_for_method_checked(match.method, tt, match.sparams)
1152+
(code, ty) = Core.Compiler.typeinf_code(interp, meth, match.spec_types, match.sparams, optimize)
11531153
code === nothing && error("inference not successful") # inference disabled?
11541154
debuginfo === :none && remove_linenums!(code)
11551155
push!(asts, code => ty)
@@ -1165,9 +1165,9 @@ function return_types(@nospecialize(f), @nospecialize(types=Tuple), interp=Core.
11651165
types = to_tuple_type(types)
11661166
rt = []
11671167
world = get_world_counter()
1168-
for x in _methods(f, types, -1, world)
1169-
meth = func_for_method_checked(x[3], types, x[2])
1170-
ty = Core.Compiler.typeinf_type(interp, meth, x[1], x[2])
1168+
for match in _methods(f, types, -1, world)
1169+
meth = func_for_method_checked(match.method, types, match.sparams)
1170+
ty = Core.Compiler.typeinf_type(interp, meth, match.spec_types, match.sparams)
11711171
ty === nothing && error("inference not successful") # inference disabled?
11721172
push!(rt, ty)
11731173
end
@@ -1359,11 +1359,12 @@ function isambiguous(m1::Method, m2::Method; ambiguous_bottom::Bool=false)
13591359
if !ambiguous_bottom
13601360
has_bottom_parameter(ti) && return false
13611361
end
1362-
ml = _methods_by_ftype(ti, -1, typemax(UInt))
1363-
for m in ml
1362+
matches = _methods_by_ftype(ti, -1, typemax(UInt))
1363+
for match in matches
1364+
m = match.method
13641365
m === m1 && continue
13651366
m === m2 && continue
1366-
if ti <: m[3].sig && morespecific(m[3].sig, m1.sig) && morespecific(m[3].sig, m2.sig)
1367+
if ti <: m.sig && morespecific(m.sig, m1.sig) && morespecific(m.sig, m2.sig)
13671368
return false
13681369
end
13691370
end

src/builtins.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,7 @@ void jl_init_primitives(void) JL_GC_DISABLED
15831583
add_builtin("Argument", (jl_value_t*)jl_argument_type);
15841584
add_builtin("Const", (jl_value_t*)jl_const_type);
15851585
add_builtin("PartialStruct", (jl_value_t*)jl_partial_struct_type);
1586+
add_builtin("MethodMatch", (jl_value_t*)jl_method_match_type);
15861587
add_builtin("IntrinsicFunction", (jl_value_t*)jl_intrinsic_type);
15871588
add_builtin("Function", (jl_value_t*)jl_function_type);
15881589
add_builtin("Builtin", (jl_value_t*)jl_builtin_type);

src/clangsa/GCChecker.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,7 @@ bool GCChecker::isGCTrackedType(QualType QT) {
767767
Name.endswith_lower("jl_excstack_t") ||
768768
Name.endswith_lower("jl_task_t") ||
769769
Name.endswith_lower("jl_uniontype_t") ||
770+
Name.endswith_lower("jl_method_match_t") ||
770771
// Probably not technically true for these, but let's allow
771772
// it
772773
Name.endswith_lower("typemap_intersection_env") ||

0 commit comments

Comments
 (0)