Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Methods for bits to union variant and back #49298

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion base/compiler/typelimits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ union_count_abstract(x::Union) = union_count_abstract(x.a) + union_count_abstrac
union_count_abstract(@nospecialize(x)) = !isdispatchelem(x)

function issimpleenoughtype(@nospecialize t)
return unionlen(t) + union_count_abstract(t) <= MAX_TYPEUNION_LENGTH &&
return nvariants(t) + union_count_abstract(t) <= MAX_TYPEUNION_LENGTH &&
unioncomplexity(t) <= MAX_TYPEUNION_COMPLEXITY
end

Expand Down
2 changes: 1 addition & 1 deletion base/compiler/typeutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ function unionsplitcost(𝕃::AbstractLattice, argtypes::Union{SimpleVector,Vect
ti = widenconst(ti)
end
if isa(ti, Union)
nti = unionlen(ti)
nti = nvariants(ti)
if nti > max
max, nti = nti, max
end
Expand Down
2 changes: 2 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ end

# BEGIN 1.8 deprecations

@deprecate unionlen(t) nvariants(t)

const var"@_inline_meta" = var"@inline"
const var"@_noinline_meta" = var"@noinline"
@deprecate getindex(t::Tuple, i::Real) t[convert(Int, i)]
Expand Down
87 changes: 85 additions & 2 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -997,8 +997,91 @@ hasgenerator(m::Core.MethodInstance) = hasgenerator(m.def::Method)

# low-level method lookup functions used by the compiler

unionlen(x::Union) = unionlen(x.a) + unionlen(x.b)
unionlen(@nospecialize(x)) = 1
"""
Base.nvariants(T) -> Int

Returns the number of type variants that `T` represents.
"""
function nvariants(@nospecialize(t))
@_total_meta
n = 0
while isa(t, Union)
n += 1
t = t.b
end
return n
end

"""
Base.tag_to_variant(T, tag)

Returns the variant type of `T` associated with the union bits tag. If there is no variant
associate with `tag` then `Union{}` is returned.

# Examples

```jldoctest
julia> U = Union{Nothing, UInt8, UInt16, UInt32};

julia> tag = Base.variant_to_tag(U, UInt32);

julia> Base.tag_to_variant(U, tag) == UInt32
true
```

"""
function tag_to_variant(t::Union, tag)
@_total_meta
a = t.a
b = t.b
while true
tag == 0 && return a
isa(b, Union) || return (tag == 0 ? b : Union{})
a = b.a
b = b.b
tag -= 1
end
end
tag_to_variant(@nospecialize(t), tag) = tag == 0 ? t : Union{}

"""
Base.variant_to_tag(T, V)

Returns the tag for identifying the variant `V` in `T`. If `V` is not found in `U` then tag
will be `nvariants(T)`.

# Examples

```jldoctest
julia> U = Union{Nothing, UInt8, UInt16, UInt32};

julia> Base.tag_to_variant(U, Base.variant_to_tag(U, Nothing)) == Nothing
true

julia> tag = Base.variant_to_tag(U, Float64)
4

julia> Base.tag_to_variant(U, tag)
Union{}
```

"""
function variant_to_tag(t::Union, @nospecialize(vt))
@_total_meta
tag = 0
a = t.a
b = t.b
while true
vt <: a && return tag
tag += 1
# if last member of union doesn'vt match `vt` then return tag that will never be
# reached by `tag_to_variant`
isa(b, Union) || return (b == vt ? tag : (tag + 1))
a = b.a
b = b.b
end
end
variant_to_tag(@nospecialize(t), @nospecialize(vt)) = vt <: t ? 0 : 1

_uniontypes(x::Union, ts) = (_uniontypes(x.a,ts); _uniontypes(x.b,ts); ts)
_uniontypes(@nospecialize(x), ts) = (push!(ts, x); ts)
Expand Down
2 changes: 1 addition & 1 deletion base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ function make_typealiases(@nospecialize(x::Type))
continue
end
end
ul = unionlen(applied)
ul = nvariants(applied)
for p in xenv
applied = rewrap_unionall(applied, p)
end
Expand Down
2 changes: 1 addition & 1 deletion stdlib/InteractiveUtils/src/codeview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ end
# True if one can be pretty certain that the compiler handles this union well,
# i.e. must be small with concrete types.
function is_expected_union(u::Union)
Base.unionlen(u) < 4 || return false
Base.nvariants(u) < 4 || return false
for x in Base.uniontypes(u)
if !Base.isdispatchelem(x) || x == Core.Box
return false
Expand Down
12 changes: 6 additions & 6 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ let # 40336
@test t !== r && t <: r
end

@test Core.Compiler.unionlen(Union{}) == 1
@test Core.Compiler.unionlen(Int8) == 1
@test Core.Compiler.unionlen(Union{Int8, Int16}) == 2
@test Core.Compiler.unionlen(Union{Int8, Int16, Int32, Int64}) == 4
@test Core.Compiler.unionlen(Tuple{Union{Int8, Int16, Int32, Int64}}) == 1
@test Core.Compiler.unionlen(Union{Int8, Int16, Int32, T} where T) == 1
@test Core.Compiler.nvariants(Union{}) == 1
@test Core.Compiler.nvariants(Int8) == 1
@test Core.Compiler.nvariants(Union{Int8, Int16}) == 2
@test Core.Compiler.nvariants(Union{Int8, Int16, Int32, Int64}) == 4
@test Core.Compiler.nvariants(Tuple{Union{Int8, Int16, Int32, Int64}}) == 1
@test Core.Compiler.nvariants(Union{Int8, Int16, Int32, T} where T) == 1

@test Core.Compiler.unioncomplexity(Union{}) == 0
@test Core.Compiler.unioncomplexity(Int8) == 0
Expand Down