Skip to content

Commit a19f415

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

File tree

3 files changed

+81
-51
lines changed

3 files changed

+81
-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

+75-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=16,
22+
tuple_splat::Int=4, 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 is(argtype,Bottom)
674693
return Bottom
675694
end
@@ -703,7 +722,7 @@ function builtin_tfunction(f::ANY, argtypes::Array{Any,1}, sv::InferenceState)
703722
if is(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
@@ -1006,9 +1025,10 @@ function abstract_apply(af::ANY, fargs, aargtypes::Vector{Any}, vtypes::VarTable
10061025
# can be collapsed to a call to the applied func
10071026
at = append_any(Any[type_typeof(af)], ctypes...)
10081027
n = length(at)
1009-
if n-1 > MAX_TUPLETYPE_LEN
1010-
tail = foldl((a,b)->tmerge(a,unwrapva(b)), Bottom, at[MAX_TUPLETYPE_LEN+1:n])
1011-
at = vcat(at[1:MAX_TUPLETYPE_LEN], Any[Vararg{tail}])
1028+
if n-1 > sv.params.MAX_TUPLETYPE_LEN
1029+
tail = foldl((a,b)->tmerge(a,unwrapva(b)), Bottom,
1030+
at[sv.params.MAX_TUPLETYPE_LEN+1:n])
1031+
at = vcat(at[1:sv.params.MAX_TUPLETYPE_LEN], Any[Vararg{tail}])
10121032
end
10131033
return abstract_call(af, (), at, vtypes, sv)
10141034
end
@@ -1024,6 +1044,7 @@ function pure_eval_call(f::ANY, argtypes::ANY, atype::ANY, vtypes::VarTable, sv:
10241044
end
10251045

10261046
if f === return_type && length(argtypes) == 3
1047+
# NOTE: only considering calls to return_type without InferenceParams arg
10271048
tt = argtypes[3]
10281049
if isType(tt)
10291050
af_argtype = tt.parameters[1]
@@ -1127,7 +1148,7 @@ function abstract_call(f::ANY, fargs, argtypes::Vector{Any}, vtypes::VarTable, s
11271148
return Type
11281149
end
11291150

1130-
if sv.inlining
1151+
if sv.params.inlining
11311152
# need to model the special inliner for ^
11321153
# to ensure we have added the same edge
11331154
if isdefined(Main, :Base) &&
@@ -1520,7 +1541,8 @@ end
15201541

15211542

15221543
# build (and start inferring) the inference frame for the linfo
1523-
function typeinf_frame(linfo::MethodInstance, optimize::Bool, cached::Bool, caller)
1544+
function typeinf_frame(linfo::MethodInstance, caller, optimize::Bool, cached::Bool,
1545+
params::InferenceParams)
15241546
frame = nothing
15251547
if linfo.inInference
15261548
# inference on this signature may be in progress,
@@ -1549,7 +1571,7 @@ function typeinf_frame(linfo::MethodInstance, optimize::Bool, cached::Bool, call
15491571
src = get_source(linfo)
15501572
end
15511573
linfo.inInference = true
1552-
frame = InferenceState(linfo, src, optimize, inlining_enabled(), cached)
1574+
frame = InferenceState(linfo, src, optimize, cached, params)
15531575
end
15541576
frame = frame::InferenceState
15551577

@@ -1590,7 +1612,7 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller
15901612
end
15911613
end
15921614
end
1593-
frame = typeinf_frame(code, true, true, caller)
1615+
frame = typeinf_frame(code, caller, true, true, caller.params)
15941616
frame === nothing && return Any
15951617
frame = frame::InferenceState
15961618
return frame.bestguess
@@ -1599,12 +1621,14 @@ end
15991621
#### entry points for inferring a MethodInstance given a type signature ####
16001622

16011623
# compute an inferred AST and return type
1602-
function typeinf_code(method::Method, atypes::ANY, sparams::SimpleVector, optimize::Bool, cached::Bool)
1624+
function typeinf_code(method::Method, atypes::ANY, sparams::SimpleVector,
1625+
optimize::Bool, cached::Bool, params::InferenceParams)
16031626
code = code_for_method(method, atypes, sparams)
16041627
code === nothing && return (nothing, Any)
1605-
return typeinf_code(code::MethodInstance, optimize, cached)
1628+
return typeinf_code(code::MethodInstance, optimize, cached, params)
16061629
end
1607-
function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool)
1630+
function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool,
1631+
params::InferenceParams)
16081632
for i = 1:2 # test-and-lock-and-test
16091633
if cached && isdefined(linfo, :inferred)
16101634
# see if this code already exists in the cache
@@ -1635,7 +1659,7 @@ function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool)
16351659
end
16361660
i == 1 && ccall(:jl_typeinf_begin, Void, ())
16371661
end
1638-
frame = typeinf_frame(linfo, optimize, cached, nothing)
1662+
frame = typeinf_frame(linfo, nothing, optimize, cached, params)
16391663
ccall(:jl_typeinf_end, Void, ())
16401664
frame === nothing && return (nothing, Any)
16411665
frame = frame::InferenceState
@@ -1644,7 +1668,8 @@ function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool)
16441668
end
16451669

16461670
# compute (and cache) an inferred AST and return the inferred return type
1647-
function typeinf_type(method::Method, atypes::ANY, sparams::SimpleVector, cached::Bool=true)
1671+
function typeinf_type(method::Method, atypes::ANY, sparams::SimpleVector,
1672+
cached::Bool, params::InferenceParams)
16481673
code = code_for_method(method, atypes, sparams)
16491674
code === nothing && return nothing
16501675
code = code::MethodInstance
@@ -1661,7 +1686,7 @@ function typeinf_type(method::Method, atypes::ANY, sparams::SimpleVector, cached
16611686
end
16621687
i == 1 && ccall(:jl_typeinf_begin, Void, ())
16631688
end
1664-
frame = typeinf_frame(code, cached, cached, nothing)
1689+
frame = typeinf_frame(code, nothing, cached, cached, params)
16651690
ccall(:jl_typeinf_end, Void, ())
16661691
frame === nothing && return nothing
16671692
frame = frame::InferenceState
@@ -1672,13 +1697,14 @@ end
16721697
function typeinf_ext(linfo::MethodInstance)
16731698
if isdefined(linfo, :def)
16741699
# method lambda - infer this specialization via the method cache
1675-
(code, typ) = typeinf_code(linfo, true, true)
1700+
(code, typ) = typeinf_code(linfo, true, true, InferenceParams())
16761701
return code
16771702
else
16781703
# toplevel lambda - infer directly
16791704
linfo.inInference = true
16801705
ccall(:jl_typeinf_begin, Void, ())
1681-
frame = InferenceState(linfo, linfo.inferred::CodeInfo, true, inlining_enabled(), true)
1706+
frame = InferenceState(linfo, linfo.inferred::CodeInfo,
1707+
true, true, InferenceParams())
16821708
typeinf_loop(frame)
16831709
ccall(:jl_typeinf_end, Void, ())
16841710
@assert frame.inferred # TODO: deal with this better
@@ -2138,7 +2164,6 @@ function type_annotate!(sv::InferenceState)
21382164
body = src.code::Array{Any,1}
21392165
nexpr = length(body)
21402166
i = 1
2141-
optimize = sv.optimize::Bool
21422167
while i <= nexpr
21432168
st_i = states[i]
21442169
expr = body[i]
@@ -2151,7 +2176,7 @@ function type_annotate!(sv::InferenceState)
21512176
id = expr.args[1].id
21522177
record_slot_type!(id, widenconst(states[i+1][id].typ), src.slottypes)
21532178
end
2154-
elseif optimize
2179+
elseif sv.optimize
21552180
if ((isa(expr, Expr) && is_meta_expr(expr::Expr)) ||
21562181
isa(expr, LineNumberNode))
21572182
i += 1
@@ -2426,7 +2451,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
24262451
end
24272452
topmod = _topmod(sv)
24282453
# special-case inliners for known pure functions that compute types
2429-
if sv.inlining
2454+
if sv.params.inlining
24302455
if isconstType(e.typ,true)
24312456
if (is(f, apply_type) || is(f, fieldtype) || is(f, typeof) ||
24322457
istopfunction(topmod, f, :typejoin) ||
@@ -2460,7 +2485,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
24602485
function invoke_NF()
24612486
# converts a :call to :invoke
24622487
local nu = countunionsplit(atypes)
2463-
nu > MAX_UNION_SPLITTING && return NF
2488+
nu > sv.params.MAX_UNION_SPLITTING && return NF
24642489

24652490
if nu > 1
24662491
local spec_hit = nothing
@@ -2560,12 +2585,12 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
25602585
end
25612586
return NF
25622587
end
2563-
if !sv.inlining
2588+
if !sv.params.inlining
25642589
return invoke_NF()
25652590
end
25662591

2567-
if length(atype_unlimited.parameters) - 1 > MAX_TUPLETYPE_LEN
2568-
atype = limit_tuple_type(atype_unlimited)
2592+
if length(atype_unlimited.parameters) - 1 > sv.params.MAX_TUPLETYPE_LEN
2593+
atype = limit_tuple_type(atype_unlimited, sv.params)
25692594
else
25702595
atype = atype_unlimited
25712596
end
@@ -2646,7 +2671,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
26462671
linfo = code_for_method(method, metharg, methsp)
26472672
end
26482673
if isa(linfo, MethodInstance)
2649-
frame = typeinf_frame(linfo::MethodInstance, true, true, nothing)
2674+
frame = typeinf_frame(linfo::MethodInstance, nothing, true, true, sv.params)
26502675
end
26512676
end
26522677
if isa(frame, InferenceState) && frame.inferred
@@ -3071,7 +3096,7 @@ function inlining_pass(e::Expr, sv::InferenceState)
30713096
end
30723097
end
30733098

3074-
if sv.inlining
3099+
if sv.params.inlining
30753100
if isdefined(Main, :Base) &&
30763101
((isdefined(Main.Base, :^) && is(f, Main.Base.:^)) ||
30773102
(isdefined(Main.Base, :.^) && is(f, Main.Base.:.^))) &&
@@ -3150,7 +3175,7 @@ function inlining_pass(e::Expr, sv::InferenceState)
31503175
elseif isa(aarg, Tuple)
31513176
newargs[i-2] = Any[ QuoteNode(x) for x in aarg ]
31523177
elseif isa(t, DataType) && t.name === Tuple.name && !isvatuple(t) &&
3153-
effect_free(aarg, sv.src, sv.mod, true) && length(t.parameters) <= MAX_TUPLE_SPLAT
3178+
effect_free(aarg, sv.src, sv.mod, true) && length(t.parameters) <= sv.params.MAX_TUPLE_SPLAT
31543179
# apply(f,t::(x,y)) => f(t[1],t[2])
31553180
tp = t.parameters
31563181
newargs[i-2] = Any[ mk_getfield(aarg,j,tp[j]) for j=1:length(tp) ]
@@ -3951,10 +3976,12 @@ function reindex_labels!(sv::InferenceState)
39513976
end
39523977
end
39533978

3954-
function return_type(f::ANY, t::ANY)
3979+
function return_type(f::ANY, t::ANY, params::InferenceParams=InferenceParams())
3980+
# NOTE: if not processed by pure_eval_call during inference, a call to return_type
3981+
# might use difference InferenceParams than the method it is contained in...
39553982
rt = Union{}
39563983
for m in _methods(f, t, -1)
3957-
ty = typeinf_type(m[3], m[1], m[2])
3984+
ty = typeinf_type(m[3], m[1], m[2], true, params)
39583985
ty === nothing && return Any
39593986
rt = tmerge(rt, ty)
39603987
rt === Any && break
@@ -3988,7 +4015,7 @@ let fs = Any[typeinf_ext, typeinf_loop, typeinf_edge, occurs_outside_getfield, e
39884015
typ[i] = typ[i].ub
39894016
end
39904017
end
3991-
typeinf_type(m[3], Tuple{typ...}, m[2])
4018+
typeinf_type(m[3], Tuple{typ...}, m[2], true, InferenceParams())
39924019
end
39934020
end
39944021
end

0 commit comments

Comments
 (0)