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

RFC: allow Tuple{Union{}}, returning Union{} #53452

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ else
_return_type(@nospecialize(f), @nospecialize(t)) = Any
end

# return Tuple{tt...} if the all given elements may have instances, otherwise return Union{} if any cannot have instances
function TupleOrBottom(tt...)
any(p -> p === Union{}, tt) && return Union{}
return Tuple{tt...}
Expand Down
2 changes: 1 addition & 1 deletion src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1927,7 +1927,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
}
}
if (pi == jl_bottom_type)
jl_errorf("Tuple field type cannot be Union{}");
return jl_bottom_type;
if (cacheable && !jl_is_concrete_type(pi))
cacheable = 0;
}
Expand Down
6 changes: 6 additions & 0 deletions test/compiler/codegen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ end
# issue #41157
f41157(a, b) = a[1] = b[1]
@test_throws BoundsError f41157(Tuple{Int}[], (NTuple{N,Union{}} where N)[])
@test_throws BoundsError f41157(Tuple{Int}[], Tuple{Union{}}[])

# issue #41096
struct Modulate41096{M<:Union{Function, Val{true}, Val{false}}, id}
Expand Down Expand Up @@ -788,6 +789,11 @@ f_isa_type(@nospecialize(x)) = isa(x, Type)
f47247(a::Ref{Int}, b::Nothing) = setfield!(a, :x, b)
@test_throws TypeError f47247(Ref(5), nothing)

@testset "regression in generic_bitcast: should support Union{} values" begin
f(x) = Core.bitcast(UInt, Core.compilerbarrier(:type, x)::Int)
@test occursin("unreachable", get_llvm(f, Tuple{UInt}))
end

f48085(@nospecialize x...) = length(x)
@test Core.Compiler.get_compileable_sig(which(f48085, (Vararg{Any},)), Tuple{typeof(f48085), Vararg{Int}}, Core.svec()) === nothing
@test Core.Compiler.get_compileable_sig(which(f48085, (Vararg{Any},)), Tuple{typeof(f48085), Int, Vararg{Int}}, Core.svec()) === Tuple{typeof(f48085), Any, Vararg{Any}}
Expand Down
2 changes: 1 addition & 1 deletion test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1096,7 +1096,7 @@ end
g21771(T) = T
f21771(::Val{U}) where {U} = Tuple{g21771(U)}
@test @inferred(f21771(Val{Int}())) === Tuple{Int}
@test_throws ErrorException @inferred(f21771(Val{Union{}}()))
@test @inferred(f21771(Val{Union{}}())) === Union{}
@test @inferred(f21771(Val{Integer}())) === Tuple{Integer}

# PR #28284, check that constants propagate through calls to new
Expand Down
13 changes: 4 additions & 9 deletions test/subtype.jl
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ function test_old()
end

const easy_menagerie =
Any[Any, Int, Int8, Integer, Real,
Any[Bottom, Any, Int, Int8, Integer, Real,
Array{Int,1}, AbstractArray{Int,1},
Tuple{Int,Vararg{Integer}}, Tuple{Integer,Vararg{Int}}, Tuple{},
Union{Int,Int8},
Expand Down Expand Up @@ -635,10 +635,7 @@ end

add_variants!(easy_menagerie)
add_variants!(hard_menagerie)
push!(easy_menagerie, Bottom)
push!(easy_menagerie, Ref{Bottom})
push!(easy_menagerie, @UnionAll N NTuple{N,Bottom})
push!(easy_menagerie, @UnionAll S<:Bottom Ref{S})

const menagerie = [easy_menagerie; hard_menagerie]

Expand Down Expand Up @@ -685,11 +682,9 @@ function test_properties()
@test isequal_type(T, S) == isequal_type(Ref{T}, Ref{S})

# covariance
if T !== Bottom && S !== Bottom
@test issubTS == issub(Tuple{T}, Tuple{S})
@test issubTS == issub(Tuple{Vararg{T}}, Tuple{Vararg{S}})
@test issubTS == issub(Tuple{T}, Tuple{Vararg{S}})
end
@test issubTS == issub(Tuple{T}, Tuple{S})
@test issubTS == issub(Tuple{Vararg{T}}, Tuple{Vararg{S}})
@test issubTS == issub(Tuple{T}, Tuple{Vararg{S}})

# pseudo-contravariance
@test issubTS == issub(¬S, ¬T)
Expand Down
4 changes: 2 additions & 2 deletions test/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -803,8 +803,8 @@ namedtup = (;a=1, b=2, c=3)
# some basic equivalence handling tests for Union{} appearing in Tuple Vararg parameters
@test Tuple{} <: Tuple{Vararg{Union{}}}
@test Tuple{Int} <: Tuple{Int, Vararg{Union{}}}
@test_throws ErrorException("Tuple field type cannot be Union{}") Tuple{Int, Vararg{Union{},1}}
@test_throws ErrorException("Tuple field type cannot be Union{}") Tuple{Vararg{Union{},1}}
@test Tuple{Int, Vararg{Union{},1}} === Union{}
@test Tuple{Vararg{Union{},1}} === Union{}
@test Tuple{} <: Tuple{Vararg{Union{},N}} where N
@test !(Tuple{} >: Tuple{Vararg{Union{},N}} where N)

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@testset "#52385" begin
eagerzip() = error()
function eagerzip(args::AbstractArray...)
allequal(axes.(args)) || throw(DimensionMismatch())
Base.require_one_based_indexing(args...)
res = similar(first(args), Tuple{eltype.(args)...})
for i in eachindex(args...)
res[i] = getindex.(args, i)
end
res
end
@test isempty(eagerzip(Int[], []))
@test eltype(eagerzip(Int[], [])) === Tuple{Int64, Any}
@test isempty(eagerzip(Union{}[], []))
@test eltype(eagerzip(Union{}[], [])) === Union{}
end

Seems worthwhile to grab @LilithHafner's test case from #52385 (comment)

Expand Down