Skip to content

Commit a218e82

Browse files
authored
handle Type{Union{}} like typeof(Union{}) more (#55508)
We could try to make them both pointers (by setting mayinlinealloc=false on Core.TypeofBottom), but let's try to make them both equivalent representations of the typeof Union{} as a singleton value. Fixes #55208
1 parent bec4702 commit a218e82

File tree

6 files changed

+35
-6
lines changed

6 files changed

+35
-6
lines changed

src/cgutils.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl
650650
{
651651
// this function converts a Julia Type into the equivalent LLVM type
652652
if (isboxed) *isboxed = false;
653-
if (jt == (jl_value_t*)jl_bottom_type)
653+
if (jt == (jl_value_t*)jl_bottom_type || jt == (jl_value_t*)jl_typeofbottom_type || jt == (jl_value_t*)jl_typeofbottom_type->super)
654654
return getVoidTy(ctxt);
655655
if (jl_is_concrete_immutable(jt)) {
656656
if (jl_datatype_nbits(jt) == 0)
@@ -760,7 +760,7 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt,
760760
// use this where C-compatible (unboxed) structs are desired
761761
// use julia_type_to_llvm directly when you want to preserve Julia's type semantics
762762
if (isboxed) *isboxed = false;
763-
if (jt == (jl_value_t*)jl_bottom_type)
763+
if (jt == (jl_value_t*)jl_bottom_type || jt == (jl_value_t*)jl_typeofbottom_type || jt == (jl_value_t*)jl_typeofbottom_type->super)
764764
return getVoidTy(ctxt);
765765
if (jl_is_primitivetype(jt))
766766
return bitstype_to_llvm(jt, ctxt, llvmcall);
@@ -948,6 +948,9 @@ static bool for_each_uniontype_small(
948948
allunbox &= for_each_uniontype_small(f, ((jl_uniontype_t*)ty)->b, counter);
949949
return allunbox;
950950
}
951+
else if (ty == (jl_value_t*)jl_typeofbottom_type->super) {
952+
f(++counter, jl_typeofbottom_type); // treat Tuple{union{}} as identical to typeof(Union{})
953+
}
951954
else if (jl_is_pointerfree(ty)) {
952955
f(++counter, (jl_datatype_t*)ty);
953956
return true;
@@ -1691,6 +1694,8 @@ static std::pair<Value*, bool> emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x,
16911694
if (intersected_type == (jl_value_t*)jl_bottom_type)
16921695
known_isa = false;
16931696
}
1697+
if (intersected_type == (jl_value_t*)jl_typeofbottom_type->super)
1698+
intersected_type = (jl_value_t*)jl_typeofbottom_type; // swap abstract Type{Union{}} for concrete typeof(Union{})
16941699
if (known_isa) {
16951700
if (!*known_isa && !msg.isTriviallyEmpty()) {
16961701
emit_type_error(ctx, x, literal_pointer_val(ctx, type), msg);

src/codegen.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,6 +2240,8 @@ static inline jl_cgval_t ghostValue(jl_codectx_t &ctx, jl_value_t *typ)
22402240
// replace T::Type{T} with T, by assuming that T must be a leaftype of some sort
22412241
jl_cgval_t constant(NULL, true, typ, NULL, best_tbaa(ctx.tbaa(), typ));
22422242
constant.constant = jl_tparam0(typ);
2243+
if (typ == (jl_value_t*)jl_typeofbottom_type->super)
2244+
constant.isghost = true;
22432245
return constant;
22442246
}
22452247
return jl_cgval_t(typ);
@@ -2252,7 +2254,7 @@ static inline jl_cgval_t ghostValue(jl_codectx_t &ctx, jl_datatype_t *typ)
22522254
static inline jl_cgval_t mark_julia_const(jl_codectx_t &ctx, jl_value_t *jv)
22532255
{
22542256
jl_value_t *typ;
2255-
if (jl_is_type(jv)) {
2257+
if (jl_is_type(jv) && jv != jl_bottom_type) {
22562258
typ = (jl_value_t*)jl_wrap_Type(jv); // TODO: gc-root this?
22572259
}
22582260
else {
@@ -3619,8 +3621,8 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva
36193621
if (arg1.constant && arg2.constant)
36203622
return ConstantInt::get(getInt1Ty(ctx.builder.getContext()), jl_egal(arg1.constant, arg2.constant));
36213623

3622-
jl_value_t *rt1 = arg1.typ;
3623-
jl_value_t *rt2 = arg2.typ;
3624+
jl_value_t *rt1 = (arg1.constant ? jl_typeof(arg1.constant) : arg1.typ);
3625+
jl_value_t *rt2 = (arg2.constant ? jl_typeof(arg2.constant) : arg2.typ);
36243626
if (jl_is_concrete_type(rt1) && jl_is_concrete_type(rt2) && !jl_is_kind(rt1) && !jl_is_kind(rt2) && rt1 != rt2) {
36253627
// disjoint concrete leaf types are never equal (quick test)
36263628
return ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 0);
@@ -9534,7 +9536,7 @@ static jl_llvm_functions_t
95349536
RTindex = UndefValue::get(getInt8Ty(ctx.builder.getContext()));
95359537
}
95369538
else if (jl_is_concrete_type(val.typ) || val.constant) {
9537-
size_t tindex = get_box_tindex((jl_datatype_t*)val.typ, phiType);
9539+
size_t tindex = get_box_tindex((jl_datatype_t*)(val.constant ? jl_typeof(val.constant) : val.typ), phiType);
95389540
if (tindex == 0) {
95399541
if (VN)
95409542
V = boxed(ctx, val);

src/datatype.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ int jl_struct_try_layout(jl_datatype_t *dt)
357357

358358
int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree)
359359
{
360+
if (jl_typeofbottom_type && ty == jl_typeofbottom_type->super)
361+
ty = jl_typeofbottom_type;
360362
if (ty->name->mayinlinealloc && jl_struct_try_layout(ty)) {
361363
if (ty->layout->npointers > 0) {
362364
if (pointerfree)
@@ -1656,6 +1658,8 @@ JL_DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type)
16561658
{
16571659
jl_task_t *ct = jl_current_task;
16581660
if (!jl_is_datatype(type) || !type->isconcretetype || type->layout == NULL || jl_is_layout_opaque(type->layout)) {
1661+
if (type == jl_typeofbottom_type->super)
1662+
return jl_bottom_type; // ::Type{Union{}} is an abstract type, but is also a singleton when used as a field type
16591663
jl_type_error("new", (jl_value_t*)jl_datatype_type, (jl_value_t*)type);
16601664
}
16611665
if (type->instance != NULL)

src/jltypes.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3024,6 +3024,7 @@ void jl_init_types(void) JL_GC_DISABLED
30243024
jl_anytuple_type->layout = NULL;
30253025

30263026
jl_typeofbottom_type->super = jl_wrap_Type(jl_bottom_type);
3027+
jl_typeofbottom_type->super->layout = jl_typeofbottom_type->layout; // the only abstract type with a layout
30273028
jl_emptytuple_type = (jl_datatype_t*)jl_apply_tuple_type(jl_emptysvec, 0);
30283029
jl_emptytuple = jl_gc_permobj(0, jl_emptytuple_type);
30293030
jl_emptytuple_type->instance = jl_emptytuple;

test/compiler/codegen.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,3 +969,18 @@ end
969969

970970
# Core.getptls() special handling
971971
@test !occursin("call ptr @jlplt", get_llvm(Core.getptls, Tuple{})) #It should lower to a direct load of the ptls and not a ccall
972+
973+
# issue 55208
974+
@noinline function f55208(x, i)
975+
z = (i == 0 ? x[1] : x[i])
976+
return z isa Core.TypeofBottom
977+
end
978+
@test f55208((Union{}, 5, 6, 7), 0)
979+
980+
@noinline function g55208(x, i)
981+
z = (i == 0 ? x[1] : x[i])
982+
typeof(z)
983+
end
984+
@test g55208((Union{}, true, true), 0) === typeof(Union{})
985+
986+
@test string((Core.Union{}, true, true, true)) == "(Union{}, true, true, true)"

test/core.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8265,3 +8265,5 @@ end
82658265
@test Tuple{Vararg{Int}} === Union{Tuple{Int}, Tuple{}, Tuple{Int, Int, Vararg{Int}}}
82668266
@test (Tuple{Vararg{T}} where T) === (Union{Tuple{T, T, Vararg{T}}, Tuple{}, Tuple{T}} where T)
82678267
@test_broken (Tuple{Vararg{T}} where T) === Union{Tuple{T, T, Vararg{T}} where T, Tuple{}, Tuple{T} where T}
8268+
8269+
@test sizeof(Pair{Union{typeof(Union{}),Nothing}, Union{Type{Union{}},Nothing}}(Union{}, Union{})) == 2

0 commit comments

Comments
 (0)