Skip to content

Commit dc2f727

Browse files
committed
Put inference parameters in a dedicated object.
This allows overriding parameters, while reducing global state and simplifying the API.
1 parent 5e998a5 commit dc2f727

File tree

3 files changed

+80
-51
lines changed

3 files changed

+80
-51
lines changed

base/REPLCompletions.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,8 @@ function get_type_call(expr::Expr)
285285
length(mt) == 1 || return (Any, false)
286286
m = first(mt)
287287
# Typeinference
288-
return_type = Core.Inference.typeinf_type(m[3], m[1], m[2])
288+
params = Core.Inference.InferenceParams()
289+
return_type = Core.Inference.typeinf_type(m[3], m[1], m[2], true, params)
289290
return_type === nothing && return (Any, false)
290291
return (return_type, true)
291292
end

base/inference.jl

+74-48
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,25 @@ import Core: _apply, svec, apply_type, Builtin, IntrinsicFunction, MethodInstanc
55
#### parameters limiting potentially-infinite types ####
66
const MAX_TYPEUNION_LEN = 3
77
const MAX_TYPE_DEPTH = 7
8-
const MAX_TUPLETYPE_LEN = 15
9-
const MAX_TUPLE_DEPTH = 4
108

11-
const MAX_TUPLE_SPLAT = 16
12-
const MAX_UNION_SPLITTING = 4
9+
immutable InferenceParams
10+
# optimization
11+
inlining::Bool
12+
13+
# parameters limiting potentially-infinite types (configurable)
14+
MAX_TUPLETYPE_LEN::Int
15+
MAX_TUPLE_DEPTH::Int
16+
MAX_TUPLE_SPLAT::Int
17+
MAX_UNION_SPLITTING::Int
18+
19+
# reasonable defaults
20+
InferenceParams(;inlining::Bool=inlining_enabled(),
21+
tupletype_len::Int=15, tuple_depth::Int=4,
22+
tuple_splat::Int=16, union_splitting::Int=4) =
23+
new(inlining, tupletype_len,
24+
tuple_depth, tuple_splat, union_splitting)
25+
end
26+
1327
const UNION_SPLIT_MISMATCH_ERROR = false
1428

1529
# alloc_elim_pass! relies on `Slot_AssignedOnce | Slot_UsedUndef` being
@@ -49,6 +63,8 @@ type InferenceState
4963
mod::Module
5064
currpc::LineNum
5165

66+
params::InferenceParams
67+
5268
# info on the state of inference and the linfo
5369
linfo::MethodInstance # used here for the tuple (specTypes, env, Method)
5470
src::CodeInfo
@@ -74,14 +90,16 @@ type InferenceState
7490
# iteration fixed-point detection
7591
fixedpoint::Bool
7692
inworkq::Bool
77-
# optimization
93+
94+
# TODO: put these in InferenceParams (depends on proper multi-methodcache support)
7895
optimize::Bool
79-
inlining::Bool
8096
cached::Bool
97+
8198
inferred::Bool
8299

