Skip to content

Commit

Permalink
make Tuple{Union{}} unconstructable
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
vtjnash committed Mar 22, 2023
1 parent 6d678fe commit 07ced48
Show file tree
Hide file tree
Showing 22 changed files with 184 additions and 112 deletions.
22 changes: 17 additions & 5 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1375,7 +1375,11 @@ function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft)
va = isvarargtype(last)
elts = Any[ fieldtype(tti0, i) for i = 1:len ]
if va
elts[len] = Vararg{elts[len]}
if elts[len] === Union{}
pop!(elts)
else
elts[len] = Vararg{elts[len]}
end
end
return AbstractIterationResult(elts, nothing)
end
Expand All @@ -1384,6 +1388,9 @@ function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft)
elseif tti0 === Any
return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects())
elseif tti0 <: Array
if eltype(tti0) === Union{}
return AbstractIterationResult(Any[], nothing)
end
return AbstractIterationResult(Any[Vararg{eltype(tti0)}], nothing)
else
return abstract_iteration(interp, itft, typ, sv)
Expand Down Expand Up @@ -2097,7 +2104,7 @@ end

function sp_type_rewrap(@nospecialize(T), linfo::MethodInstance, isreturn::Bool)
isref = false
if T === Bottom
if unwrapva(T) === Bottom
return Bottom
elseif isa(T, Type)
if isa(T, DataType) && (T::DataType).name === _REF_NAME
Expand Down Expand Up @@ -2134,8 +2141,13 @@ end
function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::VarTable, sv::InferenceState)
f = abstract_eval_value(interp, e.args[2], vtypes, sv)
# rt = sp_type_rewrap(e.args[3], sv.linfo, true)
at = Any[ sp_type_rewrap(argt, sv.linfo, false) for argt in e.args[4]::SimpleVector ]
pushfirst!(at, f)
atv = e.args[4]::SimpleVector
at = Vector{Any}(undef, length(atv) + 1)
at[1] = f
for i = 1:length(atv)
at[i + 1] = sp_type_rewrap(at[i], sv.linfo, false)
at[i + 1] === Bottom && return
end
# this may be the wrong world for the call,
# but some of the result is likely to be valid anyways
# and that may help generate better codegen
Expand Down Expand Up @@ -2338,7 +2350,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
let t = t, at = at; all(i::Int->getfield(at.val::Tuple, i) isa fieldtype(t, i), 1:n); end
nothrow = isexact
t = Const(ccall(:jl_new_structt, Any, (Any, Any), t, at.val))
elseif isa(at, PartialStruct) && at ᵢ Tuple && n == length(at.fields::Vector{Any}) &&
elseif isa(at, PartialStruct) && at ᵢ Tuple && n > 0 && n == length(at.fields::Vector{Any}) && !isvarargtype(at.fields[end]) &&
let t = t, at = at; all(i::Int->(at.fields::Vector{Any})[i] fieldtype(t, i), 1:n); end
nothrow = isexact
t = PartialStruct(t, at.fields::Vector{Any})
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/inferenceresult.jl
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ function most_general_argtypes(method::Union{Method, Nothing}, @nospecialize(spe
# to the appropriate `Tuple` type or `PartialStruct` instance.
if !toplevel && isva
if specTypes::Type == Tuple
linfo_argtypes = Any[Any for i = 1:nargs]
if nargs > 1
linfo_argtypes = Any[Any for i = 1:nargs]
linfo_argtypes[end] = Vararg{Any}
linfo_argtypes[end] = Tuple
end
vargtype = Tuple
else
Expand Down
10 changes: 10 additions & 0 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1872,7 +1872,15 @@ add_tfunc(apply_type, 1, INT_INF, apply_type_tfunc, 10)
# convert the dispatch tuple type argtype to the real (concrete) type of
# the tuple of those values
function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
isempty(argtypes) && return Const(())
argtypes = anymap(widenslotwrapper, argtypes)
if isvarargtype(argtypes[end]) && unwrapva(argtypes[end]) === Union{}
# Drop the Vararg in Tuple{...,Vararg{Union{}}} since it must be length 0.
# If there is a Vararg num also, it must be a TypeVar, and it must be
# zero, but that generally shouldn't show up here, since it implies a
# UnionAll context is missing around this.
pop!(argtypes)
end
all_are_const = true
for i in 1:length(argtypes)
if !isa(argtypes[i], Const)
Expand Down Expand Up @@ -1915,6 +1923,8 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
params[i] = x
elseif !isvarargtype(x) && hasintersect(x, Type)
params[i] = Union{x, Type}
elseif x === Union{}
return Bottom # argtypes is malformed, but try not to crash
else
params[i] = x
end
Expand Down
2 changes: 1 addition & 1 deletion src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,7 @@ JL_CALLABLE(jl_f_apply_type)
jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi);
}
}
return (jl_value_t*)jl_apply_tuple_type_v(&args[1], nargs-1);
return jl_apply_tuple_type_v(&args[1], nargs-1);
}
else if (args[0] == (jl_value_t*)jl_uniontype_type) {
// Union{} has extra restrictions, so it needs to be checked after
Expand Down
16 changes: 8 additions & 8 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5146,7 +5146,7 @@ static std::pair<Function*, Function*> get_oc_function(jl_codectx_t &ctx, jl_met
for (size_t i = 0; i < jl_svec_len(argt_typ->parameters); ++i) {
jl_svecset(sig_args, 1+i, jl_svecref(argt_typ->parameters, i));
}
sigtype = (jl_value_t*)jl_apply_tuple_type_v(jl_svec_data(sig_args), nsig);
sigtype = jl_apply_tuple_type_v(jl_svec_data(sig_args), nsig);

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

if (can_optimize) {
jl_value_t *closure_t = NULL;
jl_tupletype_t *env_t = NULL;
jl_value_t *env_t = NULL;
JL_GC_PUSH2(&closure_t, &env_t);

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

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

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

jl_cgval_t closure_fields[5] = {
env,
Expand Down Expand Up @@ -6441,7 +6441,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con
sigt = NULL;
}
else {
sigt = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)sigt);
sigt = jl_apply_tuple_type((jl_svec_t*)sigt);
}
if (sigt && !(unionall_env && jl_has_typevar_from_unionall(rt, unionall_env))) {
unionall_env = NULL;
Expand Down Expand Up @@ -6891,9 +6891,9 @@ static jl_datatype_t *compute_va_type(jl_method_instance_t *lam, size_t nreq)
}
jl_svecset(tupargs, i-nreq, argType);
}
jl_datatype_t *typ = jl_apply_tuple_type(tupargs);
jl_value_t *typ = jl_apply_tuple_type(tupargs);
JL_GC_POP();
return typ;
return (jl_datatype_t*)typ;
}


