mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 22:58:46 +00:00
Begin work on producing a canonicalized type string for hashing types.
This commit is contained in:
+225
-4
@@ -1,5 +1,5 @@
|
|||||||
struct Scope;
|
|
||||||
struct Ast;
|
struct Ast;
|
||||||
|
struct Scope;
|
||||||
struct Entity;
|
struct Entity;
|
||||||
|
|
||||||
enum BasicKind {
|
enum BasicKind {
|
||||||
@@ -2119,6 +2119,23 @@ gb_internal bool is_type_sliceable(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal Entity *type_get_polymorphic_parent(Type *t, Type **params_) {
|
||||||
|
t = base_type(t);
|
||||||
|
Type *parent = nullptr;
|
||||||
|
if (t->kind == Type_Struct) {
|
||||||
|
parent = t->Struct.polymorphic_parent;
|
||||||
|
if (params_) *params_ = t->Struct.polymorphic_params;
|
||||||
|
} else if (t->kind == Type_Union) {
|
||||||
|
parent = t->Union.polymorphic_parent;
|
||||||
|
if (params_) *params_ = t->Union.polymorphic_params;
|
||||||
|
}
|
||||||
|
if (parent != nullptr) {
|
||||||
|
GB_ASSERT(parent->kind == Type_Named);
|
||||||
|
|
||||||
|
return parent->Named.type_name;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
gb_internal bool is_type_polymorphic_record(Type *t) {
|
gb_internal bool is_type_polymorphic_record(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
@@ -4580,7 +4597,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count));
|
str = gb_string_appendc(str, gb_bprintf("[%lld]", cast(long long)type->Array.count));
|
||||||
str = write_type_to_string(str, type->Array.elem);
|
str = write_type_to_string(str, type->Array.elem);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -4753,10 +4770,10 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProcCC_CDecl:
|
case ProcCC_CDecl:
|
||||||
str = gb_string_appendc(str, " \"cdecl\" ");
|
str = gb_string_appendc(str, " \"c\" ");
|
||||||
break;
|
break;
|
||||||
case ProcCC_StdCall:
|
case ProcCC_StdCall:
|
||||||
str = gb_string_appendc(str, " \"stdcall\" ");
|
str = gb_string_appendc(str, " \"std\" ");
|
||||||
break;
|
break;
|
||||||
case ProcCC_FastCall:
|
case ProcCC_FastCall:
|
||||||
str = gb_string_appendc(str, " \"fastcall\" ");
|
str = gb_string_appendc(str, " \"fastcall\" ");
|
||||||
@@ -4856,5 +4873,209 @@ gb_internal gbString type_to_string_shorthand(Type *type) {
|
|||||||
return type_to_string(type, true);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
return w;
|
||||||
|
case Type_Struct:
|
||||||
|
w = gb_string_appendc(w, "struct");
|
||||||
|
return 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->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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user