83100
# src is assumed to be a newly-allocated CodeInfo, that can be modified in-place to contain intermediate results
84-
function InferenceState(linfo::MethodInstance, src::CodeInfo, optimize::Bool, inlining::Bool, cached::Bool)
101+
function InferenceState(linfo::MethodInstance, src::CodeInfo,
102+
optimize::Bool, cached::Bool, params::InferenceParams)
85103
code = src.code::Array{Any,1}
86104
nl = label_counter(code) + 1
87105
toplevel = !isdefined(linfo, :def)
@@ -113,7 +131,7 @@ type InferenceState
113131
end
114132
s[1][la] = VarState(Tuple, false)
115133
else
116-
s[1][la] = VarState(tuple_tfunc(limit_tuple_depth(tupletype_tail(atypes, la))), false)
134+
s[1][la] = VarState(tuple_tfunc(limit_tuple_depth(params, tupletype_tail(atypes, la))), false)
117135
end
118136
la -= 1
119137
end
@@ -168,12 +186,13 @@ type InferenceState
168186
inmodule = toplevel ? current_module() : linfo.def.module # toplevel thunks are inferred in the current module
169187
frame = new(
170188
sp, nl, inmodule, 0,
189+
params,
171190
linfo, src, nargs, s, Union{}, W, n,
172191
cur_hand, handler_at, n_handlers,
173192
ssavalue_uses, ssavalue_init,
174193
ObjectIdDict(), #Dict{InferenceState, Vector{LineNum}}(),
175194
Vector{Tuple{InferenceState, Vector{LineNum}}}(),
176-
false, false, optimize, inlining, cached, false)
195+
false, false, optimize, cached, false)
177196
push!(active, frame)
178197
nactive[] += 1
179198
return frame
@@ -669,7 +688,7 @@ function invoke_tfunc(f::ANY, types::ANY, argtype::ANY, sv::InferenceState)
669688
if !isleaftype(Type{types})
670689
return Any
671690
end
672-
argtype = typeintersect(types,limit_tuple_type(argtype))
691+
argtype = typeintersect(types,limit_tuple_type(argtype, sv.params))
673692
if argtype === Bottom
674693
return Bottom
675694
end
@@ -703,7 +722,7 @@ function builtin_tfunction(f::ANY, argtypes::Array{Any,1}, sv::InferenceState)
703722
if f === tuple
704723
for a in argtypes
705724
if !isa(a, Const)
706-
return tuple_tfunc(limit_tuple_depth(argtypes_to_type(argtypes)))
725+
return tuple_tfunc(limit_tuple_depth(sv.params, argtypes_to_type(argtypes)))
707726
end
708727
end
709728
return Const(tuple(map(a->a.val, argtypes)...))
@@ -766,28 +785,28 @@ function builtin_tfunction(f::ANY, argtypes::Array{Any,1}, sv::InferenceState)
766785
return tf[3](argtypes...)
767786
end
768787

769-
limit_tuple_depth(t::ANY) = limit_tuple_depth_(t,0)
788+
limit_tuple_depth(params::InferenceParams, t::ANY) = limit_tuple_depth_(params,t,0)
770789

771-
function limit_tuple_depth_(t::ANY, d::Int)
790+
function limit_tuple_depth_(params::InferenceParams, t::ANY, d::Int)
772791
if isa(t,Union)
773792
# also limit within Union types.
774793
# may have to recur into other stuff in the future too.
775-
return Union{map(x->limit_tuple_depth_(x,d+1), t.types)...}
794+
return Union{map(x->limit_tuple_depth_(params,x,d+1), t.types)...}
776795
end
777796
if isa(t,TypeVar)
778-
return limit_tuple_depth_(t.ub, d)
797+
return limit_tuple_depth_(params, t.ub, d)
779798
end
780799
if !(isa(t,DataType) && t.name === Tuple.name)
781800
return t
782801
end
783-
if d > MAX_TUPLE_DEPTH
802+
if d > params.MAX_TUPLE_DEPTH
784803
return Tuple
785804
end
786-
p = map(x->limit_tuple_depth_(x,d+1), t.parameters)
805+
p = map(x->limit_tuple_depth_(params,x,d+1), t.parameters)
787806
Tuple{p...}
788807
end
789808

790-
limit_tuple_type = (t::ANY) -> limit_tuple_type_n(t, MAX_TUPLETYPE_LEN)
809+
limit_tuple_type = (t::ANY, params::InferenceParams) -> limit_tuple_type_n(t, params.MAX_TUPLETYPE_LEN)
791810

792811
function limit_tuple_type_n(t::ANY, lim::Int)
793812
p = t.parameters
@@ -802,7 +821,7 @@ end
802821

803822
#### recursing into expression ####
804823

