Skip to content

Commit e62b6e3

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 cac267c commit e62b6e3

27 files changed

+205
-120
lines changed

base/compiler/abstractinterpretation.jl

+19-6
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,8 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
546546
add_remark!(interp, sv, "Refusing to infer into `depwarn`")
547547
return MethodCallResult(Any, false, false, nothing, Effects())
548548
end
549+
sigtuple = unwrap_unionall(sig)
550+
sigtuple isa DataType || return MethodCallResult(Any, false, false, nothing, Effects())
549551

550552
# Limit argument type tuple growth of functions:
551553
# look through the parents list to see if there's a call to the same method
@@ -581,7 +583,6 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
581583
washardlimit = hardlimit
582584

583585
if topmost !== nothing
584-
sigtuple = unwrap_unionall(sig)::DataType
585586
msig = unwrap_unionall(method.sig)::DataType
586587
spec_len = length(msig.parameters) + 1
587588
ls = length(sigtuple.parameters)
@@ -1376,7 +1377,11 @@ function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft)
13761377
va = isvarargtype(last)
13771378
elts = Any[ fieldtype(tti0, i) for i = 1:len ]
13781379
if va
1379-
elts[len] = Vararg{elts[len]}
1380+
if elts[len] === Union{}
1381+
pop!(elts)
1382+
else
1383+
elts[len] = Vararg{elts[len]}
1384+
end
13801385
end
13811386
return AbstractIterationResult(elts, nothing)
13821387
end
@@ -1385,6 +1390,9 @@ function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft)
13851390
elseif tti0 === Any
13861391
return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects())
13871392
elseif tti0 <: Array
1393+
if eltype(tti0) === Union{}
1394+
return AbstractIterationResult(Any[], nothing)
1395+
end
13881396
return AbstractIterationResult(Any[Vararg{eltype(tti0)}], nothing)
13891397
else
13901398
return abstract_iteration(interp, itft, typ, sv)
@@ -2098,7 +2106,7 @@ end
20982106

20992107
function sp_type_rewrap(@nospecialize(T), linfo::MethodInstance, isreturn::Bool)
21002108
isref = false
2101-
if T === Bottom
2109+
if unwrapva(T) === Bottom
21022110
return Bottom
21032111
elseif isa(T, Type)
21042112
if isa(T, DataType) && (T::DataType).name === _REF_NAME
@@ -2135,8 +2143,13 @@ end
21352143
function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::VarTable, sv::InferenceState)
21362144
f = abstract_eval_value(interp, e.args[2], vtypes, sv)
21372145
# rt = sp_type_rewrap(e.args[3], sv.linfo, true)
2138-
at = Any[ sp_type_rewrap(argt, sv.linfo, false) for argt in e.args[4]::SimpleVector ]
2139-
pushfirst!(at, f)
2146+
atv = e.args[4]::SimpleVector
2147+
at = Vector{Any}(undef, length(atv) + 1)
2148+
at[1] = f
2149+
for i = 1:length(atv)
2150+
at[i + 1] = sp_type_rewrap(at[i], sv.linfo, false)
2151+
at[i + 1] === Bottom && return
2152+
end
21402153
# this may be the wrong world for the call,
21412154
# but some of the result is likely to be valid anyways
21422155
# and that may help generate better codegen
@@ -2339,7 +2352,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
23392352
let t = t, at = at; all(i::Int->getfield(at.val::Tuple, i) isa fieldtype(t, i), 1:n); end
23402353
nothrow = isexact
23412354
t = Const(ccall(:jl_new_structt, Any, (Any, Any), t, at.val))
2342-
elseif isa(at, PartialStruct) && at ᵢ Tuple && n == length(at.fields::Vector{Any}) &&
2355+
elseif isa(at, PartialStruct) && at ᵢ Tuple && n > 0 && n == length(at.fields::Vector{Any}) && !isvarargtype(at.fields[end]) &&
23432356
let t = t, at = at; all(i::Int->(at.fields::Vector{Any})[i] fieldtype(t, i), 1:n); end
23442357
nothrow = isexact
23452358
t = PartialStruct(t, at.fields::Vector{Any})

