From 4eba3698aa1dde15abd22de1452229293282efee Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 09:47:49 +0000 Subject: Begin work on nested declarations --- src/types.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index c88878b9c..42530eccc 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4919,6 +4919,12 @@ gb_internal u64 type_hash_canonical_type(Type *type) { return hash; } +gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { + gbString w = gb_string_make(allocator, ""); + w = write_type_to_canonical_string(w, type); + return make_string(cast(u8 const *)w, gb_string_length(w)); +} + // NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { if (type == nullptr) { @@ -5101,6 +5107,15 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { case Type_Named: if (type->Named.type_name != nullptr) { Entity *e = type->Named.type_name; + + if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || + e->flags & EntityFlag_NotExported) { + if (e->scope->flags & ScopeFlag_Proc) { + GB_PANIC("NESTED IN PROC\n"); + } else if (e->scope->flags & ScopeFlag_File) { + GB_PANIC("PRIVATE TO FILE\n"); + } + } if (e->pkg != nullptr) { w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); w = gb_string_appendc(w, "."); -- cgit v1.2.3 From 99d91ccd31366e78c7ec0e94b5e3d473806721ed Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 11:32:49 +0000 Subject: Work on making name mangling deterministic --- src/check_decl.cpp | 6 + src/check_expr.cpp | 2 +- src/checker.cpp | 1 + src/checker.hpp | 2 + src/entity.cpp | 1 + src/gb/gb.h | 2 +- src/llvm_backend.hpp | 2 +- src/llvm_backend_general.cpp | 43 ++++- src/llvm_backend_stmt.cpp | 3 +- src/name_canonicalization.cpp | 419 ++++++++++++++++++++++++++++++++++++++++++ src/types.cpp | 269 --------------------------- 11 files changed, 475 insertions(+), 275 deletions(-) create mode 100644 src/name_canonicalization.cpp (limited to 'src/types.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 9084f15f0..d6f8e6fa7 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1784,6 +1784,10 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de ctx->curr_proc_sig = type; ctx->curr_proc_calling_convention = type->Proc.calling_convention; + if (decl->parent && decl->entity && decl->parent->entity) { + decl->entity->parent_proc_decl = decl->parent; + } + if (ctx->pkg->name != "runtime") { switch (type->Proc.calling_convention) { case ProcCC_None: @@ -1873,6 +1877,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de check_open_scope(ctx, body); { + ctx->scope->decl_info = decl; + for (auto const &entry : using_entities) { Entity *uvar = entry.uvar; Entity *prev = scope_insert(ctx->scope, uvar); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 550a7749c..f0021e67f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -345,7 +345,7 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice const &nodes, check_collect_entities(c, nodes); for (auto const &entry : s->elements) { - Entity *e = entry.value; + Entity *e = entry.value;\ switch (e->kind) { case Entity_Constant: case Entity_TypeName: diff --git a/src/checker.cpp b/src/checker.cpp index bfcabe4fa..c74a72a14 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3894,6 +3894,7 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) { #include "check_expr.cpp" #include "check_builtin.cpp" #include "check_type.cpp" +#include "name_canonicalization.cpp" #include "check_decl.cpp" #include "check_stmt.cpp" diff --git a/src/checker.hpp b/src/checker.hpp index 4634047c0..472ab8e50 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -276,6 +276,8 @@ struct Scope { StringMap elements; PtrSet imported; + DeclInfo *decl_info; + i32 flags; // ScopeFlag union { AstPackage *pkg; diff --git a/src/entity.cpp b/src/entity.cpp index d137a8674..b2148aa7b 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -257,6 +257,7 @@ struct Entity { bool has_instrumentation : 1; bool is_memcpy_like : 1; bool uses_branch_location : 1; + bool is_anonymous : 1; } Procedure; struct { Array entities; diff --git a/src/gb/gb.h b/src/gb/gb.h index 59611ceb6..98c362e93 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -5856,7 +5856,7 @@ gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) { gb_inline char *gb_bprintf_va(char const *fmt, va_list va) { - gb_local_persist char buffer[4096]; + gb_thread_local gb_local_persist char buffer[4096]; gb_snprintf_va(buffer, gb_size_of(buffer), fmt, va); return buffer; } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index a0775ac3b..dd6f1a083 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -399,7 +399,7 @@ struct lbProcedure { gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c); gb_internal String lb_mangle_name(Entity *e); -gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String name = {}); +gb_internal String lb_get_entity_name(lbModule *m, Entity *e); gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0); gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7425b9fd7..dc212e51d 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1444,6 +1444,7 @@ gb_internal void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { } gb_internal String lb_mangle_name(Entity *e) { +#if 1 String name = e->token.string; AstPackage *pkg = e->pkg; @@ -1483,9 +1484,18 @@ gb_internal String lb_mangle_name(Entity *e) { String mangled_name = make_string((u8 const *)new_name, new_name_len-1); return mangled_name; +#else + gbString w = gb_string_make(gb_heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + gb_printf_err(">> %s\n", w); + + String mangled_name = make_string(cast(u8 const *)w, gb_string_length(w)); + return mangled_name; +#endif } gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p, lbModule *module) { +#if 0 // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration // and as a result, the declaration does not have time to determine what it should be @@ -1516,6 +1526,7 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur } } + // NOTE(bill): Generate a new name // parent_proc.name-guid String ts_name = e->token.string; @@ -1528,6 +1539,12 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur String name = make_string(cast(u8 *)name_text, name_len-1); e->TypeName.ir_mangled_name = name; + + { + String s = type_to_canonical_string(temporary_allocator(), e->type); + gb_printf_err("1) %.*s\n", LIT(s)); + gb_printf_err("2) %.*s\n", LIT(name)); + } return name; } else { // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now @@ -1538,11 +1555,18 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur String name = make_string(cast(u8 *)name_text, name_len-1); e->TypeName.ir_mangled_name = name; + + { + String s = type_to_canonical_string(temporary_allocator(), e->type); + gb_printf_err("3) %.*s\n", LIT(s)); + gb_printf_err("4) %.*s\n", LIT(name)); + } return name; } +#endif } -gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_name) { +gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { GB_ASSERT(m != nullptr); if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) { return e->TypeName.ir_mangled_name; @@ -1553,6 +1577,13 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_nam return e->token.string; } +#if 1 + gbString w = gb_string_make(heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + defer (gb_string_free(w)); + + String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); +#else if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { return lb_set_nested_type_name_ir_mangled_name(e, nullptr, m); } @@ -1576,11 +1607,17 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_nam if (!no_name_mangle) { name = lb_mangle_name(e); + + gbString w = gb_string_make(gb_heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + if (w[0] == 0) { + gb_printf_err(">> %s %.*s\n", w, LIT(name)); + } } if (name.len == 0) { name = e->token.string; } - +#endif if (e->kind == Entity_TypeName) { e->TypeName.ir_mangled_name = name; } else if (e->kind == Entity_Procedure) { @@ -2869,6 +2906,8 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr pl->decl->code_gen_module = m; e->decl_info = pl->decl; pl->decl->entity = e; + e->parent_proc_decl = pl->decl->parent; + e->Procedure.is_anonymous = true; e->flags |= EntityFlag_ProcBodyChecked; lbProcedure *p = lb_create_procedure(m, e); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index b05df0b46..b83472075 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -32,7 +32,8 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) continue; } - lb_set_nested_type_name_ir_mangled_name(e, p, p->module); + String name = lb_get_entity_name(p->module, e); + gb_unused(name); } for_array(i, vd->names) { diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp new file mode 100644 index 000000000..fa09f27c0 --- /dev/null +++ b/src/name_canonicalization.cpp @@ -0,0 +1,419 @@ +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); +gb_internal gbString write_canonical_params(gbString w, Type *params) { + w = gb_string_appendc(w, "("); + if (params) { + GB_ASSERT(params->kind == Type_Tuple); + for_array(i, params->Tuple.variables) { + Entity *v = params->Tuple.variables[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + if (v->kind == Entity_Variable) { + if (v->flags&EntityFlag_CVarArg) { + w = gb_string_appendc(w, "#c_vararg"); + } + if (v->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(v->type); + w = gb_string_appendc(w, ".."); + GB_ASSERT(v->type->kind == Type_Slice); + w = write_type_to_canonical_string(w, slice->Slice.elem); + } else { + w = write_type_to_canonical_string(w, v->type); + } + } else if (v->kind == Entity_TypeName) { + w = gb_string_appendc(w, "$"); + w = write_type_to_canonical_string(w, v->type); + } else if (v->kind == Entity_Constant) { + w = gb_string_appendc(w, "$$"); + w = write_exact_value_to_string(w, v->Constant.value); + } else { + GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); + } + } + } + return gb_string_appendc(w, ")"); +} + +gb_internal u64 type_hash_canonical_type(Type *type) { + if (type == nullptr) { + return 0; + } + TEMPORARY_ALLOCATOR_GUARD(); + gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); + u64 hash = fnv64a(w, gb_string_length(w)); + return hash; +} + +gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { + gbString w = gb_string_make(allocator, ""); + w = write_type_to_canonical_string(w, type); + return make_string(cast(u8 const *)w, gb_string_length(w)); +} + +gb_internal void print_scope_flags(Scope *s) { + if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg "); + if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin "); + if (s->flags & ScopeFlag_Global) gb_printf_err("Global "); + if (s->flags & ScopeFlag_File) gb_printf_err("File "); + if (s->flags & ScopeFlag_Init) gb_printf_err("Init "); + if (s->flags & ScopeFlag_Proc) gb_printf_err("Proc "); + if (s->flags & ScopeFlag_Type) gb_printf_err("Type "); + if (s->flags & ScopeFlag_HasBeenImported) gb_printf_err("HasBeenImported "); + if (s->flags & ScopeFlag_ContextDefined) gb_printf_err("ContextDefined "); + gb_printf_err("\n"); +} + + + +gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool ignore_final_dot=false) { + GB_ASSERT(e != nullptr); + + // auto const &parent_entity = [](Scope *s) -> Entity* { + // while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { + // s = s->parent; + // } + // if (s->decl_info && s->decl_info->entity) { + // return s->decl_info->entity; + // } + // return nullptr; + // }; + + if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export || e->Procedure.is_foreign) { + // no prefix + return w; + } + if (e->parent_proc_decl) { + Entity *p = e->parent_proc_decl->entity; + w = write_canonical_parent_prefix(w, p); + w = gb_string_append_length(w, p->token.string.text, p->token.string.len); + if (is_type_polymorphic(p->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, p->type); + } + w = gb_string_appendc(w, "."); + + } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) { + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, "."); + } else { + String file_name = filename_without_directory(e->file->fullpath); + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + } + } else if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export || e->Procedure.is_foreign) { + // no prefix + return w; + } + GB_PANIC("TODO(bill): handle entity kind: %d", e->kind); + } + + if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { + w = gb_string_appendc(w, gb_bprintf("$anon%d", e->token.pos.offset)); + } else { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + } + + if (is_type_polymorphic(e->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, e->type); + } + if (!ignore_final_dot) { + w = gb_string_appendc(w, "."); + } + + return w; +} + +gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { + GB_ASSERT(e != nullptr); + + if (e->token.string == "_") { + GB_PANIC("_ string"); + } + if (e->token.string.len == 0) { + GB_PANIC("empty string"); + } + + if (e->kind == Entity_Variable) { + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + if (e->Variable.link_name.len > 0) { + w = gb_string_append_length(w, e->Variable.link_name.text, e->Variable.link_name.len); + return w; + } else if (is_foreign || is_export) { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + return w; + } + } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { + w = gb_string_append_length(w, e->Procedure.link_name.text, e->Procedure.link_name.len); + return w; + } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + return w; + } + + if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || + e->flags & EntityFlag_NotExported) { + + Scope *s = e->scope; + while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { + s = s->parent; + } + + if (s->decl_info != nullptr && s->decl_info->entity) { + w = write_canonical_parent_prefix(w, s->decl_info->entity); + goto write_base_name; + } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) { + String file_name = filename_without_directory(s->file->fullpath); + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + goto write_base_name; + } + gb_printf_err("%s HERE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); + print_scope_flags(s); + GB_PANIC("weird entity"); + } + if (e->pkg != nullptr) { + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + w = gb_string_appendc(w, "."); + } + +write_base_name: + + switch (e->kind) { + case Entity_TypeName: + { + Type *params = nullptr; + Entity *parent = type_get_polymorphic_parent(e->type, ¶ms); + if (parent) { + w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); + w = write_canonical_params(w, params); + } else { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + } + } + // Handle parapoly stuff here? + return w; + + case Entity_Procedure: + case Entity_Variable: + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + if (is_type_polymorphic(e->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, e->type); + } + return w; + + default: + GB_PANIC("TODO(bill): entity kind %d", e->kind); + break; + } + return w; +} + +// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { + if (type == nullptr) { + return gb_string_appendc(w, "<>"); // none/void type + } + + type = default_type(type); + GB_ASSERT(!is_type_untyped(type)); + + switch (type->kind) { + case Type_Basic: + return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); + case Type_Pointer: + w = gb_string_append_rune(w, '^'); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_MultiPointer: + w = gb_string_appendc(w, "[^]"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_SoaPointer: + w = gb_string_appendc(w, "#soa^"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_EnumeratedArray: + if (type->EnumeratedArray.is_sparse) { + w = gb_string_appendc(w, "#sparse"); + } + w = gb_string_append_rune(w, '['); + w = write_type_to_canonical_string(w, type->EnumeratedArray.index); + w = gb_string_append_rune(w, ']'); + return write_type_to_canonical_string(w, type->EnumeratedArray.elem); + case Type_Array: + w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_Slice: + w = gb_string_appendc(w, "[]"); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_DynamicArray: + w = gb_string_appendc(w, "[dynamic]"); + return write_type_to_canonical_string(w, type->DynamicArray.elem); + case Type_SimdVector: + w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); + return write_type_to_canonical_string(w, type->SimdVector.elem); + case Type_Matrix: + if (type->Matrix.is_row_major) { + w = gb_string_appendc(w, "#row_major "); + } + w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); + return write_type_to_canonical_string(w, type->Matrix.elem); + case Type_Map: + w = gb_string_appendc(w, "map["); + w = write_type_to_canonical_string(w, type->Map.key); + w = gb_string_appendc(w, "]"); + return write_type_to_canonical_string(w, type->Map.value); + + case Type_Enum: + w = gb_string_appendc(w, "enum"); + if (type->Enum.base_type != nullptr) { + w = gb_string_append_rune(w, ' '); + w = write_type_to_canonical_string(w, type->Enum.base_type); + w = gb_string_append_rune(w, ' '); + } + w = gb_string_append_rune(w, '{'); + for_array(i, type->Enum.fields) { + Entity *f = type->Enum.fields[i]; + GB_ASSERT(f->kind == Entity_Constant); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, "="); + w = write_exact_value_to_string(w, f->Constant.value); + } + return gb_string_append_rune(w, '}'); + case Type_BitSet: + w = gb_string_appendc(w, "bit_set["); + if (type->BitSet.elem == nullptr) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else if (is_type_enum(type->BitSet.elem)) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else { + w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); + w = gb_string_append_fmt(w, "..="); + w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); + } + if (type->BitSet.underlying != nullptr) { + w = gb_string_appendc(w, ";"); + w = write_type_to_canonical_string(w, type->BitSet.underlying); + } + return gb_string_appendc(w, "]"); + + case Type_Union: + w = gb_string_appendc(w, "union"); + + switch (type->Union.kind) { + case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; + case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; + } + if (type->Union.custom_align != 0) { + w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); + } + w = gb_string_appendc(w, "{"); + for_array(i, type->Union.variants) { + Type *t = type->Union.variants[i]; + if (i > 0) w = gb_string_appendc(w, ", "); + w = write_type_to_canonical_string(w, t); + } + return gb_string_appendc(w, "}"); + case Type_Struct: + if (type->Struct.soa_kind != StructSoa_None) { + switch (type->Struct.soa_kind) { + case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; + case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; + case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; + default: GB_PANIC("Unknown StructSoaKind"); break; + } + return write_type_to_canonical_string(w, type->Struct.soa_elem); + } + + w = gb_string_appendc(w, "struct"); + if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); + if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); + if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); + if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); + if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); + if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); + w = gb_string_appendc(w, "{"); + for_array(i, type->Struct.fields) { + Entity *f = type->Struct.fields[i]; + GB_ASSERT(f->kind == Entity_Variable); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length (w, f->token.string.text, f->token.string.len); + w = gb_string_appendc (w, ":"); + w = write_type_to_canonical_string(w, f->type); + String tag = type->Struct.tags[i]; + if (tag.len != 0) { + String s = quote_to_ascii(heap_allocator(), tag); + w = gb_string_append_length(w, s.text, s.len); + gb_free(heap_allocator(), s.text); + } + } + return gb_string_appendc(w, "}"); + + case Type_BitField: + w = gb_string_appendc(w, "bit_field"); + w = write_type_to_canonical_string(w, type->BitField.backing_type); + w = gb_string_appendc(w, " {"); + for (isize i = 0; i < type->BitField.fields.count; i++) { + Entity *f = type->BitField.fields[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, ":"); + w = write_type_to_canonical_string(w, f->type); + w = gb_string_appendc(w, "|"); + w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); + } + return gb_string_appendc(w, " }"); + + case Type_Proc: + w = gb_string_appendc(w, "proc"); + if (default_calling_convention() != type->Proc.calling_convention) { + w = gb_string_appendc(w, "\""); + w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); + w = gb_string_appendc(w, "\""); + } + + w = write_canonical_params(w, type->Proc.params); + if (type->Proc.result_count > 0) { + w = gb_string_appendc(w, "->"); + w = write_canonical_params(w, type->Proc.results); + } + return w; + + case Type_Generic: + GB_PANIC("Type_Generic should never be hit"); + return w; + + case Type_Named: + if (type->Named.type_name != nullptr) { + return write_canonical_entity_name(w, type->Named.type_name); + } else { + w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); + } + // Handle parapoly stuff here? + return w; + + default: + GB_PANIC("unknown type kind %d", type->kind); + break; + } + + return w; +} \ No newline at end of file diff --git a/src/types.cpp b/src/types.cpp index 42530eccc..d6dea56ad 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4872,272 +4872,3 @@ gb_internal gbString type_to_string(Type *type, bool shorthand) { gb_internal gbString type_to_string_shorthand(Type *type) { return type_to_string(type, true); } - -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); -gb_internal gbString write_canonical_params(gbString w, Type *params) { - w = gb_string_appendc(w, "("); - if (params) { - GB_ASSERT(params->kind == Type_Tuple); - for_array(i, params->Tuple.variables) { - Entity *v = params->Tuple.variables[i]; - if (i > 0) { - w = gb_string_appendc(w, ","); - } - if (v->kind == Entity_Variable) { - if (v->flags&EntityFlag_CVarArg) { - w = gb_string_appendc(w, "#c_vararg"); - } - if (v->flags&EntityFlag_Ellipsis) { - Type *slice = base_type(v->type); - w = gb_string_appendc(w, ".."); - GB_ASSERT(v->type->kind == Type_Slice); - w = write_type_to_canonical_string(w, slice->Slice.elem); - } else { - w = write_type_to_canonical_string(w, v->type); - } - } else if (v->kind == Entity_TypeName) { - w = gb_string_appendc(w, "$"); - w = write_type_to_canonical_string(w, v->type); - } else if (v->kind == Entity_Constant) { - w = gb_string_appendc(w, "$$"); - w = write_exact_value_to_string(w, v->Constant.value); - } else { - GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); - } - } - } - return gb_string_appendc(w, ")"); -} - -gb_internal u64 type_hash_canonical_type(Type *type) { - if (type == nullptr) { - return 0; - } - TEMPORARY_ALLOCATOR_GUARD(); - gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); - u64 hash = fnv64a(w, gb_string_length(w)); - return hash; -} - -gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { - gbString w = gb_string_make(allocator, ""); - w = write_type_to_canonical_string(w, type); - return make_string(cast(u8 const *)w, gb_string_length(w)); -} - -// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { - if (type == nullptr) { - return gb_string_appendc(w, "<>"); // none/void type - } - - type = default_type(type); - GB_ASSERT(!is_type_untyped(type)); - - switch (type->kind) { - case Type_Basic: - return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); - case Type_Pointer: - w = gb_string_append_rune(w, '^'); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_MultiPointer: - w = gb_string_appendc(w, "[^]"); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_SoaPointer: - w = gb_string_appendc(w, "#soa^"); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_EnumeratedArray: - if (type->EnumeratedArray.is_sparse) { - w = gb_string_appendc(w, "#sparse"); - } - w = gb_string_append_rune(w, '['); - w = write_type_to_canonical_string(w, type->EnumeratedArray.index); - w = gb_string_append_rune(w, ']'); - return write_type_to_canonical_string(w, type->EnumeratedArray.elem); - case Type_Array: - w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); - return write_type_to_canonical_string(w, type->Array.elem); - case Type_Slice: - w = gb_string_appendc(w, "[]"); - return write_type_to_canonical_string(w, type->Array.elem); - case Type_DynamicArray: - w = gb_string_appendc(w, "[dynamic]"); - return write_type_to_canonical_string(w, type->DynamicArray.elem); - case Type_SimdVector: - w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); - return write_type_to_canonical_string(w, type->SimdVector.elem); - case Type_Matrix: - if (type->Matrix.is_row_major) { - w = gb_string_appendc(w, "#row_major "); - } - w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); - return write_type_to_canonical_string(w, type->Matrix.elem); - case Type_Map: - w = gb_string_appendc(w, "map["); - w = write_type_to_canonical_string(w, type->Map.key); - w = gb_string_appendc(w, "]"); - return write_type_to_canonical_string(w, type->Map.value); - - case Type_Enum: - w = gb_string_appendc(w, "enum"); - if (type->Enum.base_type != nullptr) { - w = gb_string_append_rune(w, ' '); - w = write_type_to_canonical_string(w, type->Enum.base_type); - w = gb_string_append_rune(w, ' '); - } - w = gb_string_append_rune(w, '{'); - for_array(i, type->Enum.fields) { - Entity *f = type->Enum.fields[i]; - GB_ASSERT(f->kind == Entity_Constant); - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, "="); - w = write_exact_value_to_string(w, f->Constant.value); - } - return gb_string_append_rune(w, '}'); - case Type_BitSet: - w = gb_string_appendc(w, "bit_set["); - if (type->BitSet.elem == nullptr) { - w = write_type_to_canonical_string(w, type->BitSet.elem); - } else if (is_type_enum(type->BitSet.elem)) { - w = write_type_to_canonical_string(w, type->BitSet.elem); - } else { - w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); - w = gb_string_append_fmt(w, "..="); - w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); - } - if (type->BitSet.underlying != nullptr) { - w = gb_string_appendc(w, ";"); - w = write_type_to_canonical_string(w, type->BitSet.underlying); - } - return gb_string_appendc(w, "]"); - - case Type_Union: - w = gb_string_appendc(w, "union"); - - switch (type->Union.kind) { - case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; - case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; - } - if (type->Union.custom_align != 0) { - w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); - } - w = gb_string_appendc(w, "{"); - for_array(i, type->Union.variants) { - Type *t = type->Union.variants[i]; - if (i > 0) w = gb_string_appendc(w, ", "); - w = write_type_to_canonical_string(w, t); - } - return gb_string_appendc(w, "}"); - case Type_Struct: - if (type->Struct.soa_kind != StructSoa_None) { - switch (type->Struct.soa_kind) { - case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; - case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; - case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; - default: GB_PANIC("Unknown StructSoaKind"); break; - } - return write_type_to_canonical_string(w, type->Struct.soa_elem); - } - - w = gb_string_appendc(w, "struct"); - if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); - if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); - if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); - if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); - if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); - if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); - w = gb_string_appendc(w, "{"); - for_array(i, type->Struct.fields) { - Entity *f = type->Struct.fields[i]; - GB_ASSERT(f->kind == Entity_Variable); - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length (w, f->token.string.text, f->token.string.len); - w = gb_string_appendc (w, ":"); - w = write_type_to_canonical_string(w, f->type); - String tag = type->Struct.tags[i]; - if (tag.len != 0) { - String s = quote_to_ascii(heap_allocator(), tag); - w = gb_string_append_length(w, s.text, s.len); - gb_free(heap_allocator(), s.text); - } - } - return gb_string_appendc(w, "}"); - - case Type_BitField: - w = gb_string_appendc(w, "bit_field"); - w = write_type_to_canonical_string(w, type->BitField.backing_type); - w = gb_string_appendc(w, " {"); - for (isize i = 0; i < type->BitField.fields.count; i++) { - Entity *f = type->BitField.fields[i]; - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, ":"); - w = write_type_to_canonical_string(w, f->type); - w = gb_string_appendc(w, "|"); - w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); - } - return gb_string_appendc(w, " }"); - - case Type_Proc: - w = gb_string_appendc(w, "proc"); - if (default_calling_convention() != type->Proc.calling_convention) { - w = gb_string_appendc(w, "\""); - w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); - w = gb_string_appendc(w, "\""); - } - - w = write_canonical_params(w, type->Proc.params); - if (type->Proc.result_count > 0) { - w = gb_string_appendc(w, "->"); - w = write_canonical_params(w, type->Proc.results); - } - return w; - - case Type_Generic: - GB_PANIC("Type_Generic should never be hit"); - return w; - - case Type_Named: - if (type->Named.type_name != nullptr) { - Entity *e = type->Named.type_name; - - if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || - e->flags & EntityFlag_NotExported) { - if (e->scope->flags & ScopeFlag_Proc) { - GB_PANIC("NESTED IN PROC\n"); - } else if (e->scope->flags & ScopeFlag_File) { - GB_PANIC("PRIVATE TO FILE\n"); - } - } - if (e->pkg != nullptr) { - w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); - w = gb_string_appendc(w, "."); - } - Type *params = nullptr; - Entity *parent = type_get_polymorphic_parent(type, ¶ms); - if (parent) { - w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); - w = write_canonical_params(w, params); - } else { - w = gb_string_append_length(w, e->token.string.text, e->token.string.len); - } - } else { - w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); - } - // Handle parapoly stuff here? - return w; - - default: - GB_PANIC("unknown type kind %d", type->kind); - break; - } - - return w; -} \ No newline at end of file -- cgit v1.2.3 From 9b26bb2e6a1e32e17102550b481c6909549b87e5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 13:10:38 +0000 Subject: Begin work on hash types --- src/checker.cpp | 44 +++++++++++++++++++++++++++++++++++++++++-- src/checker.hpp | 7 ++++++- src/llvm_backend.cpp | 7 ++++--- src/llvm_backend_general.cpp | 2 -- src/llvm_backend_type.cpp | 6 +++--- src/name_canonicalization.cpp | 25 +++++++++++++++++++----- src/ptr_set.cpp | 10 +++++----- src/types.cpp | 36 +++++++++++++++++++++++++++++++++-- 8 files changed, 114 insertions(+), 23 deletions(-) (limited to 'src/types.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index c74a72a14..054d6aeb0 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3,7 +3,10 @@ #include "entity.cpp" #include "types.cpp" -String get_final_microarchitecture(); + +gb_internal u64 type_hash_canonical_type(Type *type); + +gb_internal String get_final_microarchitecture(); gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression); gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr); @@ -2037,7 +2040,8 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { // Unique entry // NOTE(bill): map entries grow linearly and in order ti_index = c->info->type_info_types.count; - array_add(&c->info->type_info_types, t); + Type_Info_Type tt = {t, type_hash_canonical_type(t)}; + array_add(&c->info->type_info_types, tt); } map_set(&c->checker->info.type_info_map, t, ti_index); @@ -6725,6 +6729,42 @@ gb_internal void check_parsed_files(Checker *c) { add_type_and_value(&c->builtin_ctx, u.expr, u.info->mode, u.info->type, u.info->value); } + TIME_SECTION("check for type hash collisions"); + { + PtrSet found = {}; + ptr_set_init(&found, c->info.type_info_types.count); + defer (ptr_set_destroy(&found)); + for (auto const &tt : c->info.type_info_types) { + if (ptr_set_update(&found, cast(uintptr)tt.hash)) { + Type *other_type = nullptr; + for (auto const &other : c->info.type_info_types) { + if (&tt == &other) { + continue; + } + if (cast(uintptr)other.hash == cast(uintptr)tt.hash && + !are_types_identical(tt.type, other.type)) { + other_type = other.type; + break; + } + } + if (other_type != nullptr) { + String ts = type_to_canonical_string(temporary_allocator(), tt.type); + String os = type_to_canonical_string(temporary_allocator(), other_type); + if (ts != os) { + compiler_error("%s found type hash collision with %s (hash = %llu)\n" + "%s vs %s\n", + type_to_string(tt.type), type_to_string(other_type), cast(unsigned long long)tt.hash, + temp_canonical_string(tt.type), + temp_canonical_string(other_type) + ); + } + } + } + } + } + + + TIME_SECTION("sort init and fini procedures"); check_sort_init_and_fini_procedures(c); diff --git a/src/checker.hpp b/src/checker.hpp index 472ab8e50..c9a0c3302 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -409,6 +409,11 @@ struct Defineable { String pos_str; }; +struct Type_Info_Type { + Type *type; + u64 hash; // see: type_hash_canonical_type +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -453,7 +458,7 @@ struct CheckerInfo { PtrMap gen_types; BlockingMutex type_info_mutex; // NOT recursive - Array type_info_types; + Array type_info_types; PtrMap type_info_map; BlockingMutex foreign_mutex; // NOT recursive diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 0896ea8c7..8cb480dd4 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -24,7 +24,7 @@ #include "llvm_backend_stmt.cpp" #include "llvm_backend_proc.cpp" -String get_default_microarchitecture() { +gb_internal String get_default_microarchitecture() { String default_march = str_lit("generic"); if (build_context.metrics.arch == TargetArch_amd64) { // NOTE(bill): x86-64-v2 is more than enough for everyone @@ -47,7 +47,7 @@ String get_default_microarchitecture() { return default_march; } -String get_final_microarchitecture() { +gb_internal String get_final_microarchitecture() { BuildContext *bc = &build_context; String microarch = bc->microarch; @@ -3182,7 +3182,8 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { isize count = 0; isize offsets_extra = 0; - for (Type *t : m->info->type_info_types) { + for (auto const &tt : m->info->type_info_types) { + Type *t = tt.type; isize index = lb_type_info_index(m->info, t, false); if (index < 0) { continue; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7fdfa0bb2..b9ae3d254 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1460,8 +1460,6 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { w = write_canonical_entity_name(w, e); defer (gb_string_free(w)); - gb_printf_err("%s\n", w); - String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); if (e->kind == Entity_TypeName) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 6c12b37be..6f9f94fbd 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -12,7 +12,7 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_ gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count); for (auto const &entry : *set) { isize type_info_index = entry.key; - gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index])); + gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type)); } GB_PANIC("NOT FOUND"); } @@ -280,7 +280,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ LLVMTypeRef *modified_types = lb_setup_modified_types_for_type_info(m, global_type_info_data_entity_count); defer (gb_free(heap_allocator(), modified_types)); for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; + Type *t = info->type_info_types[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } @@ -343,7 +343,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ }; for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; + Type *t = info->type_info_types[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 3910c573d..8edb5e968 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -7,7 +7,7 @@ * builtin names - just their normal name e.g. `i32` or `string` * nested - pkg.parent1.parent2.name * file private - pkg.[file_name].name - * Example: `foo.[bar.odin].Type` + * Example: `pkg.[file.odin].Type` * polymorphic procedure/type - pkg.foo::TYPE * naming convention for parameters * type @@ -15,7 +15,7 @@ * $$constant_parameter * Example: `foo.to_thing::proc(u64)->([]u8)` * nested decl in polymorphic procedure - pkg.foo::TYPE.name - * anonymous procedures - pkg.foo.$anon123 + * anonymous procedures - pkg.foo.$anon[file.odin:123] * 123 is the file offset in bytes @@ -38,7 +38,12 @@ #define CANONICAL_NONE_TYPE "<>" + gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); +gb_internal u64 type_hash_canonical_type(Type *type); +gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type); +gb_internal gbString temp_canonical_string(Type *type); + gb_internal gbString write_canonical_params(gbString w, Type *params) { w = gb_string_appendc(w, "("); if (params) { @@ -81,7 +86,7 @@ gb_internal u64 type_hash_canonical_type(Type *type) { TEMPORARY_ALLOCATOR_GUARD(); gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); u64 hash = fnv64a(w, gb_string_length(w)); - return hash; + return hash ? hash : 1; } gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { @@ -90,6 +95,11 @@ gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { return make_string(cast(u8 const *)w, gb_string_length(w)); } +gb_internal gbString temp_canonical_string(Type *type) { + gbString w = gb_string_make(temporary_allocator(), ""); + return write_type_to_canonical_string(w, type); +} + gb_internal void print_scope_flags(Scope *s) { if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg "); if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin "); @@ -156,7 +166,8 @@ gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool i } if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { - w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "%d", e->token.pos.offset)); + String file_name = filename_without_directory(e->file->fullpath); + w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset)); } else { w = gb_string_append_length(w, e->token.string.text, e->token.string.len); } @@ -449,8 +460,12 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { } return w; + case Type_Tuple: + w = gb_string_appendc(w, "params"); + w = write_canonical_params(w, type); + return w; default: - GB_PANIC("unknown type kind %d", type->kind); + GB_PANIC("unknown type kind %d %.*s", type->kind, LIT(type_strings[type->kind])); break; } diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index ff4befc37..5097e2bb6 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -42,7 +42,7 @@ gb_internal void ptr_set_destroy(PtrSet *s) { template gb_internal isize ptr_set__find(PtrSet *s, T ptr) { - GB_ASSERT(ptr != nullptr); + GB_ASSERT(ptr != 0); if (s->count != 0) { #if 0 for (usize i = 0; i < s->capacity; i++) { @@ -58,7 +58,7 @@ gb_internal isize ptr_set__find(PtrSet *s, T ptr) { T key = s->keys[hash_index]; if (key == ptr) { return hash_index; - } else if (key == nullptr) { + } else if (key == 0) { return -1; } hash_index = (hash_index+1)&mask; @@ -122,7 +122,7 @@ gb_internal bool ptr_set_update(PtrSet *s, T ptr) { // returns true if it pre for (usize i = 0; i < s->capacity; i++) { T *key = &s->keys[hash_index]; GB_ASSERT(*key != ptr); - if (*key == (T)PtrSet::TOMBSTONE || *key == nullptr) { + if (*key == (T)PtrSet::TOMBSTONE || *key == 0) { *key = ptr; s->count++; return false; @@ -169,7 +169,7 @@ struct PtrSetIterator { return *this; } T key = set->keys[index]; - if (key != nullptr && key != (T)PtrSet::TOMBSTONE) { + if (key != 0 && key != (T)PtrSet::TOMBSTONE) { return *this; } } @@ -191,7 +191,7 @@ gb_internal PtrSetIterator begin(PtrSet &set) noexcept { usize index = 0; while (index < set.capacity) { T key = set.keys[index]; - if (key != nullptr && key != (T)PtrSet::TOMBSTONE) { + if (key != 0 && key != (T)PtrSet::TOMBSTONE) { break; } index++; diff --git a/src/types.cpp b/src/types.cpp index d6dea56ad..15e1bcf45 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2774,7 +2774,37 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Enum: - return x == y; // NOTE(bill): All enums are unique + if (x == y) { + return true; + } + if (x->Enum.fields.count != y->Enum.fields.count) { + return false; + } + if (!are_types_identical(x->Enum.base_type, y->Enum.base_type)) { + return false; + } + if (x->Enum.min_value_index != y->Enum.min_value_index) { + return false; + } + if (x->Enum.max_value_index != y->Enum.max_value_index) { + return false; + } + + for (isize i = 0; i < x->Enum.fields.count; i++) { + Entity *a = x->Enum.fields[i]; + Entity *b = y->Enum.fields[i]; + if (a->token.string != b->token.string) { + return false; + } + GB_ASSERT(a->kind == b->kind); + GB_ASSERT(a->kind == Entity_Constant); + bool same = compare_exact_values(Token_CmpEq, a->Constant.value, b->Constant.value); + if (!same) { + return false; + } + } + + return true; case Type_Union: if (x->Union.variants.count == y->Union.variants.count && @@ -2832,7 +2862,9 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple return false; } } - return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params); + // TODO(bill): Which is the correct logic here? + // return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params); + return true; } break; -- cgit v1.2.3