805-
function abstract_call_gf_by_type(f::ANY, argtype::ANY, sv)
824+
function abstract_call_gf_by_type(f::ANY, argtype::ANY, sv::InferenceState)
806825
tm = _topmod(sv)
807826
# don't consider more than N methods. this trades off between
808827
# compiler performance and generated code performance.
@@ -811,7 +830,7 @@ function abstract_call_gf_by_type(f::ANY, argtype::ANY, sv)
811830
# It is important for N to be >= the number of methods in the error()
812831
# function, so we can still know that error() is always Bottom.
813832
# here I picked 4.
814-
argtype = limit_tuple_type(argtype)
833+
argtype = limit_tuple_type(argtype, sv.params)
815834
argtypes = argtype.parameters
816835
applicable = _methods_by_ftype(argtype, 4)
817836
rettype = Bottom
@@ -1008,9 +1027,9 @@ function abstract_apply(af::ANY, fargs, aargtypes::Vector{Any}, vtypes::VarTable
10081027
# can be collapsed to a call to the applied func
10091028
at = append_any(Any[type_typeof(af)], ctypes...)
10101029
n = length(at)
1011-
if n-1 > MAX_TUPLETYPE_LEN
1012-
tail = foldl((a,b)->tmerge(a,unwrapva(b)), Bottom, at[MAX_TUPLETYPE_LEN+1:n])
1013-
at = vcat(at[1:MAX_TUPLETYPE_LEN], Any[Vararg{widenconst(tail)}])
1030+
if n-1 > sv.params.MAX_TUPLETYPE_LEN
1031+
tail = foldl((a,b)->tmerge(a,unwrapva(b)), Bottom, at[sv.params.MAX_TUPLETYPE_LEN+1:n])
1032+
at = vcat(at[1:sv.params.MAX_TUPLETYPE_LEN], Any[Vararg{widenconst(tail)}])
10141033
end
10151034
return abstract_call(af, (), at, vtypes, sv)
10161035
end
@@ -1027,6 +1046,7 @@ function pure_eval_call(f::ANY, argtypes::ANY, atype::ANY, vtypes::VarTable, sv:
10271046
end
10281047

10291048
if f === return_type && length(argtypes) == 3
1049+
# NOTE: only considering calls to return_type without InferenceParams arg
10301050
tt = argtypes[3]
10311051
if isType(tt)
10321052
af_argtype = tt.parameters[1]
@@ -1130,7 +1150,7 @@ function abstract_call(f::ANY, fargs, argtypes::Vector{Any}, vtypes::VarTable, s
11301150
return Type
11311151
end
11321152

1133-
if sv.inlining
1153+
if sv.params.inlining
11341154
# need to model the special inliner for ^
11351155
# to ensure we have added the same edge
11361156
if isdefined(Main, :Base) &&
@@ -1523,7 +1543,8 @@ end
15231543

15241544

15251545
# build (and start inferring) the inference frame for the linfo
1526-
function typeinf_frame(linfo::MethodInstance, optimize::Bool, cached::Bool, caller)
1546+
function typeinf_frame(linfo::MethodInstance, caller, optimize::Bool, cached::Bool,
1547+
params::InferenceParams)
15271548
frame = nothing
15281549
if linfo.inInference
15291550
# inference on this signature may be in progress,
@@ -1552,7 +1573,7 @@ function typeinf_frame(linfo::MethodInstance, optimize::Bool, cached::Bool, call
15521573
src = get_source(linfo)
15531574
end
15541575
linfo.inInference = true
1555-
frame = InferenceState(linfo, src, optimize, inlining_enabled(), cached)
1576+
frame = InferenceState(linfo, src, optimize, cached, params)
15561577
end
15571578
frame = frame::InferenceState
15581579

@@ -1593,7 +1614,7 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller
15931614
end
15941615
end
15951616
end
1596-
frame = typeinf_frame(code, true, true, caller)
1617+
frame = typeinf_frame(code, caller, true, true, caller.params)
15971618
frame === nothing && return Any
15981619
frame = frame::InferenceState
15991620
return frame.bestguess
@@ -1602,12 +1623,14 @@ end
16021623
#### entry points for inferring a MethodInstance given a type signature ####
16031624

16041625
# compute an inferred AST and return type
1605-
function typeinf_code(method::Method, atypes::ANY, sparams::SimpleVector, optimize::Bool, cached::Bool)
1626+
function typeinf_code(method::Method, atypes::ANY, sparams::SimpleVector,
1627+
optimize::Bool, cached::Bool, params::InferenceParams)
16061628
code = code_for_method(method, atypes, sparams)
16071629
code === nothing && return (nothing, Any)
1608-
return typeinf_code(code::MethodInstance, optimize, cached)
1630+
return typeinf_code(code::MethodInstance, optimize, cached, params)
16091631
end
1610-
function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool)
1632+
function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool,
1633+
params::InferenceParams)
16111634
for i = 1:2 # test-and-lock-and-test
16121635
if cached && isdefined(linfo, :inferred)
16131636
# see if this code already exists in the cache
@@ -1638,7 +1661,7 @@ function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool)
16381661
end
16391662
i == 1 && ccall(:jl_typeinf_begin, Void, ())
16401663
end
1641-
frame = typeinf_frame(linfo, optimize, cached, nothing)
1664+
frame = typeinf_frame(linfo, nothing, optimize, cached, params)
16421665
ccall(:jl_typeinf_end, Void, ())
16431666
frame === nothing && return (nothing, Any)
16441667
frame = frame::InferenceState
@@ -1647,7 +1670,8 @@ function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool)
16471670
end
16481671

