diff --git a/NEWS.md b/NEWS.md index c98fa6b862b67..fd8f77fa957e3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -35,6 +35,8 @@ Language changes expression within a given `:toplevel` expression to make use of macros defined earlier in the same `:toplevel` expression. ([#53515]) + - `Base.Bottom`, an alias for the `Union{}` type, is deleted. + Compiler/Runtime improvements ----------------------------- diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 8d60a2443ba47..73c78427e9584 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -237,7 +237,7 @@ UInt8 ``` """ eltype(::Type) = Any -eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements")) +eltype(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements")) eltype(x) = eltype(typeof(x)) eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any diff --git a/base/compiler/compiler.jl b/base/compiler/compiler.jl index 9aecdaad51aa5..14a2072d02de1 100644 --- a/base/compiler/compiler.jl +++ b/base/compiler/compiler.jl @@ -79,6 +79,9 @@ const NUM_EFFECTS_OVERRIDES = 10 # sync with julia.h # essential files and libraries include("essentials.jl") + +const Bottom = Union{} + include("ctypes.jl") include("generator.jl") include("reflection.jl") diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index dd4c8d64e7d4e..8f40ed84cd920 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -3186,8 +3186,9 @@ Any Union{} `Union{}`, the empty [`Union`](@ref) of types, is the type that has no values. That is, it has the defining -property `isa(x, Union{}) == false` for any `x`. `Base.Bottom` is defined as its alias and the type of `Union{}` -is `Core.TypeofBottom`. +property `isa(x, Union{}) == false` for any `x`. + +The type of `Union{}` is `Core.TypeofBottom`. # Examples ```jldoctest @@ -3195,7 +3196,7 @@ julia> isa(nothing, Union{}) false ``` """ -kw"Union{}", Base.Bottom +kw"Union{}" """ Union{Types...} diff --git a/base/error.jl b/base/error.jl index d169cdc8085ac..58789443169f2 100644 --- a/base/error.jl +++ b/base/error.jl @@ -67,8 +67,8 @@ exception will continue propagation as if it had not been caught. `throw(e)` will preserve the root cause exception on the stack, as described in [`current_exceptions`](@ref). """ -rethrow() = ccall(:jl_rethrow, Bottom, ()) -rethrow(@nospecialize(e)) = ccall(:jl_rethrow_other, Bottom, (Any,), e) +rethrow() = ccall(:jl_rethrow, Union{}, ()) +rethrow(@nospecialize(e)) = ccall(:jl_rethrow_other, Union{}, (Any,), e) struct InterpreterIP code::Union{CodeInfo,Core.MethodInstance,Core.CodeInstance,Nothing} diff --git a/base/essentials.jl b/base/essentials.jl index c4ce6dfbd4e3a..bb1fb5f9e5aa5 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -4,8 +4,6 @@ using Core: CodeInfo, SimpleVector, donotdelete, compilerbarrier, memoryrefnew, const Callable = Union{Function,Type} -const Bottom = Union{} - # Define minimal array interface here to help code used in macros: length(a::Array{T, 0}) where {T} = 1 length(a::Array{T, 1}) where {T} = getfield(a, :size)[1] diff --git a/base/promotion.jl b/base/promotion.jl index 689a4e4be8f39..70a9697828785 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -17,7 +17,7 @@ julia> typejoin(Int, Float64, ComplexF32) Number ``` """ -typejoin() = Bottom +typejoin() = Union{} typejoin(@nospecialize(t)) = (@_nospecializeinfer_meta; t) typejoin(@nospecialize(t), @nospecialize(s), @nospecialize(u)) = (@_foldable_meta; @_nospecializeinfer_meta; typejoin(typejoin(t, s), u)) typejoin(@nospecialize(t), @nospecialize(s), @nospecialize(u), ts...) = (@_foldable_meta; @_nospecializeinfer_meta; afoldl(typejoin, typejoin(t, s, u), ts...)) @@ -100,8 +100,8 @@ function typejoin(@nospecialize(a), @nospecialize(b)) if a.name === Type.body.name ap = a.parameters[1] bp = b.parameters[1] - if ((isa(ap,TypeVar) && ap.lb === Bottom && ap.ub === Any) || - (isa(bp,TypeVar) && bp.lb === Bottom && bp.ub === Any)) + if ((isa(ap,TypeVar) && ap.lb === Union{} && ap.ub === Any) || + (isa(bp,TypeVar) && bp.lb === Union{} && bp.ub === Any)) # handle special Type{T} supertype return Type end @@ -143,7 +143,7 @@ function typesplit(@nospecialize(a), @nospecialize(b)) @_foldable_meta @_nospecializeinfer_meta if a <: b - return Bottom + return Union{} end if isa(a, Union) return Union{typesplit(a.a, b), @@ -247,7 +247,7 @@ function tailjoin(A::SimpleVector, i::Int) if i > length(A) return unwrapva(A[end]) end - t = Bottom + t = Union{} for j = i:length(A) t = typejoin(t, unwrapva(A[j])) end @@ -298,23 +298,23 @@ UInt16 """ function promote_type end -promote_type() = Bottom +promote_type() = Union{} promote_type(T) = T promote_type(T, S, U) = (@inline; promote_type(promote_type(T, S), U)) promote_type(T, S, U, V...) = (@inline; afoldl(promote_type, promote_type(T, S, U), V...)) -promote_type(::Type{Bottom}, ::Type{Bottom}) = Bottom +promote_type(::Type{Union{}}, ::Type{Union{}}) = Union{} promote_type(::Type{T}, ::Type{T}) where {T} = T -promote_type(::Type{T}, ::Type{Bottom}) where {T} = T -promote_type(::Type{Bottom}, ::Type{T}) where {T} = T +promote_type(::Type{T}, ::Type{Union{}}) where {T} = T +promote_type(::Type{Union{}}, ::Type{T}) where {T} = T function promote_type(::Type{T}, ::Type{S}) where {T,S} @inline # Try promote_rule in both orders. Typically only one is defined, - # and there is a fallback returning Bottom below, so the common case is + # and there is a fallback returning `Union{}` below, so the common case is # promote_type(T, S) => - # promote_result(T, S, result, Bottom) => - # typejoin(result, Bottom) => result + # promote_result(T, S, result, Union{}) => + # typejoin(result, Union{}) => result promote_result(T, S, promote_rule(T,S), promote_rule(S,T)) end @@ -327,18 +327,18 @@ it for new types as appropriate. """ function promote_rule end -promote_rule(::Type, ::Type) = Bottom +promote_rule(::Type, ::Type) = Union{} # Define some methods to avoid needing to enumerate unrelated possibilities when presented # with Type{<:T}, and return a value in general accordance with the result given by promote_type -promote_rule(::Type{Bottom}, slurp...) = Bottom -promote_rule(::Type{Bottom}, ::Type{Bottom}, slurp...) = Bottom # not strictly necessary, since the next method would match unambiguously anyways -promote_rule(::Type{Bottom}, ::Type{T}, slurp...) where {T} = T -promote_rule(::Type{T}, ::Type{Bottom}, slurp...) where {T} = T +promote_rule(::Type{Union{}}, slurp...) = Union{} +promote_rule(::Type{Union{}}, ::Type{Union{}}, slurp...) = Union{} # not strictly necessary, since the next method would match unambiguously anyways +promote_rule(::Type{Union{}}, ::Type{T}, slurp...) where {T} = T +promote_rule(::Type{T}, ::Type{Union{}}, slurp...) where {T} = T promote_result(::Type,::Type,::Type{T},::Type{S}) where {T,S} = (@inline; promote_type(T,S)) -# If no promote_rule is defined, both directions give Bottom. In that +# If no promote_rule is defined, both directions give `Union{}`. In that # case use typejoin on the original types instead. -promote_result(::Type{T},::Type{S},::Type{Bottom},::Type{Bottom}) where {T,S} = (@inline; typejoin(T, S)) +promote_result(::Type{T},::Type{S},::Type{Union{}},::Type{Union{}}) where {T,S} = (@inline; typejoin(T, S)) """ promote(xs...) diff --git a/base/reflection.jl b/base/reflection.jl index 7f9772e5ec976..4a5fee709d7d9 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -817,14 +817,14 @@ function isidentityfree(@nospecialize(t)) return false end -iskindtype(@nospecialize t) = (t === DataType || t === UnionAll || t === Union || t === typeof(Bottom)) +iskindtype(@nospecialize t) = (t === DataType || t === UnionAll || t === Union || t === typeof(Union{})) isconcretedispatch(@nospecialize t) = isconcretetype(t) && !iskindtype(t) has_free_typevars(@nospecialize(t)) = (@_total_meta; ccall(:jl_has_free_typevars, Cint, (Any,), t) != 0) # equivalent to isa(v, Type) && isdispatchtuple(Tuple{v}) || v === Union{} # and is thus perhaps most similar to the old (pre-1.0) `isleaftype` query function isdispatchelem(@nospecialize v) - return (v === Bottom) || (v === typeof(Bottom)) || isconcretedispatch(v) || + return (v === Union{}) || (v === typeof(Union{})) || isconcretedispatch(v) || (isType(v) && !has_free_typevars(v)) end @@ -2513,9 +2513,9 @@ false function isambiguous(m1::Method, m2::Method; ambiguous_bottom::Bool=false) m1 === m2 && return false ti = typeintersect(m1.sig, m2.sig) - ti === Bottom && return false + ti === Union{} && return false function inner(ti) - ti === Bottom && return false + ti === Union{} && return false if !ambiguous_bottom has_bottom_parameter(ti) && return false end @@ -2623,7 +2623,7 @@ function has_bottom_parameter(t::DataType) end return false end -has_bottom_parameter(t::typeof(Bottom)) = true +has_bottom_parameter(t::typeof(Union{})) = true has_bottom_parameter(t::UnionAll) = has_bottom_parameter(unwrap_unionall(t)) has_bottom_parameter(t::Union) = has_bottom_parameter(t.a) & has_bottom_parameter(t.b) has_bottom_parameter(t::TypeVar) = has_bottom_parameter(t.ub) diff --git a/base/show.jl b/base/show.jl index c1ad45af5cc83..18a3d3bd688fa 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2781,7 +2781,7 @@ function show(io::IO, tv::TypeVar) # If we are in the `unionall_env`, the type-variable is bound # and the type constraints are already printed. # We don't need to print it again. - # Otherwise, the lower bound should be printed if it is not `Bottom` + # Otherwise, the lower bound should be printed if it is not `Union{}` # and the upper bound should be printed if it is not `Any`. in_env = (:unionall_env => tv) in io function show_bound(io::IO, @nospecialize(b)) @@ -2791,7 +2791,7 @@ function show(io::IO, tv::TypeVar) parens && print(io, ")") end lb, ub = tv.lb, tv.ub - if !in_env && lb !== Bottom + if !in_env && lb !== Union{} if ub === Any show_unquoted(io, tv.name) print(io, ">:") diff --git a/base/tuple.jl b/base/tuple.jl index fc213410cfd7c..bdb04ccffda92 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -266,7 +266,7 @@ first(t::Tuple) = t[1] # eltype -eltype(::Type{Tuple{}}) = Bottom +eltype(::Type{Tuple{}}) = Union{} # the <: here makes the runtime a bit more complicated (needing to check isdefined), but really helps inference eltype(t::Type{<:Tuple{Vararg{E}}}) where {E} = @isdefined(E) ? (E isa Type ? E : Union{}) : _compute_eltype(t) eltype(t::Type{<:Tuple}) = _compute_eltype(t) diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index 835988ddf149f..e791dbacaef2f 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -15,7 +15,7 @@ export apropos, edit, less, code_warntype, code_llvm, code_native, methodswith, import Base.Docs.apropos -using Base: unwrap_unionall, rewrap_unionall, isdeprecated, Bottom, summarysize, +using Base: unwrap_unionall, rewrap_unionall, isdeprecated, summarysize, signature_type, format_bytes using Base.Libc using Markdown @@ -268,7 +268,7 @@ function _subtypes_in!(mods::Array, x::Type) if isa(dt, DataType) if dt.name.name === s && dt.name.module == m && supertype(dt).name == xt.name ti = typeintersect(t, x) - ti != Bottom && push!(sts, ti) + ti != Union{} && push!(sts, ti) end elseif isa(t, Module) && nameof(t) === s && parentmodule(t) === m && t !== m t === Base || push!(mods, t) # exclude Base, since it also parented by Main diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index 7600457812f66..42ee53d79db3f 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -7,7 +7,7 @@ Provide serialization of Julia objects via the functions """ module Serialization -import Base: Bottom, unsafe_convert +import Base: unsafe_convert import Core: svec, SimpleVector using Base: unaliascopy, unwrap_unionall, require_one_based_indexing, ntupleany using Core.IR @@ -62,7 +62,7 @@ const TAGS = Any[ ReturnNode, GotoIfNot, fill(Symbol, n_reserved_tags)..., - (), Bool, Any, Bottom, Core.TypeofBottom, Type, svec(), Tuple{}, false, true, nothing, + (), Bool, Any, Union{}, Core.TypeofBottom, Type, svec(), Tuple{}, false, true, nothing, :Any, :Array, :TypeVar, :Box, :Tuple, :Ptr, :return, :call, Symbol("::"), :Function, :(=), :(==), :(===), :gotoifnot, :A, :B, :C, :M, :N, :T, :S, :X, :Y, :a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m, :n, :o, :p, :q, :r, :s, :t, :u, :v, :w, :x, :y, :z, :add_int, @@ -120,7 +120,7 @@ const TYPENAME_TAG = sertag(Core.TypeName) const INT32_TAG = sertag(Int32) const INT64_TAG = sertag(Int64) const GLOBALREF_TAG = sertag(GlobalRef) -const BOTTOM_TAG = sertag(Bottom) +const BOTTOM_TAG = sertag(Union{}) const UNIONALL_TAG = sertag(UnionAll) const STRING_TAG = sertag(String) const o0 = sertag(SSAValue) @@ -652,7 +652,7 @@ for i in 0:13 @eval serialize(s::AbstractSerializer, n::$ty) = (writetag(s.io, $tag); write(s.io, n); nothing) end -serialize(s::AbstractSerializer, ::Type{Bottom}) = write_as_tag(s.io, BOTTOM_TAG) +serialize(s::AbstractSerializer, ::Type{Union{}}) = write_as_tag(s.io, BOTTOM_TAG) function serialize(s::AbstractSerializer, u::UnionAll) writetag(s.io, UNIONALL_TAG)