Skip to content

Commit 35e4a1f

Browse files
authored
make Tuple{Union{}} unconstructable (#49111)
Type intersection assumed it was equal to Union{}, so this makes it unconstructable so that holds true. This is similar to what the NamedTuple constructor does. Secondarily, this fixes an inference bug where it would create Vararg{Union{}} and then incorrectly handle that fieldtype. - Fixes #32392 - Addresses part of the concerns discussed in #24614 (comment) - Addresses part of the issues presented in #26175 - May allow improving jl_type_equality_is_identity (https://github.com/JuliaLang/julia/pull/49017/files#diff-882927c6e612596e22406ae0d06adcee88a9ec05e8b61ad81b48942e2cb266e9R986) - May allow improving intersection (finish_unionall can be more aggressive at computing varval for any typevars that appears in covariant position and has lb=Union{} and ub=leaf type)
1 parent ea72b94 commit 35e4a1f

30 files changed

+219
-131
lines changed

base/broadcast.jl

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -732,17 +732,21 @@ broadcastable(x) = collect(x)
732732
broadcastable(::Union{AbstractDict, NamedTuple}) = throw(ArgumentError("broadcasting over dictionaries and `NamedTuple`s is reserved"))
733733

734734
## Computation of inferred result type, for empty and concretely inferred cases only
735-
_broadcast_getindex_eltype(bc::Broadcasted) = Base._return_type(bc.f, eltypes(bc.args))
735+
_broadcast_getindex_eltype(bc::Broadcasted) = combine_eltypes(bc.f, bc.args)
736736
_broadcast_getindex_eltype(A) = eltype(A) # Tuple, Array, etc.
737737

738738
eltypes(::Tuple{}) = Tuple{}
739-
eltypes(t::Tuple{Any}) = Tuple{_broadcast_getindex_eltype(t[1])}
740-
eltypes(t::Tuple{Any,Any}) = Tuple{_broadcast_getindex_eltype(t[1]), _broadcast_getindex_eltype(t[2])}
741-
eltypes(t::Tuple) = Tuple{_broadcast_getindex_eltype(t[1]), eltypes(tail(t)).types...}
739+
eltypes(t::Tuple{Any}) = Iterators.TupleOrBottom(_broadcast_getindex_eltype(t[1]))
740+
eltypes(t::Tuple{Any,Any}) = Iterators.TupleOrBottom(_broadcast_getindex_eltype(t[1]), _broadcast_getindex_eltype(t[2]))
741+
# eltypes(t::Tuple) = (TT = eltypes(tail(t)); TT === Union{} ? Union{} : Iterators.TupleOrBottom(_broadcast_getindex_eltype(t[1]), TT.parameters...))
742+
eltypes(t::Tuple) = Iterators.TupleOrBottom(ntuple(i -> _broadcast_getindex_eltype(t[i]), Val(length(t)))...)
742743

743744
# Inferred eltype of result of broadcast(f, args...)
744-
combine_eltypes(f, args::Tuple) =
745-
promote_typejoin_union(Base._return_type(f, eltypes(args)))
745+
function combine_eltypes(f, args::Tuple)
746+
argT = eltypes(args)
747+
argT === Union{} && return Union{}
748+
return promote_typejoin_union(Base._return_type(f, argT))
749+
end
746750

747751
## Broadcasting core
748752

base/compiler/abstractinterpretation.jl

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,8 @@ function abstract_call_method(interp::AbstractInterpreter,
541541
add_remark!(interp, sv, "Refusing to infer into `depwarn`")
542542
return MethodCallResult(Any, false, false, nothing, Effects())
543543
end
544+
sigtuple = unwrap_unionall(sig)
545+
sigtuple isa DataType || return MethodCallResult(Any, false, false, nothing, Effects())
544546

545547
# Limit argument type tuple growth of functions:
546548
# look through the parents list to see if there's a call to the same method
@@ -577,7 +579,6 @@ function abstract_call_method(interp::AbstractInterpreter,
577579
washardlimit = hardlimit
578580

579581
if topmost !== nothing
580-
sigtuple = unwrap_unionall(sig)::DataType
581582
msig = unwrap_unionall(method.sig)::DataType
582583
spec_len = length(msig.parameters) + 1
583584
ls = length(sigtuple.parameters)
@@ -1394,7 +1395,11 @@ function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft)
13941395
va = isvarargtype(last)
13951396
elts = Any[ fieldtype(tti0, i) for i = 1:len ]
13961397
if va
1397-
elts[len] = Vararg{elts[len]}
1398+
if elts[len] === Union{}
1399+
pop!(elts)
1400+
else
1401+
elts[len] = Vararg{elts[len]}
1402+
end
13981403
end
13991404
return AbstractIterationResult(elts, nothing)
14001405
end
@@ -1403,6 +1408,9 @@ function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft)
14031408
elseif tti0 === Any
14041409
return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects())
14051410
elseif tti0 <: Array
1411+
if eltype(tti0) === Union{}
1412+
return AbstractIterationResult(Any[], nothing)
1413+
end
14061414
return AbstractIterationResult(Any[Vararg{eltype(tti0)}], nothing)
14071415
else
14081416
return abstract_iteration(interp, itft, typ, sv)
@@ -2115,7 +2123,7 @@ end
21152123