16491672
# compute (and cache) an inferred AST and return the inferred return type
1650-
function typeinf_type(method::Method, atypes::ANY, sparams::SimpleVector, cached::Bool=true)
1673+
function typeinf_type(method::Method, atypes::ANY, sparams::SimpleVector,
1674+
cached::Bool, params::InferenceParams)
16511675
code = code_for_method(method, atypes, sparams)
16521676
code === nothing && return nothing
16531677
code = code::MethodInstance
@@ -1664,7 +1688,7 @@ function typeinf_type(method::Method, atypes::ANY, sparams::SimpleVector, cached
16641688
end
16651689
i == 1 && ccall(:jl_typeinf_begin, Void, ())
16661690
end
1667-
frame = typeinf_frame(code, cached, cached, nothing)
1691+
frame = typeinf_frame(code, nothing, cached, cached, params)
16681692
ccall(:jl_typeinf_end, Void, ())
16691693
frame === nothing && return nothing
16701694
frame = frame::InferenceState
@@ -1675,13 +1699,14 @@ end
16751699
function typeinf_ext(linfo::MethodInstance)
16761700
if isdefined(linfo, :def)
16771701
# method lambda - infer this specialization via the method cache
1678-
(code, typ) = typeinf_code(linfo, true, true)
1702+
(code, typ) = typeinf_code(linfo, true, true, InferenceParams())
16791703
return code
16801704
else
16811705
# toplevel lambda - infer directly
16821706
linfo.inInference = true
16831707
ccall(:jl_typeinf_begin, Void, ())
1684-
frame = InferenceState(linfo, linfo.inferred::CodeInfo, true, inlining_enabled(), true)
1708+
frame = InferenceState(linfo, linfo.inferred::CodeInfo,
1709+
true, true, InferenceParams())
16851710
typeinf_loop(frame)
16861711
ccall(:jl_typeinf_end, Void, ())
16871712
@assert frame.inferred # TODO: deal with this better
@@ -2144,7 +2169,6 @@ function type_annotate!(sv::InferenceState)
21442169
body = src.code::Array{Any,1}
21452170
nexpr = length(body)
21462171
i = 1
2147-
optimize = sv.optimize::Bool
21482172
while i <= nexpr
21492173
st_i = states[i]
21502174
expr = body[i]
@@ -2157,7 +2181,7 @@ function type_annotate!(sv::InferenceState)
21572181
id = expr.args[1].id
21582182
record_slot_type!(id, widenconst(states[i+1][id].typ), src.slottypes)
21592183
end
2160-
elseif optimize
2184+
elseif sv.optimize
21612185
if ((isa(expr, Expr) && is_meta_expr(expr::Expr)) ||
21622186
isa(expr, LineNumberNode))
21632187
i += 1
@@ -2440,7 +2464,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
24402464
end
24412465
topmod = _topmod(sv)
24422466
# special-case inliners for known pure functions that compute types
2443-
if sv.inlining
2467+
if sv.params.inlining
24442468
if isconstType(e.typ,true)
24452469
if (f === apply_type || f === fieldtype || f === typeof ||
24462470
istopfunction(topmod, f, :typejoin) ||
@@ -2474,7 +2498,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
24742498
function invoke_NF()
24752499
# converts a :call to :invoke
24762500
local nu = countunionsplit(atypes)
2477-
nu > MAX_UNION_SPLITTING && return NF
2501+
nu > sv.params.MAX_UNION_SPLITTING && return NF
24782502

24792503
if nu > 1
24802504
local spec_hit = nothing
@@ -2574,12 +2598,12 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
25742598
end
25752599
return NF
25762600
end
2577-
if !sv.inlining
2601+
if !sv.params.inlining
25782602
return invoke_NF()
25792603
end
25802604

2581-
if length(atype_unlimited.parameters) - 1 > MAX_TUPLETYPE_LEN
2582-
atype = limit_tuple_type(atype_unlimited)
2605+
if length(atype_unlimited.parameters) - 1 > sv.params.MAX_TUPLETYPE_LEN
2606+
atype = limit_tuple_type(atype_unlimited, sv.params)
25832607
else
25842608
atype = atype_unlimited
25852609
end
@@ -2660,7 +2684,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
26602684
linfo = code_for_method(method, metharg, methsp)
26612685
end
26622686
if isa(linfo, MethodInstance)
2663-
frame = typeinf_frame(linfo::MethodInstance, true, true, nothing)
2687+
frame = typeinf_frame(linfo::MethodInstance, nothing, true, true, sv.params)
26642688
end
26652689
end
26662690
if isa(frame, InferenceState) && frame.inferred
@@ -3085,7 +3109,7 @@ function inlining_pass(e::Expr, sv::InferenceState)
30853109
end
30863110
end
30873111

3088-
if sv.inlining
3112+
if sv.params.inlining
30893113
if isdefined(Main, :Base) &&
30903114
((isdefined(Main.Base, :^) && f === Main.Base.:^) ||
30913115
(isdefined(Main.Base, :.^) && f === Main.Base.:.^)) &&
@@ -3164,7 +3188,7 @@ function inlining_pass(e::Expr, sv::InferenceState)
31643188
elseif isa(aarg, Tuple)
31653189
newargs[i-2] = Any[ QuoteNode(x) for x in aarg ]
31663190
elseif isa(t, DataType) && t.name === Tuple.name && !isvatuple(t) &&
3167-
effect_free(aarg, sv.src, sv.mod, true) && length(t.parameters) <= MAX_TUPLE_SPLAT
3191+
effect_free(aarg, sv.src, sv.mod, true) && length(t.parameters) <= sv.params.MAX_TUPLE_SPLAT
31683192
# apply(f,t::(x,y)) => f(t[1],t[2])
31693193
tp = t.parameters
31703194
newargs[i-2] = Any[ mk_getfield(aarg,j,tp[j]) for j=1:length(tp) ]
@@ -3965,10 +3989,12 @@ function reindex_labels!(sv::InferenceState)
39653989
end
39663990
end
39673991

3968-
function return_type(f::ANY, t::ANY)
3992+
function return_type(f::ANY, t::ANY, params::InferenceParams=InferenceParams())
3993+
# NOTE: if not processed by pure_eval_call during inference, a call to return_type
3994+
# might use difference InferenceParams than the method it is contained in...
39693995
rt = Union{}
39703996
for m in _methods(f, t, -1)
3971-
ty = typeinf_type(m[3], m[1], m[2])
3997+
ty = typeinf_type(m[3], m[1], m[2], true, params)
39723998
ty === nothing && return Any
39733999
rt = tmerge(rt, ty)
39744000
rt === Any && break
@@ -4002,7 +4028,7 @@ let fs = Any[typeinf_ext, typeinf_loop, typeinf_edge, occurs_outside_getfield, e
40024028
typ[i] = typ[i].ub
40034029
end
40044030
end
4005-
typeinf_type(m[3], Tuple{typ...}, m[2])
4031+
typeinf_type(m[3], Tuple{typ...}, m[2], true, InferenceParams())
40064032
end
40074033
end
40084034
end

0 commit comments

Comments
 (0)