aboutsummaryrefslogtreecommitdiff
path: root/src/name_canonicalization.cpp
diff options
context:
space:
mode:
authorCourtney Strachan <courtney.strachan@gmail.com>2025-10-06 02:41:44 +0100
committerGitHub <noreply@github.com>2025-10-06 02:41:44 +0100
commit6de2d6e8ca687c989bbb7806e5cbe8d791e425bf (patch)
tree03a2e0a84c7c1530215f8e3f59a7f643b39b3677 /src/name_canonicalization.cpp
parentdbbe96ae5c343f0e803de6ee508207a62571534f (diff)
parent0f97382fa3e46da80705c00dfe02f3deb9562e4f (diff)
Merge branch 'odin-lang:master' into master
Diffstat (limited to 'src/name_canonicalization.cpp')
-rw-r--r--src/name_canonicalization.cpp112
1 files changed, 102 insertions, 10 deletions
diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp
index a80dc1996..8bacfabc6 100644
--- a/src/name_canonicalization.cpp
+++ b/src/name_canonicalization.cpp
@@ -1,3 +1,5 @@
+gb_internal bool is_in_doc_writer(void);
+
gb_internal GB_COMPARE_PROC(type_info_pair_cmp) {
TypeInfoPair *x = cast(TypeInfoPair *)a;
TypeInfoPair *y = cast(TypeInfoPair *)b;
@@ -55,10 +57,13 @@ gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) {
usize mask = s->capacity-1;
usize hash_index = cast(usize)hash & mask;
for (usize i = 0; i < s->capacity; i++) {
- Type *key = s->keys[hash_index].type;
- if (are_types_identical_unique_tuples(key, pair.type)) {
+ auto *e = &s->keys[hash_index];
+ u64 hash = e->hash;
+ Type *key = e->type;
+ if (hash == pair.hash &&
+ are_types_identical_unique_tuples(key, pair.type)) {
return hash_index;
- } else if (key == 0) {
+ } else if (key == nullptr) {
return -1;
}
hash_index = (hash_index+1)&mask;
@@ -162,6 +167,48 @@ gb_internal bool type_set_update(TypeSet *s, Type *ptr) { // returns true if it
return type_set_update(s, pair);
}
+gb_internal bool type_set_update_with_mutex(TypeSet *s, TypeInfoPair pair, RWSpinLock *m) { // returns true if it previously existsed
+ rwlock_acquire_upgrade(m);
+ if (type_set_exists(s, pair)) {
+ rwlock_release_upgrade(m);
+ return true;
+ }
+
+ rwlock_release_upgrade_and_acquire_write(m);
+ defer (rwlock_release_write(m));
+
+ if (s->keys == nullptr) {
+ type_set_init(s);
+ } else if (type_set__full(s)) {
+ type_set_grow(s);
+ }
+ GB_ASSERT(s->count < s->capacity);
+ GB_ASSERT(s->capacity >= 0);
+
+ usize mask = s->capacity-1;
+ usize hash = cast(usize)pair.hash;
+ usize hash_index = (cast(usize)hash) & mask;
+ GB_ASSERT(hash_index < s->capacity);
+ for (usize i = 0; i < s->capacity; i++) {
+ TypeInfoPair *key = &s->keys[hash_index];
+ GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type));
+ if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) {
+ *key = pair;
+ s->count++;
+ return false;
+ }
+ hash_index = (hash_index+1)&mask;
+ }
+
+ GB_PANIC("ptr set out of memory");
+ return false;
+}
+
+gb_internal bool type_set_update_with_mutex(TypeSet *s, Type *ptr, RWSpinLock *m) { // returns true if it previously existsed
+ TypeInfoPair pair = {ptr, type_hash_canonical_type(ptr)};
+ return type_set_update_with_mutex(s, pair, m);
+}
+
gb_internal Type *type_set_add(TypeSet *s, Type *ptr) {
type_set_update(s, ptr);
@@ -284,6 +331,23 @@ gb_internal void write_canonical_params(TypeWriter *w, Type *params) {
} else {
write_type_to_canonical_string(w, v->type);
}
+ if (is_in_doc_writer()) {
+ // NOTE(bill): This just exists to make sure the entities default values exist when
+ // writing to the odin doc format
+ Ast *expr = v->Variable.init_expr;
+ if (expr == nullptr) {
+ expr = v->Variable.param_value.original_ast_expr;
+ }
+ if (expr != nullptr) {
+ type_writer_appendc(w, "=");
+ gbString s = write_expr_to_string( // Minor leak
+ gb_string_make(temporary_allocator(), ""),
+ expr,
+ build_context.cmd_doc_flags & CmdDocFlag_Short
+ );
+ type_writer_append(w, s, gb_string_length(s));
+ }
+ }
break;
case Entity_TypeName:
type_writer_appendc(w, CANONICAL_PARAM_TYPEID);
@@ -309,12 +373,20 @@ gb_internal u64 type_hash_canonical_type(Type *type) {
if (type == nullptr) {
return 0;
}
+ u64 prev_hash = type->canonical_hash.load(std::memory_order_relaxed);
+ if (prev_hash != 0) {
+ return prev_hash;
+ }
+
u64 hash = fnv64a(nullptr, 0);
TypeWriter w = {};
type_writer_make_hasher(&w, &hash);
write_type_to_canonical_string(&w, type);
+ hash = hash ? hash : 1;
- return hash ? hash : 1;
+ type->canonical_hash.store(hash, std::memory_order_relaxed);
+
+ return hash;
}
gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) {
@@ -486,7 +558,13 @@ write_base_name:
Type *params = nullptr;
Entity *parent = type_get_polymorphic_parent(e->type, &params);
- if (parent && (parent->token.string == e->token.string)) {
+ if (parent && (e->token.string == parent->token.string)) {
+ // Check for `distinct` forms
+ type_writer_append(w, parent->token.string.text, parent->token.string.len);
+ write_canonical_params(w, params);
+ } else if (parent && string_starts_with(e->token.string, parent->token.string) &&
+ string_contains_char(e->token.string, '(')) {
+ // Check for named specialization forms
type_writer_append(w, parent->token.string.text, parent->token.string.len);
write_canonical_params(w, params);
} else {
@@ -520,7 +598,6 @@ write_base_name:
return;
}
-gb_internal bool is_in_doc_writer(void);
// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string
gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
@@ -631,6 +708,10 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
case Type_Union:
type_writer_appendc(w, "union");
+ if (is_in_doc_writer() && type->Union.polymorphic_params) {
+ write_canonical_params(w, type->Union.polymorphic_params);
+ }
+
switch (type->Union.kind) {
case UnionType_no_nil: type_writer_appendc(w, "#no_nil"); break;
case UnionType_shared_nil: type_writer_appendc(w, "#shared_nil"); break;
@@ -658,9 +739,13 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
}
type_writer_appendc(w, "struct");
+
+ if (is_in_doc_writer() && type->Struct.polymorphic_params) {
+ write_canonical_params(w, type->Struct.polymorphic_params);
+ }
+
if (type->Struct.is_packed) type_writer_appendc(w, "#packed");
if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union");
- if (type->Struct.is_no_copy) type_writer_appendc(w, "#no_copy");
if (type->Struct.custom_min_field_align != 0) type_writer_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align);
if (type->Struct.custom_max_field_align != 0) type_writer_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align);
if (type->Struct.custom_align != 0) type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align);
@@ -724,16 +809,23 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
if (is_in_doc_writer()) {
type_writer_appendc(w, "$");
type_writer_append(w, type->Generic.name.text, type->Generic.name.len);
- type_writer_append_fmt(w, "%lld", cast(long long)type->Generic.id);
+ type_writer_append_fmt(w, "-%lld", cast(long long)type->Generic.id);
+ if (type->Generic.specialized) {
+ type_writer_appendc(w, "/");
+ write_type_to_canonical_string(w, type->Generic.specialized);
+ }
+ } else if (type->Generic.specialized) {
+ // If we have a specialized type, use that instead of panicking
+ write_type_to_canonical_string(w, type->Generic.specialized);
} else {
- GB_PANIC("Type_Generic should never be hit");
+ // For unspecialized generics, use a generic placeholder string
+ type_writer_appendc(w, "rawptr");
}
return;
case Type_Named:
if (type->Named.type_name != nullptr) {
write_canonical_entity_name(w, type->Named.type_name);
- return;
} else {
type_writer_append(w, type->Named.name.text, type->Named.name.len);
}