Skip to content

Commit ea6bcd5

Browse files
committed
make Tuple{Union{}} unconstructable
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 f2cbca6 commit ea6bcd5

30 files changed

+221
-133
lines changed

base/broadcast.jl

+10-6
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

+19-6
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

+2-2
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

+1-1
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

+10
Original file line numberDiff line numberDiff line change
@@ -1880,7 +1880,15 @@ add_tfunc(apply_type, 1, INT_INF, apply_type_tfunc, 10)
18801880
# convert the dispatch tuple type argtype to the real (concrete) type of
18811881
# the tuple of those values
18821882
function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
1883+
isempty(argtypes) && return Const(())
18831884
argtypes = anymap(widenslotwrapper, argtypes)
1885+
if isvarargtype(argtypes[end]) && unwrapva(argtypes[end]) === Union{}
1886+
# Drop the Vararg in Tuple{...,Vararg{Union{}}} since it must be length 0.
1887+
# If there is a Vararg num also, it must be a TypeVar, and it must be
1888+
# zero, but that generally shouldn't show up here, since it implies a
1889+
# UnionAll context is missing around this.
1890+
pop!(argtypes)
1891+
end
18841892
all_are_const = true
18851893
for i in 1:length(argtypes)
18861894
if !isa(argtypes[i], Const)
@@ -1923,6 +1931,8 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
19231931
params[i] = x
19241932
elseif !isvarargtype(x) && hasintersect(x, Type)
19251933
params[i] = Union{x, Type}
1934+
elseif x === Union{}
1935+
return Bottom # argtypes is malformed, but try not to crash
19261936
else
19271937
params[i] = x
19281938
end

base/compiler/typeutils.jl

+1
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

+5-5
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

+11-1
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