21162124
function sp_type_rewrap(@nospecialize(T), linfo::MethodInstance, isreturn::Bool)
21172125
isref = false
2118-
if T === Bottom
2126+
if unwrapva(T) === Bottom
21192127
return Bottom
21202128
elseif isa(T, Type)
21212129
if isa(T, DataType) && (T::DataType).name === _REF_NAME
@@ -2152,8 +2160,13 @@ end
21522160
function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
21532161
f = abstract_eval_value(interp, e.args[2], vtypes, sv)
21542162
# rt = sp_type_rewrap(e.args[3], sv.linfo, true)
2155-
at = Any[ sp_type_rewrap(argt, frame_instance(sv), false) for argt in e.args[4]::SimpleVector ]
2156-
pushfirst!(at, f)
2163+
atv = e.args[4]::SimpleVector
2164+
at = Vector{Any}(undef, length(atv) + 1)
2165+
at[1] = f
2166+
for i = 1:length(atv)
2167+
at[i + 1] = sp_type_rewrap(at[i], frame_instance(sv), false)
2168+
at[i + 1] === Bottom && return
2169+
end
21572170
# this may be the wrong world for the call,
21582171
# but some of the result is likely to be valid anyways
21592172
# and that may help generate better codegen
@@ -2370,7 +2383,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
23702383
end))
23712384
nothrow = isexact
23722385
t = Const(ccall(:jl_new_structt, Any, (Any, Any), t, at.val))
2373-
elseif (isa(at, PartialStruct) && at ᵢ Tuple && n == length(at.fields::Vector{Any}) &&
2386+
elseif (isa(at, PartialStruct) && at ᵢ Tuple && n > 0 && n == length(at.fields::Vector{Any}) && !isvarargtype(at.fields[end]) &&
23742387
(let t = t, at = at, =
23752388
all(i::Int->(at.fields::Vector{Any})[i] fieldtype(t, i), 1:n)
23762389
end))

base/compiler/inferenceresult.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,9 @@ function most_general_argtypes(method::Union{Method, Nothing}, @nospecialize(spe
117117
# to the appropriate `Tuple` type or `PartialStruct` instance.
118118
if !toplevel && isva
119119
if specTypes::Type == Tuple
120+
linfo_argtypes = Any[Any for i = 1:nargs]
120121
if nargs > 1
121-
linfo_argtypes = Any[Any for i = 1:nargs]
122-
linfo_argtypes[end] = Vararg{Any}
122+
linfo_argtypes[end] = Tuple
123123
end
124124
vargtype = Tuple
125125
else

base/compiler/ssair/inlining.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,7 @@ function handle_invoke_call!(todo::Vector{Pair{Int,Any}},
11701170
if isa(result, ConstPropResult)
11711171
mi = result.result.linfo
11721172
validate_sparams(mi.sparam_vals) || return nothing
1173-
if argtypes_to_type(argtypes) <: mi.def.sig
1173+
if Union{} !== argtypes_to_type(argtypes) <: mi.def.sig
11741174
item = resolve_todo(mi, result.result, argtypes, info, flag, state; invokesig)
11751175
handle_single_case!(todo, ir, idx, stmt, item, OptimizationParams(state.interp), true)
11761176
return nothing

base/compiler/tfuncs.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,7 +1904,15 @@ add_tfunc(apply_type, 1, INT_INF, apply_type_tfunc, 10)
19041904
# convert the dispatch tuple type argtype to the real (concrete) type of
19051905
# the tuple of those values
19061906
function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
1907+
isempty(argtypes) && return Const(())
19071908
argtypes = anymap(widenslotwrapper, argtypes)
1909+
if isvarargtype(argtypes[end]) && unwrapva(argtypes[end]) === Union{}
1910+
# Drop the Vararg in Tuple{...,Vararg{Union{}}} since it must be length 0.
1911+
# If there is a Vararg num also, it must be a TypeVar, and it must be
1912+
# zero, but that generally shouldn't show up here, since it implies a
1913+
# UnionAll context is missing around this.
1914+
pop!(argtypes)
1915+
end
19081916
all_are_const = true
19091917
for i in 1:length(argtypes)
19101918
if !isa(argtypes[i], Const)
@@ -1947,6 +1955,8 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
19471955
params[i] = x
19481956
elseif !isvarargtype(x) && hasintersect(x, Type)
19491957
params[i] = Union{x, Type}
1958+
elseif x === Union{}
1959+
return Bottom # argtypes is malformed, but try not to crash
19501960
else
19511961
params[i] = x
19521962
end

base/compiler/typeutils.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ function typesubtract(@nospecialize(a), @nospecialize(b), max_union_splitting::I
187187
bp = b.parameters[i]
188188
(isvarargtype(ap) || isvarargtype(bp)) && return a
189189
ta[i] = typesubtract(ap, bp, min(2, max_union_splitting))
190+
ta[i] === Union{} && return Union{}
190191
return Tuple{ta...}
191192
end
192193
end

base/iterators.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ using .Base:
1212
@inline, Pair, Pairs, AbstractDict, IndexLinear, IndexStyle, AbstractVector, Vector,
1313
SizeUnknown, HasLength, HasShape, IsInfinite, EltypeUnknown, HasEltype, OneTo,
1414
@propagate_inbounds, @isdefined, @boundscheck, @inbounds, Generator,
15-
AbstractRange, AbstractUnitRange, UnitRange, LinearIndices,
15+
AbstractRange, AbstractUnitRange, UnitRange, LinearIndices, TupleOrBottom,
1616
(:), |, +, -, *, !==, !, ==, !=, <=, <, >, >=, missing,
1717
any, _counttuple, eachindex, ntuple, zero, prod, reduce, in, firstindex, lastindex,
1818
tail, fieldtypes, min, max, minimum, zero, oneunit, promote, promote_shape
@@ -209,7 +209,7 @@ size(e::Enumerate) = size(e.itr)
209209
end
210210
last(e::Enumerate) = (length(e.itr), e.itr[end])
211211

212-
eltype(::Type{Enumerate{I}}) where {I} = Tuple{Int, eltype(I)}
212+
eltype(::Type{Enumerate{I}}) where {I} = TupleOrBottom(Int, eltype(I))
213213

214214
IteratorSize(::Type{Enumerate{I}}) where {I} = IteratorSize(I)
215215
IteratorEltype(::Type{Enumerate{I}}) where {I} = IteratorEltype(I)
@@ -394,7 +394,7 @@ _promote_tuple_shape((m,)::Tuple{Integer}, (n,)::Tuple{Integer}) = (min(m, n),)
394394
_promote_tuple_shape(a, b) = promote_shape(a, b)
395395
_promote_tuple_shape(a, b...) = _promote_tuple_shape(a, _promote_tuple_shape(b...))
396396
_promote_tuple_shape(a) = a
397-
eltype(::Type{Zip{Is}}) where {Is<:Tuple} = Tuple{map(eltype, fieldtypes(Is))...}
397+
eltype(::Type{Zip{Is}}) where {Is<:Tuple} = TupleOrBottom(map(eltype, fieldtypes(Is))...)
398398
#eltype(::Type{Zip{Tuple{}}}) = Tuple{}
399399
#eltype(::Type{Zip{Tuple{A}}}) where {A} = Tuple{eltype(A)}
400400
#eltype(::Type{Zip{Tuple{A, B}}}) where {A, B} = Tuple{eltype(A), eltype(B)}
@@ -1072,8 +1072,7 @@ end
10721072

10731073
eltype(::Type{ProductIterator{I}}) where {I} = _prod_eltype(I)
10741074
_prod_eltype(::Type{Tuple{}}) = Tuple{}
1075-
_prod_eltype(::Type{I}) where {I<:Tuple} =
1076-
Tuple{ntuple(n -> eltype(fieldtype(I, n)), _counttuple(I)::Int)...}
1075+
_prod_eltype(::Type{I}) where {I<:Tuple} = TupleOrBottom(ntuple(n -> eltype(fieldtype(I, n)), _counttuple(I)::Int)...)
10771076

10781077
iterate(::ProductIterator{Tuple{}}) = (), true
10791078
iterate(::ProductIterator{Tuple{}}, state) = nothing
@@ -1442,6 +1441,7 @@ end
14421441
function _approx_iter_type(itrT::Type, vstate::Type)
14431442
vstate <: Union{Nothing, Tuple{Any, Any}} || return Any
14441443
vstate <: Union{} && return Union{}
1444+
itrT <: Union{} && return Union{}
14451445
nextvstate = Base._return_type(doiterate, Tuple{itrT, vstate})
14461446
return (nextvstate <: vstate ? vstate : Any)
14471447
end

base/promotion.jl

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,11 @@ else
472472
_return_type(@nospecialize(f), @nospecialize(t)) = Any
473473
end
474474

475+
function TupleOrBottom(tt...)
476+
any(p -> p === Union{}, tt) && return Union{}
477+
return Tuple{tt...}
478+
end
479+
475480
"""
476481
promote_op(f, argtypes...)
477482
@@ -483,7 +488,12 @@ Guess what an appropriate container eltype would be for storing results of
483488
the container eltype on the type of the actual elements. Only in the absence of any
484489
elements (for an empty result container), it may be unavoidable to call `promote_op`.
485490
"""
486-
promote_op(f, S::Type...) = _return_type(f, Tuple{S...})
491+
function promote_op(f, S::Type...)
492+
argT = TupleOrBottom(S...)
493+
argT === Union{} && return Union{}
494+
return _return_type(f, argT)
495+
end
496+
487497

488498
## catch-alls to prevent infinite recursion when definitions are missing ##
489499

base/slicearray.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ unitaxis(::AbstractArray) = Base.OneTo(1)
4040

4141
function Slices(A::P, slicemap::SM, ax::AX) where {P,SM,AX}
4242
N = length(ax)
43-
S = Base._return_type(view, Tuple{P, map((a,l) -> l === (:) ? Colon : eltype(a), axes(A), slicemap)...})
43+
argT = map((a,l) -> l === (:) ? Colon : eltype(a), axes(A), slicemap)
44+
S = Base.promote_op(view, P, argT...)
4445
Slices{P,SM,AX,S,N}(A, slicemap, ax)
4546
end
4647

src/builtins.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1320,7 +1320,7 @@ JL_CALLABLE(jl_f_apply_type)
13201320
jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi);
13211321
}
13221322
}
1323-
return (jl_value_t*)jl_apply_tuple_type_v(&args[1], nargs-1);
1323+
return jl_apply_tuple_type_v(&args[1], nargs-1);
13241324
}
13251325
else if (args[0] == (jl_value_t*)jl_uniontype_type) {
13261326
// Union{} has extra restrictions, so it needs to be checked after

0 commit comments

Comments
 (0)