|
4 | 4 | # limitation parameters #
|
5 | 5 | #########################
|
6 | 6 |
|
7 |
| -const MAX_TYPEUNION_LEN = 3 |
8 |
| -const MAX_TYPE_DEPTH = 8 |
| 7 | +const MAX_TYPEUNION_LEN = 4 |
9 | 8 | const MAX_INLINE_CONST_SIZE = 256
|
10 |
| -const TUPLE_COMPLEXITY_LIMIT_DEPTH = 3 |
11 | 9 |
|
12 | 10 | #########################
|
13 | 11 | # limitation heuristics #
|
|
31 | 29 | # limit the complexity of type `t` to be simpler than the comparison type `compare`
|
32 | 30 | # no new values may be introduced, so the parameter `source` encodes the set of all values already present
|
33 | 31 | # 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) |
35 | 33 | source = svec(unwrap_unionall(compare), unwrap_unionall(source))
|
36 | 34 | 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 |
38 | 36 | r = _limit_type_size(t, compare, source, 1, allowed_tuplelen)
|
39 | 37 | @assert t <: r
|
40 | 38 | #@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
|
304 | 302 | return true
|
305 | 303 | end
|
306 | 304 |
|
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) |
320 | 319 | end
|
321 | 320 | end
|
| 321 | + return Bool |
322 | 322 | 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...} |
324 | 419 | end
|
0 commit comments