Expand Down
6 changes: 3 additions & 3 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,7 @@ static jl_method_instance_t *cache_method(
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));
jl_compilation_sig(tt, sparams, definition, nspec, &newparams);
if (newparams) {
temp2 = (jl_value_t*)jl_apply_tuple_type(newparams);
temp2 = jl_apply_tuple_type(newparams);
// Now there may be a problem: the widened signature is more general
// than just the given arguments, so it might conflict with another
// definition that does not have cache instances yet. To fix this, we
Expand Down Expand Up @@ -1347,7 +1347,7 @@ static jl_method_instance_t *cache_method(
}
}
if (newparams) {
simplett = jl_apply_tuple_type(newparams);
simplett = (jl_datatype_t*)jl_apply_tuple_type(newparams);
temp2 = (jl_value_t*)simplett;
}

Expand Down Expand Up @@ -2510,7 +2510,7 @@ JL_DLLEXPORT jl_value_t *jl_normalize_to_compilable_sig(jl_methtable_t *mt, jl_t
jl_compilation_sig(ti, env, m, nspec, &newparams);
int is_compileable = ((jl_datatype_t*)ti)->isdispatchtuple;
if (newparams) {
tt = jl_apply_tuple_type(newparams);
tt = (jl_datatype_t*)jl_apply_tuple_type(newparams);
if (!is_compileable) {
// compute new env, if used below
jl_value_t *ti = jl_type_intersection_env((jl_value_t*)tt, (jl_value_t*)m->sig, &newparams);
Expand Down
2 changes: 1 addition & 1 deletion src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1409,7 +1409,7 @@ static Value *emit_untyped_intrinsic(jl_codectx_t &ctx, intrinsic f, Value **arg
jl_value_t *params[2];
params[0] = xtyp;
params[1] = (jl_value_t*)jl_bool_type;
jl_datatype_t *tuptyp = jl_apply_tuple_type_v(params, 2);
jl_datatype_t *tuptyp = (jl_datatype_t*)jl_apply_tuple_type_v(params, 2);
*newtyp = tuptyp;

Value *tupval;
Expand Down
1 change: 0 additions & 1 deletion src/jl_exported_funcs.inc
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,6 @@
XX(jl_try_substrtod) \
XX(jl_try_substrtof) \
XX(jl_tty_set_mode) \
XX(jl_tupletype_fill) \
XX(jl_typeassert) \
XX(jl_typeinf_lock_begin) \
XX(jl_typeinf_lock_end) \
Expand Down
50 changes: 36 additions & 14 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1033,7 +1033,7 @@ static jl_value_t *inst_datatype_env(jl_value_t *dt, jl_svec_t *p, jl_value_t **
jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n)
{
if (tc == (jl_value_t*)jl_anytuple_type)
return (jl_value_t*)jl_apply_tuple_type_v(params, n);
return jl_apply_tuple_type_v(params, n);
if (tc == (jl_value_t*)jl_uniontype_type)
return (jl_value_t*)jl_type_union(params, n);
size_t i;
Expand Down Expand Up @@ -1122,20 +1122,20 @@ jl_datatype_t *jl_apply_cmpswap_type(jl_value_t *dt)
}
params[0] = dt;
params[1] = (jl_value_t*)jl_bool_type;
jl_datatype_t *tuptyp = jl_apply_tuple_type_v(params, 2);
jl_datatype_t *tuptyp = (jl_datatype_t*)jl_apply_tuple_type_v(params, 2);
JL_GC_PROMISE_ROOTED(tuptyp); // (JL_ALWAYS_LEAFTYPE)
jl_datatype_t *rettyp = (jl_datatype_t*)jl_apply_type2((jl_value_t*)jl_namedtuple_type, names, (jl_value_t*)tuptyp);
JL_GC_PROMISE_ROOTED(rettyp); // (JL_ALWAYS_LEAFTYPE)
return rettyp;
}

JL_DLLEXPORT jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *v)
// used to expand an NTuple to a flat representation
static jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *v)
{
// TODO: replace with just using NTuple
jl_value_t *p = NULL;
JL_GC_PUSH1(&p);
p = (jl_value_t*)jl_svec_fill(n, v);
p = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)p);
p = jl_apply_tuple_type((jl_svec_t*)p);
JL_GC_POP();
return p;
}
Expand Down Expand Up @@ -1519,9 +1519,31 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
int cacheable = 1;
if (istuple) {
size_t i;
for (i = 0; cacheable && i < ntp; i++)
if (!jl_is_concrete_type(iparams[i]) && iparams[i] != jl_bottom_type)
for (i = 0; i < ntp; i++) {
jl_value_t *pi = iparams[i];
if (jl_is_vararg(pi) && jl_unwrap_vararg(pi) == jl_bottom_type) {
jl_value_t *va1 = jl_unwrap_vararg_num(pi);
if (va1 && jl_is_long(va1)) {
ssize_t nt = jl_unbox_long(va1);
if (nt == 0)
va1 = NULL;
else
pi = jl_bottom_type; // trigger errorf below
}
// This imposes an implicit constraint that va1==0,
// so we keep the Vararg if it has a TypeVar
if (va1 == NULL) {
p = NULL;
ntp -= 1;
assert(i == ntp);
break;
}
}
if (pi == jl_bottom_type)
jl_errorf("Tuple field type cannot be Union{}");
if (cacheable && !jl_is_concrete_type(pi))
cacheable = 0;
}
}
else {
size_t i;
Expand Down Expand Up @@ -1603,7 +1625,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
l = ntp - 1 + nt;
for (; i < l; i++)
jl_svecset(p, i, va0);
jl_value_t *ndt = (jl_value_t*)jl_apply_tuple_type(p);
jl_value_t *ndt = jl_apply_tuple_type(p);
JL_GC_POP();
return ndt;
}
Expand Down Expand Up @@ -1732,17 +1754,17 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
return (jl_value_t*)ndt;
}

