diff --git a/core/_preload.odin b/core/_preload.odin index 5829abe4a..a1d729649 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -49,6 +49,7 @@ Type_Info_Complex :: struct {}; Type_Info_String :: struct {is_cstring: bool}; Type_Info_Boolean :: struct {}; Type_Info_Any :: struct {}; +Type_Info_Type_Id :: struct {}; Type_Info_Pointer :: struct { elem: ^Type_Info // nil -> rawptr }; @@ -114,6 +115,7 @@ Type_Info :: struct { Type_Info_String, Type_Info_Boolean, Type_Info_Any, + Type_Info_Type_Id, Type_Info_Pointer, Type_Info_Procedure, Type_Info_Array, @@ -237,6 +239,11 @@ type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info { return base; } +type_info_from_typeid :: proc(t: typeid) -> ^Type_Info { + index := transmute(uintptr)t; + return &__type_table[index]; +} + @(default_calling_convention = "c") diff --git a/core/fmt.odin b/core/fmt.odin index 50c083e9b..211ec69a2 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -150,6 +150,10 @@ fprint_type :: proc(fd: os.Handle, info: ^Type_Info) { os.write(fd, buf[..]); } +write_typeid :: proc(buf: ^String_Buffer, id: typeid) { + write_type(buf, type_info_from_typeid(id)); +} + write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) { if ti == nil { write_string(buf, "nil"); @@ -194,6 +198,9 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) { case Type_Info_Any: write_string(buf, "any"); + case Type_Info_Type_Id: + write_string(buf, "typeid"); + case Type_Info_Pointer: if info.elem == nil { write_string(buf, "rawptr"); @@ -914,6 +921,10 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_string(fi.buf, " @ "); fmt_pointer(fi, ptr, 'p'); } + + case Type_Info_Type_Id: + id := (^typeid)(v.data)^; + write_typeid(fi.buf, id); } } @@ -983,7 +994,9 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { case string: fmt_string(fi, a, verb); case cstring: fmt_cstring(fi, a, verb); - case: fmt_value(fi, arg, verb); + case typeid: write_typeid(fi.buf, a); + + case: fmt_value(fi, arg, verb); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c4a1e7a43..66c26dda4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2873,6 +2873,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_align_of: case BuiltinProc_offset_of: case BuiltinProc_type_info_of: + case BuiltinProc_typeid_of: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; default: @@ -3426,6 +3427,34 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id break; } + case BuiltinProc_typeid_of: { + // proc typeid_of(Type) -> ^Type_Info + if (c->context.scope->is_global) { + compiler_error("'typeid_of' Cannot be declared within a #shared_global_scope due to how the internals of the compiler works"); + } + + // NOTE(bill): The type information may not be setup yet + init_preload(c); + AstNode *expr = ce->args[0]; + Operand o = {}; + check_expr_or_type(c, &o, expr); + if (o.mode == Addressing_Invalid) { + return false; + } + Type *t = o.type; + if (t == nullptr || t == t_invalid || is_type_polymorphic(operand->type)) { + error(ce->args[0], "Invalid argument for 'typeid_of'"); + return false; + } + t = default_type(t); + + add_type_info_type(c, t); + + operand->mode = Addressing_Value; + operand->type = t_typeid; + break; + } + case BuiltinProc_swizzle: { // proc swizzle(v: [N]T, ...int) -> [M]T Type *type = base_type(operand->type); diff --git a/src/checker.cpp b/src/checker.cpp index 6d035760c..b0aa30e04 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1023,6 +1023,8 @@ void add_type_info_type(Checker *c, Type *t) { add_type_info_type(c, t_type_info_ptr); add_type_info_type(c, t_rawptr); break; + case Basic_typeid: + break; case Basic_complex64: add_type_info_type(c, t_type_info_float); @@ -1564,6 +1566,7 @@ void init_preload(Checker *c) { t_type_info_string = find_core_type(c, str_lit("Type_Info_String")); t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean")); t_type_info_any = find_core_type(c, str_lit("Type_Info_Any")); + t_type_info_typeid = find_core_type(c, str_lit("Type_Info_Type_Id")); t_type_info_pointer = find_core_type(c, str_lit("Type_Info_Pointer")); t_type_info_procedure = find_core_type(c, str_lit("Type_Info_Procedure")); t_type_info_array = find_core_type(c, str_lit("Type_Info_Array")); @@ -1584,6 +1587,7 @@ void init_preload(Checker *c) { t_type_info_string_ptr = alloc_type_pointer(t_type_info_string); t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean); t_type_info_any_ptr = alloc_type_pointer(t_type_info_any); + t_type_info_typeid_ptr = alloc_type_pointer(t_type_info_typeid); t_type_info_pointer_ptr = alloc_type_pointer(t_type_info_pointer); t_type_info_procedure_ptr = alloc_type_pointer(t_type_info_procedure); t_type_info_array_ptr = alloc_type_pointer(t_type_info_array); diff --git a/src/checker.hpp b/src/checker.hpp index b2ea3a921..6b931fa62 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -86,6 +86,7 @@ enum BuiltinProcId { BuiltinProc_offset_of, BuiltinProc_type_of, BuiltinProc_type_info_of, + BuiltinProc_typeid_of, BuiltinProc_swizzle, @@ -128,6 +129,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("offset_of"), 2, false, Expr_Expr}, {STR_LIT("type_of"), 1, false, Expr_Expr}, {STR_LIT("type_info_of"), 1, false, Expr_Expr}, + {STR_LIT("typeid_of"), 1, false, Expr_Expr}, {STR_LIT("swizzle"), 1, true, Expr_Expr}, diff --git a/src/ir.cpp b/src/ir.cpp index f4f795e6d..c5061b38e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4203,6 +4203,13 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv return ir_type_info(proc, t); } + case BuiltinProc_typeid_of: { + Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); + i32 entry_index = cast(i32)ir_type_info_index(proc->module->info, t); + GB_ASSERT(entry_index >= 0); + return ir_value_constant(proc->module->allocator, t_typeid, exact_value_i64(entry_index)); + } + case BuiltinProc_len: { irValue *v = ir_build_expr(proc, ce->args[0]); Type *t = base_type(ir_type(v)); @@ -7951,6 +7958,10 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info case Basic_any: tag = ir_emit_conv(proc, variant_ptr, t_type_info_any_ptr); break; + + case Basic_typeid: + tag = ir_emit_conv(proc, variant_ptr, t_type_info_typeid_ptr); + break; } break; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e24859413..435924f06 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -342,6 +342,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { case Basic_string: ir_write_str_lit(f, "%..string"); return; case Basic_cstring: ir_write_str_lit(f, "i8*"); return; + case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return; } break; @@ -1750,6 +1751,12 @@ void print_llvm_ir(irGen *ir) { ir_print_type(f, m, t_type_info_ptr); ir_write_str_lit(f, "} ; Basic_any\n"); + ir_print_encoded_local(f, str_lit("..typeid")); + ir_write_str_lit(f, " = type "); + ir_print_type(f, m, t_uintptr); + ir_write_str_lit(f, "; Basic_typeid\n"); + + ir_write_str_lit(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n"); ir_write_byte(f, '\n'); diff --git a/src/types.cpp b/src/types.cpp index 33ba05a2a..b5ed0a885 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -38,6 +38,8 @@ enum BasicKind { Basic_cstring, // ^u8 Basic_any, // rawptr + ^Type_Info + Basic_typeid, + Basic_UntypedBool, Basic_UntypedInteger, Basic_UntypedFloat, @@ -283,6 +285,8 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_cstring, BasicFlag_String, -1, STR_LIT("cstring")}}, {Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}}, + {Type_Basic, {Basic_typeid, 0, -1, STR_LIT("typeid")}}, + {Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, 0, STR_LIT("untyped bool")}}, {Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}}, {Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}}, @@ -329,6 +333,8 @@ gb_global Type *t_string = &basic_types[Basic_string]; gb_global Type *t_cstring = &basic_types[Basic_cstring]; gb_global Type *t_any = &basic_types[Basic_any]; +gb_global Type *t_typeid = &basic_types[Basic_typeid]; + gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool]; gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger]; gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat]; @@ -360,6 +366,7 @@ gb_global Type *t_type_info_rune = nullptr; gb_global Type *t_type_info_float = nullptr; gb_global Type *t_type_info_complex = nullptr; gb_global Type *t_type_info_any = nullptr; +gb_global Type *t_type_info_typeid = nullptr; gb_global Type *t_type_info_string = nullptr; gb_global Type *t_type_info_boolean = nullptr; gb_global Type *t_type_info_pointer = nullptr; @@ -381,6 +388,7 @@ gb_global Type *t_type_info_float_ptr = nullptr; gb_global Type *t_type_info_complex_ptr = nullptr; gb_global Type *t_type_info_quaternion_ptr = nullptr; gb_global Type *t_type_info_any_ptr = nullptr; +gb_global Type *t_type_info_typeid_ptr = nullptr; gb_global Type *t_type_info_string_ptr = nullptr; gb_global Type *t_type_info_boolean_ptr = nullptr; gb_global Type *t_type_info_pointer_ptr = nullptr; @@ -1128,6 +1136,8 @@ bool is_type_comparable(Type *t) { return true; case Basic_cstring: return false; + case Basic_typeid: + return true; } return true; case Type_Pointer: @@ -1334,7 +1344,7 @@ Type *default_type(Type *type) { return type; } - +/* // NOTE(bill): Valid Compile time execution #run type bool is_type_cte_safe(Type *type) { type = default_type(base_type(type)); @@ -1392,7 +1402,7 @@ bool is_type_cte_safe(Type *type) { return false; } - + */ i64 union_variant_index(Type *u, Type *v) { u = base_type(u); GB_ASSERT(u->kind == Type_Union); @@ -1884,6 +1894,7 @@ i64 type_align_of_internal(Type *t, TypePath *path) { case Basic_string: return build_context.word_size; case Basic_cstring: return build_context.word_size; case Basic_any: return build_context.word_size; + case Basic_typeid: return build_context.word_size; case Basic_int: case Basic_uint: case Basic_uintptr: case Basic_rawptr: return build_context.word_size; @@ -2085,6 +2096,7 @@ i64 type_size_of_internal(Type *t, TypePath *path) { case Basic_string: return 2*build_context.word_size; case Basic_cstring: return build_context.word_size; case Basic_any: return 2*build_context.word_size; + case Basic_typeid: return build_context.word_size; case Basic_int: case Basic_uint: case Basic_uintptr: case Basic_rawptr: return build_context.word_size;