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

make Tuple{Union{}} unconstructable #49111

Merged
merged 1 commit into from
Apr 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -732,17 +732,21 @@ broadcastable(x) = collect(x)
broadcastable(::Union{AbstractDict, NamedTuple}) = throw(ArgumentError("broadcasting over dictionaries and `NamedTuple`s is reserved"))

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

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

# Inferred eltype of result of broadcast(f, args...)
combine_eltypes(f, args::Tuple) =
promote_typejoin_union(Base._return_type(f, eltypes(args)))
function combine_eltypes(f, args::Tuple)
argT = eltypes(args)
argT === Union{} && return Union{}
return promote_typejoin_union(Base._return_type(f, argT))
end

## Broadcasting core

Expand Down
25 changes: 19 additions & 6 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,8 @@ function abstract_call_method(interp::AbstractInterpreter,
add_remark!(interp, sv, "Refusing to infer into `depwarn`")
return MethodCallResult(Any, false, false, nothing, Effects())
end
sigtuple = unwrap_unionall(sig)
sigtuple isa DataType || return MethodCallResult(Any, false, false, nothing, Effects())

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

if topmost !== nothing
sigtuple = unwrap_unionall(sig)::DataType
msig = unwrap_unionall(method.sig)::DataType
spec_len = length(msig.parameters) + 1
ls = length(sigtuple.parameters)
Expand Down Expand Up @@ -1394,7 +1395,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 @@ -1403,6 +1408,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 @@ -2115,7 +2123,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 @@ -2152,8 +2160,13 @@ end
function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
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, frame_instance(sv), 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], frame_instance(sv), 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 @@ -2370,7 +2383,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
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))
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/inferenceresult.jl
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,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
2 changes: 1 addition & 1 deletion base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1170,7 +1170,7 @@ function handle_invoke_call!(todo::Vector{Pair{Int,Any}},
if isa(result, ConstPropResult)
mi = result.result.linfo
validate_sparams(mi.sparam_vals) || return nothing
if argtypes_to_type(argtypes) <: mi.def.sig
if Union{} !== argtypes_to_type(argtypes) <: mi.def.sig
item = resolve_todo(mi, result.result, argtypes, info, flag, state; invokesig)
handle_single_case!(todo, ir, idx, stmt, item, OptimizationParams(state.interp), true)
return nothing
Expand Down
10 changes: 10 additions & 0 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,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 @@ -1923,6 +1931,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
1 change: 1 addition & 0 deletions base/compiler/typeutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ function typesubtract(@nospecialize(a), @nospecialize(b), max_union_splitting::I
bp = b.parameters[i]
(isvarargtype(ap) || isvarargtype(bp)) && return a
ta[i] = typesubtract(ap, bp, min(2, max_union_splitting))
ta[i] === Union{} && return Union{}
return Tuple{ta...}
end
end
Expand Down
10 changes: 5 additions & 5 deletions base/iterators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ using .Base:
@inline, Pair, Pairs, AbstractDict, IndexLinear, IndexStyle, AbstractVector, Vector,
SizeUnknown, HasLength, HasShape, IsInfinite, EltypeUnknown, HasEltype, OneTo,
@propagate_inbounds, @isdefined, @boundscheck, @inbounds, Generator,
AbstractRange, AbstractUnitRange, UnitRange, LinearIndices,
AbstractRange, AbstractUnitRange, UnitRange, LinearIndices, TupleOrBottom,
(:), |, +, -, *, !==, !, ==, !=, <=, <, >, >=, missing,
any, _counttuple, eachindex, ntuple, zero, prod, reduce, in, firstindex, lastindex,
tail, fieldtypes, min, max, minimum, zero, oneunit, promote, promote_shape
Expand Down Expand Up @@ -209,7 +209,7 @@ size(e::Enumerate) = size(e.itr)
end
last(e::Enumerate) = (length(e.itr), e.itr[end])

eltype(::Type{Enumerate{I}}) where {I} = Tuple{Int, eltype(I)}
eltype(::Type{Enumerate{I}}) where {I} = TupleOrBottom(Int, eltype(I))

IteratorSize(::Type{Enumerate{I}}) where {I} = IteratorSize(I)
IteratorEltype(::Type{Enumerate{I}}) where {I} = IteratorEltype(I)
Expand Down Expand Up @@ -394,7 +394,7 @@ _promote_tuple_shape((m,)::Tuple{Integer}, (n,)::Tuple{Integer}) = (min(m, n),)
_promote_tuple_shape(a, b) = promote_shape(a, b)
_promote_tuple_shape(a, b...) = _promote_tuple_shape(a, _promote_tuple_shape(b...))
_promote_tuple_shape(a) = a
eltype(::Type{Zip{Is}}) where {Is<:Tuple} = Tuple{map(eltype, fieldtypes(Is))...}
eltype(::Type{Zip{Is}}) where {Is<:Tuple} = TupleOrBottom(map(eltype, fieldtypes(Is))...)
#eltype(::Type{Zip{Tuple{}}}) = Tuple{}
#eltype(::Type{Zip{Tuple{A}}}) where {A} = Tuple{eltype(A)}
#eltype(::Type{Zip{Tuple{A, B}}}) where {A, B} = Tuple{eltype(A), eltype(B)}
Expand Down Expand Up @@ -1072,8 +1072,7 @@ end

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

iterate(::ProductIterator{Tuple{}}) = (), true
iterate(::ProductIterator{Tuple{}}, state) = nothing
Expand Down Expand Up @@ -1442,6 +1441,7 @@ end
function _approx_iter_type(itrT::Type, vstate::Type)
vstate <: Union{Nothing, Tuple{Any, Any}} || return Any
vstate <: Union{} && return Union{}
itrT <: Union{} && return Union{}
nextvstate = Base._return_type(doiterate, Tuple{itrT, vstate})
return (nextvstate <: vstate ? vstate : Any)
end
Expand Down
12 changes: 11 additions & 1 deletion base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,11 @@ else
_return_type(@nospecialize(f), @nospecialize(t)) = Any
end

function TupleOrBottom(tt...)
any(p -> p === Union{}, tt) && return Union{}
return Tuple{tt...}
end

"""
promote_op(f, argtypes...)

Expand All @@ -483,7 +488,12 @@ Guess what an appropriate container eltype would be for storing results of
the container eltype on the type of the actual elements. Only in the absence of any
elements (for an empty result container), it may be unavoidable to call `promote_op`.
"""
promote_op(f, S::Type...) = _return_type(f, Tuple{S...})
function promote_op(f, S::Type...)
argT = TupleOrBottom(S...)
argT === Union{} && return Union{}
return _return_type(f, argT)
end


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

Expand Down
3 changes: 2 additions & 1 deletion base/slicearray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ unitaxis(::AbstractArray) = Base.OneTo(1)

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

Expand Down
2 changes: 1 addition & 1 deletion src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1320,7 +1320,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 @@ -5152,7 +5152,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 @@ -5475,7 +5475,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 @@ -5485,10 +5485,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 @@ -5501,7 +5501,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 @@ -6447,7 +6447,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 @@ -6897,9 +6897,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 @@ -1227,7 +1227,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 @@ -1350,7 +1350,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 @@ -2513,7 +2513,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 @@ -1416,7 +1416,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
Loading