static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params)
static jl_value_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params)
{
return (jl_datatype_t*)inst_datatype_inner(jl_anytuple_type, params, p, np, NULL, NULL);
return inst_datatype_inner(jl_anytuple_type, params, p, np, NULL, NULL);
}

JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type(jl_svec_t *params)
JL_DLLEXPORT jl_value_t *jl_apply_tuple_type(jl_svec_t *params)
{
return jl_apply_tuple_type_v_(jl_svec_data(params), jl_svec_len(params), params);
}

JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np)
JL_DLLEXPORT jl_value_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np)
{
return jl_apply_tuple_type_v_(p, np, NULL);
}
Expand Down Expand Up @@ -1828,7 +1850,7 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
ssize_t nt = jl_unbox_long(N);
if (nt < 0)
jl_errorf("size or dimension is negative: %zd", nt);
return (jl_value_t*)jl_tupletype_fill(nt, T);
return jl_tupletype_fill(nt, T);
}
}
jl_value_t **iparams;
Expand Down Expand Up @@ -2293,7 +2315,7 @@ void jl_init_types(void) JL_GC_DISABLED
jl_anytuple_type->layout = NULL;

jl_typeofbottom_type->super = jl_wrap_Type(jl_bottom_type);
jl_emptytuple_type = jl_apply_tuple_type(jl_emptysvec);
jl_emptytuple_type = (jl_datatype_t*)jl_apply_tuple_type(jl_emptysvec);
jl_emptytuple = jl_gc_permobj(0, jl_emptytuple_type);
jl_emptytuple_type->instance = jl_emptytuple;