base/compiler/inferenceresult.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ function most_general_argtypes(method::Union{Method, Nothing}, @nospecialize(spe
119119
# to the appropriate `Tuple` type or `PartialStruct` instance.
120120
if !toplevel && isva
121121
if specTypes::Type == Tuple
122+
linfo_argtypes = Any[Any for i = 1:nargs]
122123
if nargs > 1
123-
linfo_argtypes = Any[Any for i = 1:nargs]
124-
linfo_argtypes[end] = Vararg{Any}
124+
linfo_argtypes[end] = Tuple
125125
end
126126
vargtype = Tuple
127127
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
@@ -1872,7 +1872,15 @@ add_tfunc(apply_type, 1, INT_INF, apply_type_tfunc, 10)
18721872
# convert the dispatch tuple type argtype to the real (concrete) type of
18731873
# the tuple of those values
18741874
function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
1875+
isempty(argtypes) && return Const(())
18751876
argtypes = anymap(widenslotwrapper, argtypes)
1877+
if isvarargtype(argtypes[end]) && unwrapva(argtypes[end]) === Union{}
1878+
# Drop the Vararg in Tuple{...,Vararg{Union{}}} since it must be length 0.
1879+
# If there is a Vararg num also, it must be a TypeVar, and it must be
1880+
# zero, but that generally shouldn't show up here, since it implies a
1881+
# UnionAll context is missing around this.
1882+
pop!(argtypes)
1883+
end
18761884
all_are_const = true
18771885
for i in 1:length(argtypes)
18781886
if !isa(argtypes[i], Const)
@@ -1915,6 +1923,8 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
19151923
params[i] = x
19161924
elseif !isvarargtype(x) && hasintersect(x, Type)
19171925
params[i] = Union{x, Type}
1926+
elseif x === Union{}
1927+
return Bottom # argtypes is malformed, but try not to crash
19181928
else
19191929
params[i] = x
19201930
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

+10-4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ if Base !== Core.Compiler
4141
export partition
4242
end
4343

44+
function TupleOrBottom(tt...)
45+
any(p -> p === Union{}, tt) && return Union{}
46+
return Tuple{tt...}
47+
end
48+
49+
4450
"""
4551
Iterators.map(f, iterators...)
4652
@@ -209,7 +215,7 @@ size(e::Enumerate) = size(e.itr)
209215
end
210216
last(e::Enumerate) = (length(e.itr), e.itr[end])
211217

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

214220
IteratorSize(::Type{Enumerate{I}}) where {I} = IteratorSize(I)
215221
IteratorEltype(::Type{Enumerate{I}}) where {I} = IteratorEltype(I)
@@ -394,7 +400,7 @@ _promote_tuple_shape((m,)::Tuple{Integer}, (n,)::Tuple{Integer}) = (min(m, n),)
394400
_promote_tuple_shape(a, b) = promote_shape(a, b)
395401
_promote_tuple_shape(a, b...) = _promote_tuple_shape(a, _promote_tuple_shape(b...))
396402
_promote_tuple_shape(a) = a
397-
eltype(::Type{Zip{Is}}) where {Is<:Tuple} = Tuple{map(eltype, fieldtypes(Is))...}
403+
eltype(::Type{Zip{Is}}) where {Is<:Tuple} = TupleOrBottom(map(eltype, fieldtypes(Is))...)
398404
#eltype(::Type{Zip{Tuple{}}}) = Tuple{}
399405
#eltype(::Type{Zip{Tuple{A}}}) where {A} = Tuple{eltype(A)}
400406
#eltype(::Type{Zip{Tuple{A, B}}}) where {A, B} = Tuple{eltype(A), eltype(B)}
@@ -1072,8 +1078,7 @@ end
10721078

10731079
eltype(::Type{ProductIterator{I}}) where {I} = _prod_eltype(I)
10741080
_prod_eltype(::Type{Tuple{}}) = Tuple{}
1075-
_prod_eltype(::Type{I}) where {I<:Tuple} =
1076-
Tuple{ntuple(n -> eltype(fieldtype(I, n)), _counttuple(I)::Int)...}
1081+
_prod_eltype(::Type{I}) where {I<:Tuple} = TupleOrBottom(ntuple(n -> eltype(fieldtype(I, n)), _counttuple(I)::Int)...)
10771082

10781083
iterate(::ProductIterator{Tuple{}}) = (), true
10791084
iterate(::ProductIterator{Tuple{}}, state) = nothing
@@ -1442,6 +1447,7 @@ end
14421447
function _approx_iter_type(itrT::Type, vstate::Type)
14431448
vstate <: Union{Nothing, Tuple{Any, Any}} || return Any
14441449
vstate <: Union{} && return Union{}
1450+
itrT <: Union{} && return Union{}
14451451
nextvstate = Base._return_type(doiterate, Tuple{itrT, vstate})
14461452
return (nextvstate <: vstate ? vstate : Any)
14471453
end

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
@@ -5146,7 +5146,7 @@ static std::pair<Function*, Function*> get_oc_function(jl_codectx_t &ctx, jl_met
51465146
for (size_t i = 0; i < jl_svec_len(argt_typ->parameters); ++i) {
51475147
jl_svecset(sig_args, 1+i, jl_svecref(argt_typ->parameters, i));
51485148
}
5149-
sigtype = (jl_value_t*)jl_apply_tuple_type_v(jl_svec_data(sig_args), nsig);
5149+
sigtype = jl_apply_tuple_type_v(jl_svec_data(sig_args), nsig);
51505150

51515151
jl_method_instance_t *mi = jl_specializations_get_linfo(closure_method, sigtype, jl_emptysvec);
51525152
jl_code_instance_t *ci = (jl_code_instance_t*)jl_rettype_inferred(mi, ctx.world, ctx.world);
@@ -5469,7 +5469,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
54695469

54705470
if (can_optimize) {
54715471
jl_value_t *closure_t = NULL;
5472-
jl_tupletype_t *env_t = NULL;
5472+
jl_value_t *env_t = NULL;
54735473
JL_GC_PUSH2(&closure_t, &env_t);
54745474

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

54805480
env_t = jl_apply_tuple_type_v(env_component_ts, nargs-4);
54815481
// we need to know the full env type to look up the right specialization
5482-
if (jl_is_concrete_type((jl_value_t*)env_t)) {
5482+
if (jl_is_concrete_type(env_t)) {
54835483
jl_tupletype_t *argt_typ = (jl_tupletype_t*)argt.constant;
54845484
Function *F, *specF;
5485-
std::tie(F, specF) = get_oc_function(ctx, (jl_method_t*)source.constant, env_t, argt_typ, ub.constant);
5485+
std::tie(F, specF) = get_oc_function(ctx, (jl_method_t*)source.constant, (jl_datatype_t*)env_t, argt_typ, ub.constant);
54865486
if (F) {
54875487
jl_cgval_t jlcall_ptr = mark_julia_type(ctx, F, false, jl_voidpointer_type);
54885488
jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe);
@@ -5495,7 +5495,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
54955495
fptr = mark_julia_type(ctx, (llvm::Value*)Constant::getNullValue(ctx.types().T_size), false, jl_voidpointer_type);
54965496

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

55005500
jl_cgval_t closure_fields[5] = {
55015501
env,
@@ -6441,7 +6441,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con
64416441
sigt = NULL;
64426442
}
64436443
else {
6444-
sigt = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)sigt);
6444+
sigt = jl_apply_tuple_type((jl_svec_t*)sigt);
64456445
}
64466446
if (sigt && !(unionall_env && jl_has_typevar_from_unionall(rt, unionall_env))) {
64476447
unionall_env = NULL;
@@ -6891,9 +6891,9 @@ static jl_datatype_t *compute_va_type(jl_method_instance_t *lam, size_t nreq)
68916891
}
68926892
jl_svecset(tupargs, i-nreq, argType);
68936893
}
6894-
jl_datatype_t *typ = jl_apply_tuple_type(tupargs);
6894+
jl_value_t *typ = jl_apply_tuple_type(tupargs);
68956895
JL_GC_POP();
6896-
return typ;
6896+
return (jl_datatype_t*)typ;
68976897
}
68986898

68996899

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)