@@ -327,21 +327,95 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb))
327
327
# XXX : this should never happen
328
328
return Any
329
329
end
330
- if unionlen (typea) + unionlen (typeb) > MAX_TYPEUNION_LEN
330
+ # converge the Tuple part of the Union less quickly
331
+ # this is a bit more tricky than other branch, so
332
+ # do this first, so that the lattice is over Tuple is associative:
333
+ # tmerge(A, tmerge(B, C)) == tmerge(tmerge(A, B), C)
334
+ tuplea = typeintersect (typea, Tuple)
335
+ tupleb = typeintersect (typeb, Tuple)
336
+ if tuplea != = Union{} && tupleb != = Union{}
337
+ if isconcretetype (tuplea) && isconcretetype (tupleb)
338
+ # if the tuple part is concrete, try just returning the Union
339
+ u = Union{typea, typeb}
340
+ if unionlen (u) <= MAX_TYPEUNION_LEN
341
+ return u
342
+ end
343
+ end
344
+ # otherwise, make a single non-concrete Tuple containing both
345
+ tuplejoin = Tuple
346
+ if tuplea <: Tuple && tupleb <: Tuple
347
+ # converge the Tuple element-wise if they are the same length
348
+ # see 4ee2b41552a6bc95465c12ca66146d69b354317b, be59686f7613a2ccfd63491c7b354d0b16a95c05,
349
+ if nothing != = tuplelen (tuplea) === tuplelen (tupleb)
350
+ tuplejoin = tuplemerge (tuplea, tupleb)
351
+ end
352
+ # TODO : else, merge them into a single Tuple{Vararg{T}} instead (#22120)?
353
+ end
354
+ # now rejoin it with the rest of the type union elements
355
+ typea = Union{tuplejoin, typea}
356
+ end
357
+ u = Union{typea, typeb}
358
+ if unionlen (u) <= MAX_TYPEUNION_LEN
331
359
# don't let type unions get too big
332
360
# this sets our convergence rate (e.g. worst-case compiler performance)
333
- namea, nameb = _typename (typea), _typename (typeb)
334
- if namea isa Const && nameb isa Const && namea. val === nameb. val
335
- # If they have the same type name, widen to that instead
336
- # of widening fully (or using a slower convergence like typejoin)
337
- wrapper = (namea. val:: Core.TypeName ). wrapper
338
- if typea <: wrapper && typeb <: wrapper
339
- # This can happen when a typevar has bounds too wide for its context
340
- return wrapper
361
+ return u
362
+ end
363
+ # see if either of them is a DataType
364
+ # which can be used to collapse the Union
365
+ # by swapping it for the widest possible version
366
+ # of itself (the wrapper)
367
+ # this currently violates associativity, which reduces the predictability
368
+ # of the result but is not inherently wrong
369
+ # TODO : instead, call `uniontypes` on `u`, and swap all of the results for their wrappers
370
+ unwrapa = unwrap_unionall (typea)
371
+ unwrapb = unwrap_unionall (typeb)
372
+ if unwrapa isa DataType
373
+ wrapa = unwrapa. name. wrapper
374
+ if typea <: wrapa
375
+ u = Union{wrapa, typeb}
376
+ if unionlen (u) <= MAX_TYPEUNION_LEN
377
+ return u
341
378
end
342
379
end
343
- # TODO : something smarter, like a common supertype?
344
- return Any
380
+ elseif unwrapb isa DataType
381
+ wrapb = unwrapb. name. wrapper
382
+ if typeb <: wrapb
383
+ u = Union{typea, wrapb}
384
+ if unionlen (u) <= MAX_TYPEUNION_LEN
385
+ return u
386
+ end
387
+ end
388
+ end
389
+ # finally, just return the widest possible type
390
+ return Any
391
+ end
392
+
393
+ # the inverse of switchtupleunion, with limits on max element union size
394
+ function tuplemerge (@nospecialize (a), @nospecialize (b))
395
+ if isa (a, UnionAll)
396
+ return UnionAll (a. var, tuplemerge (a. body, b))
397
+ elseif isa (b, UnionAll)
398
+ return UnionAll (b. var, tuplemerge (a, b. body))
399
+ elseif isa (a, Union)
400
+ return tuplemerge (tuplemerge (a. a, a. b), b)
401
+ elseif isa (b, Union)
402
+ return tuplemerge (a, tuplemerge (b. a, b. b))
403
+ end
404
+ a = a:: DataType
405
+ b = b:: DataType
406
+ ap, bp = a. parameters, b. parameters
407
+ lar = length (ap):: Int
408
+ lbr = length (bp):: Int
409
+ @assert lar === lbr && a. name === b. name === Tuple. name " assertion failure"
410
+ p = Vector {Any} (undef, lar)
411
+ for i = 1 : lar
412
+ api = ap[i]
413
+ bpi = bp[i]
414
+ if unionlen (unwrap_unionall (api)) + unionlen (unwrap_unionall (bpi)) > MAX_TYPEUNION_LEN
415
+ p[i] = Any
416
+ else
417
+ p[i] = Union{api, bpi}
418
+ end
345
419
end
346
- return Union{typea, typeb }
420
+ return Tuple{p ... }
347
421
end
0 commit comments