+2-1
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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ JL_CALLABLE(jl_f_apply_type)
13181318
jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi);
13191319
}
13201320
}
1321-
return (jl_value_t*)jl_apply_tuple_type_v(&args[1], nargs-1);
1321+
return jl_apply_tuple_type_v(&args[1], nargs-1);
13221322
}
13231323
else if (args[0] == (jl_value_t*)jl_uniontype_type) {
13241324
// Union{} has extra restrictions, so it needs to be checked after

src/codegen.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -5152,7 +5152,7 @@ static std::pair<Function*, Function*> get_oc_function(jl_codectx_t &ctx, jl_met
51525152
for (size_t i = 0; i < jl_svec_len(argt_typ->parameters); ++i) {
51535153
jl_svecset(sig_args, 1+i, jl_svecref(argt_typ->parameters, i));
51545154
}
5155-
sigtype = (jl_value_t*)jl_apply_tuple_type_v(jl_svec_data(sig_args), nsig);
5155+
sigtype = jl_apply_tuple_type_v(jl_svec_data(sig_args), nsig);
51565156

51575157
jl_method_instance_t *mi = jl_specializations_get_linfo(closure_method, sigtype, jl_emptysvec);
51585158
jl_code_instance_t *ci = (jl_code_instance_t*)jl_rettype_inferred(mi, ctx.world, ctx.world);
@@ -5475,7 +5475,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
54755475

54765476
if (can_optimize) {
54775477
jl_value_t *closure_t = NULL;
5478-
jl_tupletype_t *env_t = NULL;
5478+
jl_value_t *env_t = NULL;
54795479
JL_GC_PUSH2(&closure_t, &env_t);
54805480

54815481
jl_value_t **env_component_ts = (jl_value_t**)alloca(sizeof(jl_value_t*) * (nargs-4));
@@ -5485,10 +5485,10 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
54855485

54865486
env_t = jl_apply_tuple_type_v(env_component_ts, nargs-4);
54875487
// we need to know the full env type to look up the right specialization
5488-
if (jl_is_concrete_type((jl_value_t*)env_t)) {
5488+
if (jl_is_concrete_type(env_t)) {
54895489
jl_tupletype_t *argt_typ = (jl_tupletype_t*)argt.constant;
54905490
Function *F, *specF;
5491-
std::tie(F, specF) = get_oc_function(ctx, (jl_method_t*)source.constant, env_t, argt_typ, ub.constant);
5491+
std::tie(F, specF) = get_oc_function(ctx, (jl_method_t*)source.constant, (jl_datatype_t*)env_t, argt_typ, ub.constant);
54925492
if (F) {
54935493
jl_cgval_t jlcall_ptr = mark_julia_type(ctx, F, false, jl_voidpointer_type);
54945494
jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe);
@@ -5501,7 +5501,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
55015501
fptr = mark_julia_type(ctx, (llvm::Value*)Constant::getNullValue(ctx.types().T_size), false, jl_voidpointer_type);
55025502

55035503
// TODO: Inline the env at the end of the opaque closure and generate a descriptor for GC
5504-
jl_cgval_t env = emit_new_struct(ctx, (jl_value_t*)env_t, nargs-4, &argv.data()[4]);
5504+
jl_cgval_t env = emit_new_struct(ctx, env_t, nargs-4, &argv.data()[4]);
55055505

55065506
jl_cgval_t closure_fields[5] = {
55075507
env,
@@ -6447,7 +6447,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con
64476447
sigt = NULL;
64486448
}
64496449
else {
6450-
sigt = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)sigt);
6450+
sigt = jl_apply_tuple_type((jl_svec_t*)sigt);
64516451
}
64526452
if (sigt && !(unionall_env && jl_has_typevar_from_unionall(rt, unionall_env))) {
64536453
unionall_env = NULL;
@@ -6897,9 +6897,9 @@ static jl_datatype_t *compute_va_type(jl_method_instance_t *lam, size_t nreq)
68976897
}
68986898
jl_svecset(tupargs, i-nreq, argType);
68996899
}
6900-
jl_datatype_t *typ = jl_apply_tuple_type(tupargs);
6900+
jl_value_t *typ = jl_apply_tuple_type(tupargs);
69016901
JL_GC_POP();
6902-
return typ;
6902+
return (jl_datatype_t*)typ;
69036903
}
69046904

69056905

src/gf.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -1227,7 +1227,7 @@ static jl_method_instance_t *cache_method(
12271227
intptr_t nspec = (kwmt == NULL || kwmt == jl_type_type_mt || kwmt == jl_nonfunction_mt || kwmt == jl_kwcall_mt ? definition->nargs + 1 : jl_atomic_load_relaxed(&kwmt->max_args) + 2 + 2 * (mt == jl_kwcall_mt));
12281228
jl_compilation_sig(tt, sparams, definition, nspec, &newparams);
12291229
if (newparams) {
1230-
temp2 = (jl_value_t*)jl_apply_tuple_type(newparams);
1230+
temp2 = jl_apply_tuple_type(newparams);
12311231
// Now there may be a problem: the widened signature is more general
12321232
// than just the given arguments, so it might conflict with another
12331233
// definition that does not have cache instances yet. To fix this, we
@@ -1350,7 +1350,7 @@ static jl_method_instance_t *cache_method(
13501350
}
13511351
}
13521352
if (newparams) {
1353-
simplett = jl_apply_tuple_type(newparams);
1353+
simplett = (jl_datatype_t*)jl_apply_tuple_type(newparams);
13541354
temp2 = (jl_value_t*)simplett;
13551355
}
13561356

@@ -2513,7 +2513,7 @@ JL_DLLEXPORT jl_value_t *jl_normalize_to_compilable_sig(jl_methtable_t *mt, jl_t
25132513
jl_compilation_sig(ti, env, m, nspec, &newparams);
25142514
int is_compileable = ((jl_datatype_t*)ti)->isdispatchtuple;
25152515
if (newparams) {
2516-
tt = jl_apply_tuple_type(newparams);
2516+
tt = (jl_datatype_t*)jl_apply_tuple_type(newparams);
25172517
if (!is_compileable) {
25182518
// compute new env, if used below
25192519
jl_value_t *ti = jl_type_intersection_env((jl_value_t*)tt, (jl_value_t*)m->sig, &newparams);

src/intrinsics.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,7 @@ static Value *emit_untyped_intrinsic(jl_codectx_t &ctx, intrinsic f, Value **arg
14091409
jl_value_t *params[2];
14101410
params[0] = xtyp;
14111411
params[1] = (jl_value_t*)jl_bool_type;
1412-
jl_datatype_t *tuptyp = jl_apply_tuple_type_v(params, 2);
1412+
jl_datatype_t *tuptyp = (jl_datatype_t*)jl_apply_tuple_type_v(params, 2);
14131413
*newtyp = tuptyp;
14141414

14151415
Value *tupval;

src/jl_exported_funcs.inc

-1
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,6 @@
478478
XX(jl_try_substrtod) \
479479
XX(jl_try_substrtof) \
480480
XX(jl_tty_set_mode) \
481-
XX(jl_tupletype_fill) \
482481
XX(jl_typeassert) \
483482
XX(jl_typeinf_lock_begin) \
484483
XX(jl_typeinf_lock_end) \

0 commit comments

Comments
 (0)