@@ -529,11 +529,81 @@ function show(io::IO, @nospecialize(x::Type))
529
529
end
530
530
end
531
531
532
+ # The `:unionall_tvs` io context records typevar naming data, i.e. whether
533
+ # the typevar needs a corresponding `where` being printed or not.
534
+ # It is being filled recursively here first before printing the typevar
535
+ # itself.
536
+ io = IOContext (io, :unionall_tvs => _unionall_tvs (io))
537
+ _unionall_name_tvs (io, x)
538
+
539
+ # The `:unionall_env => tv::TypeVar` io context is used to signify that
540
+ # io is happening within the unionall environment of `tv`.
532
541
show (IOContext (io, :unionall_env => x. var), x. body)
533
- print (io, " where " )
534
- show (io, x. var)
542
+
543
+ if isnamed (io, x. var)
544
+ print (io, " where " )
545
+ show (io, x. var)
546
+ end
535
547
end
536
548
549
+ """
550
+ isgensym(x::Symbol)
551
+
552
+ Return whether `x` is an generated symbol, as generated by e.g.
553
+ [`gensym`](@ref).
554
+ """
555
+ isgensym (x:: Symbol ) = first (String (x)) == ' #'
556
+
557
+ _unionall_tvs (io:: IO ) = get (io, :unionall_tvs , IdDict {TypeVar,Int} ())
558
+ isnamed (io:: IO , tv:: TypeVar ) = get (_unionall_tvs (io), tv, 0 ) > 1
559
+ setnamed (io:: IO , tv:: TypeVar ) = setindex! (_unionall_tvs (io), 2 , tv)
560
+
561
+ function _unionall_name_tvs (io:: IO , @nospecialize x:: UnionAll )
562
+ # collect typevar naming candidates
563
+ tvs = TypeVar[]
564
+ y = x
565
+ while y isa UnionAll
566
+ # if it is named then this method was called already on a parent
567
+ isnamed (io, y. var) && return io
568
+ push! (tvs, y. var)
569
+ y = y. body
570
+ end
571
+
572
+ if y isa DataType
573
+ # count typevar occurrences within the body recursively
574
+ isempty (_unionall_tvs (io)) && _count_tvs! (_unionall_tvs (io), y)
575
+
576
+ for tv in reverse (collect (y. parameters))
577
+ tv isa TypeVar || continue
578
+ # might have been named above or earlier in the printing hierarchy
579
+ isnamed (io, tv) && continue
580
+
581
+ if last (tvs) == tv && (tv. lb == Bottom || tv. ub == Any)
582
+ # safe for elision
583
+ pop! (tvs)
584
+ isempty (tvs) && return io
585
+ else
586
+ setnamed (io, tv)
587
+ end
588
+ end
589
+ end
590
+
591
+ # remaining ones need to be named, since anonymizing further nested
592
+ # occurences is disallowed, includes e.g. y::Union
593
+ foreach (tv -> isnamed (io, tv) || setnamed (io, tv), tvs)
594
+ end
595
+
596
+ @nospecialize
597
+ _count_tvs! (counts) = counts
598
+ _count_tvs! (counts, x) = counts
599
+ _count_tvs! (counts, x:: TypeVar ) =
600
+ (setindex! (counts, get (counts, x, 0 ) + 1 , x); _count_tvs! (counts, x. lb, x. ub))
601
+ _count_tvs! (counts, x:: UnionAll ) = _count_tvs! (counts, x. var. lb, x. var. ub, x. body)
602
+ _count_tvs! (counts, x:: Union ) = _count_tvs! (counts, x. a, x. b)
603
+ _count_tvs! (counts, x:: DataType ) = _count_tvs! (counts, x. parameters... )
604
+ _count_tvs! (counts, x1, x2, x... ) = (_count_tvs! (counts, x1); _count_tvs! (counts, x2, x... ))
605
+ @specialize
606
+
537
607
# Check whether 'sym' (defined in module 'parent') is visible from module 'from'
538
608
# If an object with this name exists in 'from', we need to check that it's the same binding
539
609
# and that it's not deprecated.
@@ -596,12 +666,28 @@ function show_datatype(io::IO, x::DataType)
596
666
print (io, " NTuple{" , n, ' ,' , x. parameters[1 ], " }" )
597
667
else
598
668
show_type_name (io, x. name)
599
- # Do not print the type parameters for the primary type if we are
600
- # printing a method signature or type parameter.
601
- # Always print the type parameter if we are printing the type directly
602
- # since this information is still useful.
669
+
670
+ if ! istuple
671
+ # find out up until which parameter we need to print typevars
672
+ y = x. name. wrapper
673
+ n, j = 0 , 0
674
+ while y isa UnionAll
675
+ j += 1
676
+ tv = x. parameters[j]
677
+ if ! isa (tv, TypeVar) || isnamed (io, tv) || in (:tv_standalone => tv, io) ||
678
+ # can only elide when typevar constraints are
679
+ # the same as defined in the parametric type itself
680
+ isa (tv. lb, TypeVar) || isa (tv. ub, TypeVar) ||
681
+ ! (tv. lb == y. var. lb) || ! (tv. ub == y. var. ub)
682
+ n = j
683
+ end
684
+ y = y. body
685
+ end
686
+ n == 0 && return
687
+ end
688
+
603
689
print (io, ' {' )
604
- for (i, p) in enumerate (x. parameters)
690
+ for (i, p) in enumerate (x. parameters[ 1 : n] )
605
691
show (io, p)
606
692
i < n && print (io, ' ,' )
607
693
end
@@ -1780,7 +1866,7 @@ function show_tuple_as_call(io::IO, name::Symbol, sig::Type, demangle=false, kwa
1780
1866
env_io = io
1781
1867
while isa (sig, UnionAll)
1782
1868
push! (tv, sig. var)
1783
- env_io = IOContext (env_io, :unionall_env => sig. var)
1869
+ env_io = IOContext (env_io, :tv_standalone => sig. var)
1784
1870
sig = sig. body
1785
1871
end
1786
1872
sig = sig. parameters
@@ -1837,37 +1923,48 @@ function ismodulecall(ex::Expr)
1837
1923
end
1838
1924
1839
1925
function show (io:: IO , tv:: TypeVar )
1840
- # If we are in the `unionall_env`, the type-variable is bound
1841
- # and the type constraints are already printed.
1842
- # We don't need to print it again.
1843
- # Otherwise, the lower bound should be printed if it is not `Bottom`
1844
- # and the upper bound should be printed if it is not `Any`.
1845
- in_env = (:unionall_env => tv) in io
1846
1926
function show_bound (io:: IO , @nospecialize (b))
1847
1927
parens = isa (b,UnionAll) && ! print_without_params (b)
1848
1928
parens && print (io, " (" )
1849
1929
show (io, b)
1850
1930
parens && print (io, " )" )
1851
1931
end
1852
1932
lb, ub = tv. lb, tv. ub
1853
- if ! in_env && lb != = Bottom
1854
- if ub === Any
1855
- show_unquoted (io, tv. name)
1856
- print (io, " >:" )
1857
- show_bound (io, lb)
1858
- else
1933
+
1934
+ # the `:tv_standalone => tv::TypeVar` io context tells to print the typevar
1935
+ # `tv` without any typebounds, this is not necessarily related to being
1936
+ # within a unionall environment
1937
+ (:tv_standalone => tv) in io && return show_unquoted (io, tv. name)
1938
+
1939
+ if (:unionall_env => tv) in io
1940
+ # within unionall type argument for `tv`
1941
+ if isnamed (io, tv)
1942
+ # named typevars get their constraints printed after `where`
1943
+ return show_unquoted (io, tv. name)
1944
+ elseif lb == Bottom
1945
+ # anonymous upper bound, need to show `<:Any` even if trivial
1946
+ return print (io, " <:" , ub)
1947
+ elseif ub == Any
1948
+ # anonymous non-trivial lower bound
1949
+ return print (io, " >:" , lb)
1950
+ end
1951
+ @assert false
1952
+ elseif lb != Bottom && ub == Any
1953
+ show_unquoted (io, tv. name)
1954
+ print (io, " >:" )
1955
+ return show_bound (io, lb)
1956
+ else
1957
+ if lb != Bottom
1859
1958
show_bound (io, lb)
1860
1959
print (io, " <:" )
1861
- show_unquoted (io, tv. name)
1862
1960
end
1863
- else
1864
1961
show_unquoted (io, tv. name)
1962
+ if ub != Any
1963
+ print (io, " <:" )
1964
+ show_bound (io, ub)
1965
+ end
1865
1966
end
1866
- if ! in_env && ub != = Any
1867
- print (io, " <:" )
1868
- show_bound (io, ub)
1869
- end
1870
- nothing
1967
+ return nothing
1871
1968
end
1872
1969
1873
1970
module IRShow
@@ -2037,7 +2134,7 @@ function dump(io::IOContext, x::DataType, n::Int, indent)
2037
2134
# approximately recapture the list of tvar parameterization
2038
2135
# that may be used by the internal fields
2039
2136
if isa (tparam, TypeVar)
2040
- tvar_io = IOContext (tvar_io, :unionall_env => tparam)
2137
+ tvar_io = IOContext (tvar_io, :tv_standalone => tparam)
2041
2138
end
2042
2139
end
2043
2140
if x. name === NamedTuple_typename && ! (x. parameters[1 ] isa Tuple)
0 commit comments