Skip to content

Commit b89e012

Browse files
authored
Merge pull request #26628 from JuliaLang/jn/typelimits
inference: remove MAX_TYPE_DEPTH limit, rewrite tmerge
2 parents c960f18 + dcdc768 commit b89e012

File tree

13 files changed

+303
-216
lines changed

13 files changed

+303
-216
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ function abstract_call_method(method::Method, @nospecialize(sig), sparams::Simpl
249249
comparison = method.sig
250250
end
251251
# see if the type is actually too big (relative to the caller), and limit it if required
252-
newsig = limit_type_size(sig, comparison, sv.linfo.specTypes, spec_len)
252+
newsig = limit_type_size(sig, comparison, sv.linfo.specTypes, sv.params.TUPLE_COMPLEXITY_LIMIT_DEPTH, spec_len)
253253

254254
if newsig !== sig
255255
# continue inference, but note that we've limited parameter complexity

base/compiler/params.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ struct Params
2626
# when inferring a call to _apply
2727
MAX_APPLY_UNION_ENUM::Int
2828

29-
# parameters limiting large types
29+
# parameters limiting large (tuple) types
3030
MAX_TUPLETYPE_LEN::Int
31+
TUPLE_COMPLEXITY_LIMIT_DEPTH::Int
3132

3233
# when attempting to inlining _apply, abort the optimization if the tuple
3334
# contains more than this many elements
@@ -41,12 +42,13 @@ struct Params
4142
inline_tupleret_bonus::Int = 400,
4243
max_methods::Int = 4,
4344
tupletype_len::Int = 15,
45+
tupletype_depth::Int = 3,
4446
tuple_splat::Int = 16,
4547
union_splitting::Int = 4,
4648
apply_union_enum::Int = 8)
4749
return new(Vector{InferenceResult}(),
4850
world, inlining, true, false, inline_cost_threshold, inline_nonleaf_penalty,
4951
inline_tupleret_bonus, max_methods, union_splitting, apply_union_enum,
50-
tupletype_len, tuple_splat)
52+
tupletype_len, tupletype_depth, tuple_splat)
5153
end
5254
end