Expand Down
5 changes: 2 additions & 3 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -1451,8 +1451,8 @@ JL_DLLEXPORT jl_value_t *jl_apply_type1(jl_value_t *tc, jl_value_t *p1);
JL_DLLEXPORT jl_value_t *jl_apply_type2(jl_value_t *tc, jl_value_t *p1, jl_value_t *p2);
JL_DLLEXPORT jl_datatype_t *jl_apply_modify_type(jl_value_t *dt);
JL_DLLEXPORT jl_datatype_t *jl_apply_cmpswap_type(jl_value_t *dt);
JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type(jl_svec_t *params);
JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np);
JL_DLLEXPORT jl_value_t *jl_apply_tuple_type(jl_svec_t *params);
JL_DLLEXPORT jl_value_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np);
JL_DLLEXPORT jl_datatype_t *jl_new_datatype(jl_sym_t *name,
jl_module_t *module,
jl_datatype_t *super,
Expand Down Expand Up @@ -1486,7 +1486,6 @@ JL_DLLEXPORT jl_svec_t *jl_alloc_svec(size_t n);
JL_DLLEXPORT jl_svec_t *jl_alloc_svec_uninit(size_t n);
JL_DLLEXPORT jl_svec_t *jl_svec_copy(jl_svec_t *a);
JL_DLLEXPORT jl_svec_t *jl_svec_fill(size_t n, jl_value_t *x);
JL_DLLEXPORT jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *v);
JL_DLLEXPORT jl_sym_t *jl_symbol(const char *str) JL_NOTSAFEPOINT;
JL_DLLEXPORT jl_sym_t *jl_symbol_lookup(const char *str) JL_NOTSAFEPOINT;
JL_DLLEXPORT jl_sym_t *jl_symbol_n(const char *str, size_t len) JL_NOTSAFEPOINT;
Expand Down
Loading

0 comments on commit 07ced48

Please sign in to comment.