diff --git a/core/_preload.odin b/core/_preload.odin index cec6a59b4..8807aa9da 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -211,7 +211,7 @@ __Map_Header :: struct { -type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { +type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { if info == nil do return nil; base := info; @@ -225,7 +225,7 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { } -type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info { +type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { if info == nil do return nil; base := info; @@ -239,27 +239,24 @@ type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info { return base; } - -typeid_from_type_info :: proc(ti: ^Type_Info) -> typeid { - id: uintptr = 0; - if ti != nil { - id = (uintptr(ti) - uintptr(&__type_table[0]))/size_of(Type_Info); - } +__typeid_of :: proc "contextless" (ti: ^Type_Info) -> typeid { + if ti == nil do return nil; + start := uintptr(&__type_table[0]); + end := uintptr(ti); + id := (end-start)/size_of(Type_Info); return transmute(typeid)id; } -type_info_from_typeid :: proc(t: typeid) -> ^Type_Info { - index := transmute(uintptr)t; - return &__type_table[index]; -} -typeid_base :: proc(id: typeid) -> typeid { - ti := type_info_from_typeid(id); + + +typeid_base :: proc "contextless" (id: typeid) -> typeid { + ti := type_info_of(id); ti = type_info_base(ti); - return typeid_from_type_info(ti); + return typeid_of(ti); } -typeid_base_without_enum :: proc(id: typeid) -> typeid { - ti := type_info_from_typeid(id); +typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid { + ti := type_info_of(id); ti = type_info_base_without_enum(ti); - return typeid_from_type_info(ti); + return typeid_of(ti); } @@ -668,7 +665,7 @@ __print_caller_location :: proc(fd: os.Handle, using loc: Source_Code_Location) os.write_byte(fd, ')'); } __print_typeid :: proc(fd: os.Handle, id: typeid) { - ti := type_info_from_typeid(id); + ti := type_info_of(id); __print_type(fd, ti); } __print_type :: proc(fd: os.Handle, ti: ^Type_Info) { @@ -681,7 +678,7 @@ __print_type :: proc(fd: os.Handle, ti: ^Type_Info) { case Type_Info_Named: os.write_string(fd, info.name); case Type_Info_Integer: - a := any{typeid = typeid_from_type_info(ti)}; + a := any{typeid = typeid_of(ti)}; switch _ in a { case int: os.write_string(fd, "int"); case uint: os.write_string(fd, "uint"); @@ -701,7 +698,7 @@ __print_type :: proc(fd: os.Handle, ti: ^Type_Info) { case Type_Info_String: os.write_string(fd, "string"); case Type_Info_Boolean: - a := any{typeid = typeid_from_type_info(ti)}; + a := any{typeid = typeid_of(ti)}; switch _ in a { case bool: os.write_string(fd, "bool"); case: diff --git a/core/fmt.odin b/core/fmt.odin index 0a2a30dbe..b29fa40a7 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -151,7 +151,7 @@ fprint_type :: proc(fd: os.Handle, info: ^Type_Info) { } write_typeid :: proc(buf: ^String_Buffer, id: typeid) { - write_type(buf, type_info_from_typeid(id)); + write_type(buf, type_info_of(id)); } write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) { @@ -164,7 +164,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) { case Type_Info_Named: write_string(buf, info.name); case Type_Info_Integer: - a := any{typeid = typeid_from_type_info(ti)}; + a := any{typeid = typeid_of(ti)}; switch _ in a { case int: write_string(buf, "int"); case uint: write_string(buf, "uint"); @@ -188,7 +188,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) { write_string(buf, "string"); } case Type_Info_Boolean: - a := any{typeid = typeid_from_type_info(ti)}; + a := any{typeid = typeid_of(ti)}; switch _ in a { case bool: write_string(buf, "bool"); case: @@ -629,7 +629,7 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) { enum_value_to_string :: proc(v: any) -> (string, bool) { v.typeid = typeid_base(v.typeid); - type_info := type_info_from_typeid(v.typeid); + type_info := type_info_of(v.typeid); switch e in type_info.variant { case: return "", false; @@ -653,7 +653,7 @@ enum_value_to_string :: proc(v: any) -> (string, bool) { return "", false; } - a := any{v.data, typeid_from_type_info(type_info_base(e.base))}; + a := any{v.data, typeid_of(type_info_base(e.base))}; switch v in a { case rune: return get_str(v, e); case i8: return get_str(v, e); @@ -696,14 +696,14 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { return; } - type_info := type_info_from_typeid(v.typeid); + type_info := type_info_of(v.typeid); switch e in type_info.variant { case: fmt_bad_verb(fi, verb); case Type_Info_Enum: switch verb { case: fmt_bad_verb(fi, verb); case 'd', 'f': - fmt_arg(fi, any{v.data, typeid_from_type_info(type_info_base(e.base))}, verb); + fmt_arg(fi, any{v.data, typeid_of(type_info_base(e.base))}, verb); case 's', 'v': str, ok := enum_value_to_string(v); if !ok do str = "!%(BAD ENUM VALUE)"; @@ -719,7 +719,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { return; } - type_info := type_info_from_typeid(v.typeid); + type_info := type_info_of(v.typeid); switch info in type_info.variant { case Type_Info_Named: switch b in info.base.variant { @@ -755,7 +755,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_string(fi.buf, "any{}"); } else { data := rawptr(uintptr(v.data) + b.offsets[i]); - id := typeid_from_type_info(t); + id := typeid_of(t); fmt_arg(fi, any{data, id}, 'v'); } @@ -766,7 +766,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_byte(fi.buf, '}'); case: - fmt_value(fi, any{v.data, typeid_from_type_info(info.base)}, verb); + fmt_value(fi, any{v.data, typeid_of(info.base)}, verb); } case Type_Info_Boolean: fmt_arg(fi, v, verb); @@ -790,7 +790,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if i > 0 do write_string(fi.buf, ", "); data := uintptr(v.data) + uintptr(i*info.elem_size); - fmt_arg(fi, any{rawptr(data), typeid_from_type_info(info.elem)}, verb); + fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb); } case Type_Info_Dynamic_Array: @@ -801,7 +801,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if i > 0 do write_string(fi.buf, ", "); data := uintptr(array.data) + uintptr(i*info.elem_size); - fmt_arg(fi, any{rawptr(data), typeid_from_type_info(info.elem)}, verb); + fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb); } case Type_Info_Slice: @@ -812,7 +812,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if i > 0 do write_string(fi.buf, ", "); data := uintptr(slice.data) + uintptr(i*info.elem_size); - fmt_arg(fi, any{rawptr(data), typeid_from_type_info(info.elem)}, verb); + fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb); } case Type_Info_Map: @@ -843,13 +843,13 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_string(fi.buf, header.key.str); } else { fi := Fmt_Info{buf = fi.buf}; - fmt_arg(&fi, any{rawptr(&header.key.hash), typeid_from_type_info(info.key)}, 'v'); + fmt_arg(&fi, any{rawptr(&header.key.hash), typeid_of(info.key)}, 'v'); } write_string(fi.buf, "="); value := data + entry_type.offsets[2]; - fmt_arg(fi, any{rawptr(value), typeid_from_type_info(info.value)}, 'v'); + fmt_arg(fi, any{rawptr(value), typeid_of(info.value)}, 'v'); } } @@ -884,7 +884,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_string(fi.buf, "any{}"); } else { data := uintptr(v.data) + info.offsets[i]; - id := typeid_from_type_info(t); + id := typeid_of(t); fmt_arg(fi, any{rawptr(data), id}, 'v'); } if hash do write_string(fi.buf, ",\n"); @@ -892,7 +892,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { case Type_Info_Union: tag_ptr := uintptr(v.data) + info.tag_offset; - tag_any := any{rawptr(tag_ptr), typeid_from_type_info(info.tag_type)}; + tag_any := any{rawptr(tag_ptr), typeid_of(info.tag_type)}; tag: i64 = -1; switch i in tag_any { @@ -910,7 +910,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if v.data == nil || tag == 0 { write_string(fi.buf, "nil"); } else { - id := typeid_from_type_info(info.variants[tag-1]); + id := typeid_of(info.variants[tag-1]); fmt_arg(fi, any{v.data, id}, verb); } @@ -958,7 +958,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { fi.arg = arg; if verb == 'T' { - ti := type_info_from_typeid(arg.typeid); + ti := type_info_of(arg.typeid); switch a in arg { case ^Type_Info: ti = a; } @@ -1015,7 +1015,7 @@ sbprint :: proc(buf: ^String_Buffer, args: ...any) -> string { fi.buf = buf; for arg, i in args { - is_string := arg != nil && types.is_string(type_info_from_typeid(arg.typeid)); + is_string := arg != nil && types.is_string(type_info_of(arg.typeid)); if i > 0 && !is_string && !prev_string { write_byte(buf, ' '); } diff --git a/core/mem.odin b/core/mem.odin index d9d9669cc..27acfd4a3 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -43,7 +43,7 @@ ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte { } any_to_bytes :: proc "contextless" (val: any) -> []byte { - ti := type_info_from_typeid(val.typeid); + ti := type_info_of(val.typeid); size := ti != nil ? ti.size : 0; return transmute([]byte)raw.Slice{val.data, size}; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index a2510f56b..e592597d2 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3421,6 +3421,13 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id add_type_info_type(c, t); + if (is_operand_value(o) && is_type_typeid(t)) { + // Okay + } else if (o.mode != Addressing_Type) { + error(ce->args[0], "Expected a type or typeid for 'type_info_of'"); + return false; + } + operand->mode = Addressing_Value; operand->type = t_type_info_ptr; @@ -3450,6 +3457,16 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id add_type_info_type(c, t); + t = base_type(t); + if (is_operand_value(o) && are_types_identical(t, t_type_info_ptr)) { + add_preload_dependency(c, "__typeid_of"); + } else if (o.mode != Addressing_Type) { + gbString ts = type_to_string(o.type); + error(ce->args[0], "Expected a type or type info for 'typeid_of', got %s", ts); + gb_string_free(ts); + return false; + } + operand->mode = Addressing_Value; operand->type = t_typeid; break; diff --git a/src/ir.cpp b/src/ir.cpp index 4750f7c8d..20f1cb947 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4209,13 +4209,30 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv } case BuiltinProc_type_info_of: { - Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); - return ir_type_info(proc, t); + AstNode *arg = ce->args[0]; + TypeAndValue tav = type_and_value_of_expr(proc->module->info, arg); + if (tav.mode == Addressing_Type) { + Type *t = default_type(type_of_expr(proc->module->info, arg)); + return ir_type_info(proc, t); + } + GB_ASSERT(is_type_typeid(tav.type)); + irValue *id = ir_emit_bitcast(proc, ir_build_expr(proc, arg), t_uintptr); + return ir_emit_array_ep(proc, ir_global_type_info_data, id); } case BuiltinProc_typeid_of: { - Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); - return ir_typeid(proc, t); + AstNode *arg = ce->args[0]; + TypeAndValue tav = type_and_value_of_expr(proc->module->info, arg); + if (tav.mode == Addressing_Type) { + Type *t = default_type(type_of_expr(proc->module->info, arg)); + return ir_typeid(proc, t); + } + Type *t = base_type(tav.type); + GB_ASSERT(are_types_identical(t, t_type_info_ptr)); + + auto args = array_make(proc->module->allocator, 1); + args[0] = ir_emit_conv(proc, ir_build_expr(proc, arg), t_type_info_ptr); + return ir_emit_global_call(proc, "__typeid_of", args); } case BuiltinProc_len: {