diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 5a0b3766c..d8104b1ec 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -166,10 +166,11 @@ Type_Info_Map :: struct { map_info: ^Map_Info, } Type_Info_Bit_Set :: struct { - elem: ^Type_Info, - underlying: ^Type_Info, // Possibly nil - lower: i64, - upper: i64, + elem: ^Type_Info, + underlying: ^Type_Info, + explicit_underlying: bool, // false = bit_set[T], true = bit_set[T, U] + lower: i64, + upper: i64, } Type_Info_Simd_Vector :: struct { elem: ^Type_Info, @@ -676,6 +677,26 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { return base } +@(require_results) +type_info_underlying :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { + if info == nil { + return nil + } + + base := info + loop: for { + #partial switch i in base.variant { + case Type_Info_Named: base = i.base + case Type_Info_Enum: base = i.base + case Type_Info_Bit_Set: base = i.underlying + case Type_Info_Bit_Field: base = i.backing_type + case: + break loop + } + } + return base +} + // type_info_base_without_enum returns the core-type of a `^Type_Info` stripping the `distinct`ness from the first level AND/OR // returns the backing integer type of an enum or bit_set `^Type_Info`. // This is also aliased as `type_info_core` @@ -713,6 +734,11 @@ when !ODIN_NO_RTTI { // returns the backing integer type of an enum or bit_set `typeid`. // This is also aliased as `typeid_core` typeid_base_without_enum :: typeid_core + + typeid_underlying :: proc "contextless" (id: typeid) -> typeid { + ti := type_info_underlying(type_info_of(id)) + return ti.id + } } diff --git a/base/runtime/print.odin b/base/runtime/print.odin index 2cdde8152..6569ece6c 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -478,7 +478,7 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_string("..") print_i64(info.upper) } - if info.underlying != nil { + if info.explicit_underlying { print_string("; ") print_type(info.underlying) } @@ -893,7 +893,7 @@ write_write_type :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, t write_string(i, buf, "..") or_return write_i64 (i, buf, info.upper) or_return } - if info.underlying != nil { + if info.explicit_underlying { write_string (i, buf, "; ") or_return write_write_type(i, buf, info.underlying) or_return } diff --git a/core/odin/ast/walk.odin b/core/odin/ast/walk.odin index 24c90c13b..5b9340c62 100644 --- a/core/odin/ast/walk.odin +++ b/core/odin/ast/walk.odin @@ -405,9 +405,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk_expr_list(v, n.fields) case ^Bit_Set_Type: walk(v, n.elem) - if n.underlying != nil { - walk(v, n.underlying) - } + walk(v, n.underlying) case ^Map_Type: walk(v, n.key) walk(v, n.value) diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 385edb19b..53561281f 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -442,10 +442,7 @@ is_endian_platform :: proc(info: ^Type_Info) -> bool { case Type_Info_Integer: return v.endianness == .Platform case Type_Info_Bit_Set: - if v.underlying != nil { - return is_endian_platform(v.underlying) - } - return true + return is_endian_platform(v.underlying) case Type_Info_Pointer: return true } @@ -467,10 +464,7 @@ is_endian_little :: proc(info: ^Type_Info) -> bool { } return v.endianness == .Little case Type_Info_Bit_Set: - if v.underlying != nil { - return is_endian_platform(v.underlying) - } - return ODIN_ENDIAN == .Little + return is_endian_little(v.underlying) case Type_Info_Pointer: return ODIN_ENDIAN == .Little } @@ -492,10 +486,7 @@ is_endian_big :: proc(info: ^Type_Info) -> bool { } return v.endianness == .Big case Type_Info_Bit_Set: - if v.underlying != nil { - return is_endian_platform(v.underlying) - } - return ODIN_ENDIAN == .Big + return is_endian_big(v.underlying) case Type_Info_Pointer: return ODIN_ENDIAN == .Big } @@ -754,7 +745,7 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt io.write_string(w, "..=", &n) or_return io.write_i64(w, info.upper, 10, &n) or_return } - if info.underlying != nil { + if info.explicit_underlying { io.write_string(w, "; ", &n) or_return write_type(w, info.underlying, &n) or_return } diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 382304a4e..89c671f7d 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -923,15 +923,25 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ GB_ASSERT(is_type_typed(t->BitSet.elem)); - LLVMValueRef vals[4] = { - get_type_info_ptr(m, t->BitSet.elem), - LLVMConstNull(lb_type(m, t_type_info_ptr)), - lb_const_int(m, t_i64, t->BitSet.lower).value, - lb_const_int(m, t_i64, t->BitSet.upper).value, + LLVMValueRef vals[5] = { + get_type_info_ptr(m, t->BitSet.elem), // ^Type_Info + nullptr, // ^Type_Info + nullptr, // bool + lb_const_int(m, t_i64, t->BitSet.lower).value, // i64 + lb_const_int(m, t_i64, t->BitSet.upper).value, // i64 }; + Type *underlying = nullptr; + bool explicit_underlying = false; if (t->BitSet.underlying != nullptr) { + underlying = t->BitSet.underlying; + explicit_underlying = true; vals[1] = get_type_info_ptr(m, t->BitSet.underlying); + vals[2] = lb_const_bool(m, t_bool, true).value; + } else { + underlying = bit_set_to_int(t); } + vals[1] = get_type_info_ptr(m, underlying); + vals[2] = lb_const_bool(m, t_bool, explicit_underlying).value; variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); }