base/compiler/tfuncs.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -712,9 +712,6 @@ function apply_type_tfunc(@nospecialize(headtypetype), @nospecialize args...)
712712
if isvarargtype(headtype)
713713
return Type
714714
end
715-
if uncertain && type_too_complex(appl, MAX_TYPE_DEPTH)
716-
return Type{<:headtype}
717-
end
718715
if istuple
719716
return Type{<:appl}
720717
end
@@ -914,3 +911,10 @@ function return_type_tfunc(argtypes::Vector{Any}, vtypes::VarTable, sv::Inferenc
914911
end
915912
return NOT_FOUND
916913
end
914+
915+
# N.B.: typename maps type equivalence classes to a single value
916+
function typename_static(@nospecialize(t))
917+
t = unwrap_unionall(t)
918+
return isType(t) ? _typename(t.parameters[1]) : Core.TypeName
919+
end
920+
typename_static(t::Const) = _typename(t.val)

base/compiler/typelattice.jl

Lines changed: 3 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,14 @@ struct PartialTypeVar
4949
end
5050

5151
# Wraps a type and represents that the value may also be undef at this point.
52+
# (only used in optimize, not abstractinterpret)
5253
struct MaybeUndef
5354
typ
55+
MaybeUndef(@nospecialize(typ)) = new(typ)
5456
end
5557

5658
# The type of a variable load is either a value or an UndefVarError
59+
# (only used in abstractinterpret, doesn't appear in optimize)
5760
struct VarState
5861
typ
5962
undef::Bool
@@ -72,32 +75,6 @@ struct NotFound end
7275

7376
const NOT_FOUND = NotFound()
7477

75-
#####################
76-
# lattice utilities #
77-
#####################
78-
79-
function rewrap(@nospecialize(t), @nospecialize(u))
80-
isa(t, Const) && return t
81-
isa(t, Conditional) && return t
82-
return rewrap_unionall(t, u)
83-
end
84-
85-
_typename(a) = Union{}
86-
_typename(a::Vararg) = Any
87-
_typename(a::TypeVar) = Any
88-
function _typename(a::Union)
89-
ta = _typename(a.a)
90-
tb = _typename(a.b)
91-
ta === tb ? tb : (ta === Any || tb === Any) ? Any : Union{}
92-
end
93-
_typename(union::UnionAll) = _typename(union.body)
94-
95-
_typename(a::DataType) = Const(a.name)
96-
97-
# N.B.: typename maps type equivalence classes to a single value
98-
typename_static(@nospecialize(t)) = isType(t) ? _typename(t.parameters[1]) : Any
99-
typename_static(t::Const) = _typename(t.val)
100-
10178
#################
10279
# lattice logic #
10380
#################
@@ -176,49 +153,6 @@ widenconst(@nospecialize(t)) = t
176153

177154
issubstate(a::VarState, b::VarState) = (a.typ b.typ && a.undef <= b.undef)
178155

179-
function tmerge(@nospecialize(typea), @nospecialize(typeb))
180-
typea typeb && return typeb
181-
typeb typea && return typea
182-
if isa(typea, MaybeUndef) || isa(typeb, MaybeUndef)
183-
return MaybeUndef(tmerge(
184-
isa(typea, MaybeUndef) ? typea.typ : typea,
185-
isa(typeb, MaybeUndef) ? typeb.typ : typeb))
186-
end
187-
if isa(typea, Conditional) && isa(typeb, Conditional)
188-
if typea.var === typeb.var
189-
vtype = tmerge(typea.vtype, typeb.vtype)
190-
elsetype = tmerge(typea.elsetype, typeb.elsetype)
191-
if vtype != elsetype
192-
return Conditional(typea.var, vtype, elsetype)
193-
end
194-
end
195-
return Bool
196-
end
197-
typea, typeb = widenconst(typea), widenconst(typeb)
198-
typea === typeb && return typea
199-
if !(isa(typea,Type) || isa(typea,TypeVar)) || !(isa(typeb,Type) || isa(typeb,TypeVar))
200-
return Any
201-
end
202-
if (typea <: Tuple) && (typeb <: Tuple)
203-
if isa(typea, DataType) && isa(typeb, DataType) && length(typea.parameters) == length(typeb.parameters) && !isvatuple(typea) && !isvatuple(typeb)
204-
return typejoin(typea, typeb)
205-
end
206-
if isa(typea, Union) || isa(typeb, Union) || (isa(typea,DataType) && length(typea.parameters)>3) ||
207-
(isa(typeb,DataType) && length(typeb.parameters)>3)
208-
# widen tuples faster (see #6704), but not too much, to make sure we can infer
209-
# e.g. (t::Union{Tuple{Bool},Tuple{Bool,Int}})[1]
210-
return Tuple
211-
end
212-
end
213-
u = Union{typea, typeb}
214-
if unionlen(u) > MAX_TYPEUNION_LEN || type_too_complex(u, MAX_TYPE_DEPTH)
215-
# don't let type unions get too big
216-
# TODO: something smarter, like a common supertype
217-
return Any
218-
end
219-
return u
220-
end
221-
222156
function smerge(sa::Union{NotFound,VarState}, sb::Union{NotFound,VarState})
223157
sa === sb && return sa
224158
sa === NOT_FOUND && return sb

base/compiler/typelimits.jl

Lines changed: 114 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
# limitation parameters #
55
#########################
66

7-
const MAX_TYPEUNION_LEN = 3
8-
const MAX_TYPE_DEPTH = 8
7+
const MAX_TYPEUNION_LEN = 4
98
const MAX_INLINE_CONST_SIZE = 256
10-
const TUPLE_COMPLEXITY_LIMIT_DEPTH = 3
119

1210
#########################
1311
# limitation heuristics #
@@ -31,10 +29,10 @@ end
3129
# limit the complexity of type `t` to be simpler than the comparison type `compare`
3230
# no new values may be introduced, so the parameter `source` encodes the set of all values already present
3331
# the outermost tuple type is permitted to have up to `allowed_tuplelen` parameters
34-
function limit_type_size(@nospecialize(t), @nospecialize(compare), @nospecialize(source), allowed_tuplelen::Int)
32+
function limit_type_size(@nospecialize(t), @nospecialize(compare), @nospecialize(source), allowed_tupledepth::Int, allowed_tuplelen::Int)
3533
source = svec(unwrap_unionall(compare), unwrap_unionall(source))
3634
source[1] === source[2] && (source = svec(source[1]))
37-
type_more_complex(t, compare, source, 1, TUPLE_COMPLEXITY_LIMIT_DEPTH, allowed_tuplelen) || return t
35+
type_more_complex(t, compare, source, 1, allowed_tupledepth, allowed_tuplelen) || return t
3836
r = _limit_type_size(t, compare, source, 1, allowed_tuplelen)
3937
@assert t <: r
4038
#@assert r === _limit_type_size(r, t, source) # this monotonicity constraint is slightly stronger than actually required,
@@ -304,21 +302,118 @@ function type_more_complex(@nospecialize(t), @nospecialize(c), sources::SimpleVe
304302
return true
305303
end
306304

307-
function type_too_complex(@nospecialize(t), d::Int)
308-
if d < 0
309-
return true
310-
elseif isa(t, Union)
311-
return type_too_complex(t.a, d - 1) || type_too_complex(t.b, d - 1)
312-
elseif isa(t, TypeVar)
313-
return type_too_complex(t.lb, d - 1) || type_too_complex(t.ub, d - 1)
314-
elseif isa(t, UnionAll)
315-
return type_too_complex(t.var, d) || type_too_complex(t.body, d)
316-
elseif isa(t, DataType)
317-
for x in (t.parameters)::SimpleVector
318-
if type_too_complex(x, d - 1)
319-
return true
305+
function tmerge(@nospecialize(typea), @nospecialize(typeb))
306+
typea typeb && return typeb
307+
typeb typea && return typea
308+
if isa(typea, MaybeUndef) || isa(typeb, MaybeUndef)
309+
return MaybeUndef(tmerge(
310+
isa(typea, MaybeUndef) ? typea.typ : typea,
311+
isa(typeb, MaybeUndef) ? typeb.typ : typeb))
312+
end
313+
if isa(typea, Conditional) && isa(typeb, Conditional)
314+
if typea.var === typeb.var
315+
vtype = tmerge(typea.vtype, typeb.vtype)
316+
elsetype = tmerge(typea.elsetype, typeb.elsetype)
317+
if vtype != elsetype
318+
return Conditional(typea.var, vtype, elsetype)
320319
end
321320
end
321+
return Bool
322322
end
323-
return false
323+
typea, typeb = widenconst(typea), widenconst(typeb)
324+
typea === typeb && return typea
325+
if !(isa(typea, Type) || isa(typea, TypeVar)) ||
326+
!(isa(typeb, Type) || isa(typeb, TypeVar))
327+
# XXX: this should never happen
328+
return Any
329+
end
330+
# if we didn't start with any unions, then always OK to form one now
331+
if !(typea isa Union || typeb isa Union)
332+
# except if we might have switched Union and Tuple below, or would do so
333+
if (isconcretetype(typea) && isconcretetype(typeb)) || !(typea <: Tuple && typeb <: Tuple)
334+
return Union{typea, typeb}
335+
end
336+
end
337+
# collect the list of types from past tmerge calls returning Union
338+
# and then reduce over that list
339+
types = Any[]
340+
_uniontypes(typea, types)
341+
_uniontypes(typeb, types)
342+
typenames = Vector{Core.TypeName}(undef, length(types))
343+
for i in 1:length(types)
344+
# check that we will be able to analyze (and simplify) everything
345+
# bail if everything isn't a well-formed DataType
346+
ti = types[i]
347+
uw = unwrap_unionall(ti)
348+
(uw isa DataType && ti <: uw.name.wrapper) || return Any
349+
typenames[i] = uw.name
350+
end
351+
# see if any of the union elements have the same TypeName
352+
# in which case, simplify this tmerge by replacing it with
353+
# the widest possible version of itself (the wrapper)
354+
for i in 1:length(types)
355+
ti = types[i]
356+
for j in (i + 1):length(types)
357+
if typenames[i] === typenames[j]
358+
tj = types[j]
359+
if ti <: tj
360+
types[i] = Union{}
361+
break
362+
elseif tj <: ti
363+
types[j] = Union{}
364+
typenames[j] = Any.name
365+
else
366+
widen = typenames[i].wrapper
367+
if typenames[i] === Tuple.name
368+
# try to widen Tuple slower: make a single non-concrete Tuple containing both
369+
# converge the Tuple element-wise if they are the same length
370+
# see 4ee2b41552a6bc95465c12ca66146d69b354317b, be59686f7613a2ccfd63491c7b354d0b16a95c05,
371+
if nothing !== tuplelen(ti) === tuplelen(tj)
372+
widen = tuplemerge(ti, tj)
373+
end
374+
# TODO: else, try to merge them into a single Tuple{Vararg{T}} instead (#22120)?
375+
end
376+
types[i] = Union{}
377+
types[j] = widen
378+
break
379+
end
380+
end
381+
end
382+
end
383+
u = Union{types...}
384+
if unionlen(u) <= MAX_TYPEUNION_LEN
385+
# don't let type unions get too big, if the above didn't reduce it enough
386+
return u
387+
end
388+
# finally, just return the widest possible type
389+
return Any
390+
end
391+
392+
# the inverse of switchtupleunion, with limits on max element union size
393+
function tuplemerge(@nospecialize(a), @nospecialize(b))
394+
if isa(a, UnionAll)
395+
return UnionAll(a.var, tuplemerge(a.body, b))
396+
elseif isa(b, UnionAll)
397+
return UnionAll(b.var, tuplemerge(a, b.body))
398+
elseif isa(a, Union)
399+
return tuplemerge(tuplemerge(a.a, a.b), b)
400+
elseif isa(b, Union)
401+
return tuplemerge(a, tuplemerge(b.a, b.b))
402+
end
403+
a = a::DataType
404+
b = b::DataType
405+
ap, bp = a.parameters, b.parameters
406+
lar = length(ap)::Int
407+
lbr = length(bp)::Int
408+
@assert lar === lbr && a.name === b.name === Tuple.name "assertion failure"
409+
p = Vector{Any}(undef, lar)
410+
for i = 1:lar
411+
ui = Union{ap[i], bp[i]}
412+
if unionlen(ui) < MAX_TYPEUNION_LEN
413+
p[i] = ui
414+
else
415+
p[i] = Any
416+
end
417+
end
418+
return Tuple{p...}
324419
end

base/compiler/typeutils.jl

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3-
const _TYPE_NAME = Type.body.name
3+
#####################
4+
# lattice utilities #
5+
#####################
6+
7+
function rewrap(@nospecialize(t), @nospecialize(u))
8+
isa(t, Const) && return t
9+
isa(t, Conditional) && return t
10+
return rewrap_unionall(t, u)
11+
end
412

13+
const _TYPE_NAME = Type.body.name
514
isType(@nospecialize t) = isa(t, DataType) && (t::DataType).name === _TYPE_NAME
615

716
# true if Type{T} is inlineable as constant T
@@ -73,6 +82,19 @@ function tvar_extent(@nospecialize t)
7382
return t
7483
end
7584

85+
_typename(@nospecialize a) = Union{}
86+
_typename(a::TypeVar) = Core.TypeName
87+
function _typename(a::Union)
88+
ta = _typename(a.a)
89+
tb = _typename(a.b)
90+
ta === tb && return ta # same type-name
91+
(ta === Union{} || tb === Union{}) && return Union{} # threw an error
92+
(ta isa Const && tb isa Const) && return Union{} # will throw an error (different type-names)
93+
return Core.TypeName # uncertain result
94+
end
95+
_typename(union::UnionAll) = _typename(union.body)
96+
_typename(a::DataType) = Const(a.name)
97+
7698
function tuple_tail_elem(@nospecialize(init), ct)
7799
return Vararg{widenconst(foldl((a, b) -> tmerge(a, tvar_extent(unwrapva(b))), init, ct))}
78100
end
@@ -117,3 +139,23 @@ function _switchtupleunion(t::Vector{Any}, i::Int, tunion::Vector{Any}, @nospeci
117139
end
118140
return tunion
119141
end
142+
143+
tuplelen(@nospecialize tpl) = nothing
144+
function tuplelen(tpl::DataType)
145+
l = length(tpl.parameters)::Int
146+
if l > 0
147+
last = unwrap_unionall(tpl.parameters[l])
148+
if isvarargtype(last)
149+
N = last.parameters[2]
150+
N isa Int || return nothing
151+
l += N - 1
152+
end
153+
end
154+
return l
155+
end
156+
tuplelen(tpl::UnionAll) = tuplelen(tpl.body)
157+
function tuplelen(tpl::Union)
158+
la, lb = tuplelen(tpl.a), tuplelen(tpl.b)
159+
la == lb && return la
160+
return nothing
161+
end

0 commit comments

Comments
 (0)