浏览代码

Simplify type info table construction

gingerBill 6 月之前
父节点
当前提交
4a29d9bb84
共有 5 个文件被更改,包括 146 次插入85 次删除
  1. 101 61
      src/checker.cpp
  2. 10 7
      src/checker.hpp
  3. 3 1
      src/llvm_backend.cpp
  4. 13 12
      src/llvm_backend_type.cpp
  5. 19 4
      src/name_canonicalization.cpp

+ 101 - 61
src/checker.cpp

@@ -828,9 +828,15 @@ gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) {
 	rw_mutex_unlock(&d->deps_mutex);
 	rw_mutex_unlock(&d->deps_mutex);
 }
 }
 gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) {
 gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) {
-	if (d == nullptr) {
+	if (d == nullptr || type == nullptr) {
 		return;
 		return;
 	}
 	}
+	if (type->kind == Type_Named) {
+		Entity *e = type->Named.type_name;
+		if (e->TypeName.is_type_alias) {
+			type = type->Named.base;
+		}
+	}
 	rw_mutex_lock(&d->type_info_deps_mutex);
 	rw_mutex_lock(&d->type_info_deps_mutex);
 	ptr_set_add(&d->type_info_deps, type);
 	ptr_set_add(&d->type_info_deps, type);
 	rw_mutex_unlock(&d->type_info_deps_mutex);
 	rw_mutex_unlock(&d->type_info_deps_mutex);
@@ -1361,9 +1367,12 @@ gb_internal void init_checker_info(CheckerInfo *i) {
 	string_map_init(&i->foreigns);
 	string_map_init(&i->foreigns);
 	// map_init(&i->gen_procs);
 	// map_init(&i->gen_procs);
 	map_init(&i->gen_types);
 	map_init(&i->gen_types);
+
 	array_init(&i->type_info_types, a);
 	array_init(&i->type_info_types, a);
-	map_init(&i->type_info_map);
-	type_set_init(&i->type_info_set);
+	type_set_init(&i->min_dep_type_info_set);
+	map_init(&i->minimum_dependency_type_info_index_map);
+
+	// map_init(&i->type_info_map);
 	string_map_init(&i->files);
 	string_map_init(&i->files);
 	string_map_init(&i->packages);
 	string_map_init(&i->packages);
 	array_init(&i->variable_init_order, a);
 	array_init(&i->variable_init_order, a);
@@ -1396,9 +1405,11 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
 	string_map_destroy(&i->foreigns);
 	string_map_destroy(&i->foreigns);
 	// map_destroy(&i->gen_procs);
 	// map_destroy(&i->gen_procs);
 	map_destroy(&i->gen_types);
 	map_destroy(&i->gen_types);
+
 	array_free(&i->type_info_types);
 	array_free(&i->type_info_types);
-	map_destroy(&i->type_info_map);
-	type_set_destroy(&i->type_info_set);
+	type_set_destroy(&i->min_dep_type_info_set);
+	map_destroy(&i->minimum_dependency_type_info_index_map);
+
 	string_map_destroy(&i->files);
 	string_map_destroy(&i->files);
 	string_map_destroy(&i->packages);
 	string_map_destroy(&i->packages);
 	array_free(&i->variable_init_order);
 	array_free(&i->variable_init_order);
@@ -1632,41 +1643,36 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) {
 	}
 	}
 }
 }
 
 
-
-gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
-	type = default_type(type);
-	if (type == t_llvm_bool) {
-		type = t_bool;
-	}
-
-	mutex_lock(&info->type_info_mutex);
+gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool error_on_failure) {
+	mutex_lock(&info->minimum_dependency_type_info_mutex);
 
 
 	isize entry_index = -1;
 	isize entry_index = -1;
-	isize *found_entry_index = map_get(&info->type_info_map, type);
+	uintptr hash = cast(uintptr)pair.hash;
+	isize *found_entry_index = map_get(&info->minimum_dependency_type_info_index_map, hash);
 	if (found_entry_index) {
 	if (found_entry_index) {
 		entry_index = *found_entry_index;
 		entry_index = *found_entry_index;
 	}
 	}
-	if (entry_index < 0) {
-		// NOTE(bill): Do manual linear search
-		for (auto const &e : info->type_info_map) {
-			if (are_types_identical_unique_tuples(e.key, type)) {
-				entry_index = e.value;
-				// NOTE(bill): Add it to the search map
-				map_set(&info->type_info_map, type, entry_index);
-				break;
-			}
-		}
-	}
-
-	mutex_unlock(&info->type_info_mutex);
+	mutex_unlock(&info->minimum_dependency_type_info_mutex);
 
 
 	if (error_on_failure && entry_index < 0) {
 	if (error_on_failure && entry_index < 0) {
-		compiler_error("Type_Info for '%s' could not be found", type_to_string(type));
+		compiler_error("Type_Info for '%s' could not be found", type_to_string(pair.type));
 	}
 	}
 	return entry_index;
 	return entry_index;
 }
 }
 
 
 
 
+gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
+	type = default_type(type);
+	if (type == t_llvm_bool) {
+		type = t_bool;
+	}
+
+	u64 hash = type_hash_canonical_type(type);
+	return type_info_index(info, {type, hash}, error_on_failure);
+}
+
+
+
 gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) {
 gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) {
 	if (expr == nullptr) {
 	if (expr == nullptr) {
 		return;
 		return;
@@ -2018,8 +2024,12 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
 	}
 	}
 
 
 	add_type_info_dependency(c->info, c->decl, t);
 	add_type_info_dependency(c->info, c->decl, t);
-
+#if 0
 	MUTEX_GUARD_BLOCK(&c->info->type_info_mutex) {
 	MUTEX_GUARD_BLOCK(&c->info->type_info_mutex) {
+		if (type_set_update(&c->info->type_info_set, t)) {
+			// return;
+		}
+
 		auto found = map_get(&c->info->type_info_map, t);
 		auto found = map_get(&c->info->type_info_map, t);
 		if (found != nullptr) {
 		if (found != nullptr) {
 			// Types have already been added
 			// Types have already been added
@@ -2238,6 +2248,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
 		GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
 		GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
 		break;
 		break;
 	}
 	}
+#endif
 }
 }
 
 
 
 
@@ -2295,11 +2306,10 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
 		return;
 		return;
 	}
 	}
 
 
-	if (type_set_update(&c->info.type_info_set, t)) {
-		// return;
+	if (type_set_update(&c->info.min_dep_type_info_set, t)) {
+		return;
 	}
 	}
 
 
-
 	// Add nested types
 	// Add nested types
 	if (t->kind == Type_Named) {
 	if (t->kind == Type_Named) {
 		// NOTE(bill): Just in case
 		// NOTE(bill): Just in case
@@ -2697,7 +2707,6 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
 	isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor
 	isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor
 
 
 	ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap);
 	ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap);
-	map_init(&c->info.minimum_dependency_type_info_set);
 
 
 #define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do {                                              \
 #define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do {                                              \
 	if (condition) {                                                                             \
 	if (condition) {                                                                             \
@@ -6720,39 +6729,70 @@ 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);
 		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");
+	TIME_SECTION("initilize type info array");
 	{
 	{
-		PtrSet<uintptr> 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)
-						);
+		for (auto const &tt : c->info.min_dep_type_info_set) {
+			array_add(&c->info.type_info_types, tt);
+		}
+		array_sort(c->info.type_info_types, type_info_pair_cmp);
+
+		map_reserve(&c->info.minimum_dependency_type_info_index_map, c->info.type_info_types.count);
+
+		for_array(i, c->info.type_info_types) {
+			auto const &tt = c->info.type_info_types[i];
+			bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, cast(uintptr)tt.hash, i);
+			if (exists) {
+				for (auto const &entry : c->info.minimum_dependency_type_info_index_map) {
+					if (entry.key == cast(uintptr)tt.hash) {
+						auto const &other = c->info.type_info_types[entry.value];
+						if (!are_types_identical_unique_tuples(tt.type, other.type)) {
+							gbString t = temp_canonical_string(tt.type);
+							gbString o = temp_canonical_string(other.type);
+							GB_PANIC("%s (%s) %llu vs %s (%s) %llu",
+							         type_to_string(tt.type, false),    t, cast(unsigned long long)tt.hash,
+							         type_to_string(other.type, false), o, cast(unsigned long long)other.hash);
+						}
 					}
 					}
 				}
 				}
 			}
 			}
 		}
 		}
-	}
+
+		GB_ASSERT(c->info.minimum_dependency_type_info_index_map.count <= c->info.type_info_types.count);
+	}
+
+	// TIME_SECTION("check for type hash collisions");
+	// {
+	// 	PtrSet<uintptr> 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)
+	// 					);
+	// 				}
+	// 			}
+	// 		}
+	// 	}
+	// }
 
 
 
 
 
 

+ 10 - 7
src/checker.hpp

@@ -222,7 +222,7 @@ struct DeclInfo {
 	PtrSet<Entity *> deps;
 	PtrSet<Entity *> deps;
 
 
 	RwMutex     type_info_deps_mutex;
 	RwMutex     type_info_deps_mutex;
-	PtrSet<Type *>    type_info_deps;
+	PtrSet<Type *>    type_info_deps; // TODO(bill): Use TypeSet
 
 
 	BlockingMutex type_and_value_mutex;
 	BlockingMutex type_and_value_mutex;
 
 
@@ -444,8 +444,10 @@ struct CheckerInfo {
 	Scope *               init_scope;
 	Scope *               init_scope;
 	Entity *              entry_point;
 	Entity *              entry_point;
 	PtrSet<Entity *>      minimum_dependency_set;
 	PtrSet<Entity *>      minimum_dependency_set;
-	PtrMap</*type info index*/isize, /*min dep index*/isize>  minimum_dependency_type_info_set;
-
+	BlockingMutex minimum_dependency_type_info_mutex;
+	PtrMap</*type info hash*/uintptr, /*min dep index*/isize> minimum_dependency_type_info_index_map;
+	TypeSet min_dep_type_info_set;
+	Array<TypeInfoPair> type_info_types; // sorted after filled
 
 
 
 
 	Array<Entity *> testing_procedures;
 	Array<Entity *> testing_procedures;
@@ -473,10 +475,10 @@ struct CheckerInfo {
 	BlockingMutex                  gen_types_mutex;
 	BlockingMutex                  gen_types_mutex;
 	PtrMap<Type *, GenTypesData *> gen_types;
 	PtrMap<Type *, GenTypesData *> gen_types;
 
 
-	BlockingMutex type_info_mutex; // NOT recursive
-	Array<TypeInfoPair> type_info_types;
-	PtrMap<Type *, isize> type_info_map;
-	TypeSet type_info_set;
+	// BlockingMutex type_info_mutex; // NOT recursive
+	// Array<TypeInfoPair> type_info_types;
+	// PtrMap<Type *, isize> type_info_map;
+	// TypeSet type_info_set;
 
 
 	BlockingMutex foreign_mutex; // NOT recursive
 	BlockingMutex foreign_mutex; // NOT recursive
 	StringMap<Entity *> foreigns;
 	StringMap<Entity *> foreigns;
@@ -595,6 +597,7 @@ gb_internal DeclInfo *   decl_info_of_entity    (Entity * e);
 gb_internal AstFile *    ast_file_of_filename   (CheckerInfo *i, String   filename);
 gb_internal AstFile *    ast_file_of_filename   (CheckerInfo *i, String   filename);
 // IMPORTANT: Only to use once checking is done
 // IMPORTANT: Only to use once checking is done
 gb_internal isize        type_info_index        (CheckerInfo *i, Type *type, bool error_on_failure);
 gb_internal isize        type_info_index        (CheckerInfo *i, Type *type, bool error_on_failure);
+gb_internal isize        type_info_index        (CheckerInfo *info, TypeInfoPair pair, bool error_on_failure);
 
 
 // Will return nullptr if not found
 // Will return nullptr if not found
 gb_internal Entity *entity_of_node(Ast *expr);
 gb_internal Entity *entity_of_node(Ast *expr);

+ 3 - 1
src/llvm_backend.cpp

@@ -3154,7 +3154,9 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
 		lbModule *m = default_module;
 		lbModule *m = default_module;
 
 
 		{ // Add type info data
 		{ // Add type info data
-			isize max_type_info_count = info->minimum_dependency_type_info_set.count+1;
+			GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count);
+
+			isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1;
 			Type *t = alloc_type_array(t_type_info_ptr, max_type_info_count);
 			Type *t = alloc_type_array(t_type_info_ptr, max_type_info_count);
 
 
 			// IMPORTANT NOTE(bill): As LLVM does not have a union type, an array of unions cannot be initialized
 			// IMPORTANT NOTE(bill): As LLVM does not have a union type, an array of unions cannot be initialized

+ 13 - 12
src/llvm_backend_type.cpp

@@ -1,16 +1,12 @@
-gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
-	auto *set = &info->minimum_dependency_type_info_set;
-	isize index = type_info_index(info, type, err_on_not_found);
+
+gb_internal isize lb_type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err_on_not_found=true) {
+	isize index = type_info_index(info, pair, err_on_not_found);
 	if (index >= 0) {
 	if (index >= 0) {
-		auto *found = map_get(set, index+1);
-		if (found) {
-			GB_ASSERT(*found >= 0);
-			return *found + 1;
-		}
+		return index+1;
 	}
 	}
 	if (err_on_not_found) {
 	if (err_on_not_found) {
-		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) {
+		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(pair.type), index, info->minimum_dependency_type_info_index_map.count);
+		for (auto const &entry : info->minimum_dependency_type_info_index_map) {
 			isize type_info_index = entry.key;
 			isize type_info_index = entry.key;
 			gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type));
 			gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type));
 		}
 		}
@@ -19,6 +15,10 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_
 	return -1;
 	return -1;
 }
 }
 
 
+gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
+	return lb_type_info_index(info, {type, type_hash_canonical_type(type)}, err_on_not_found);
+}
+
 gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) {
 gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) {
 	GB_ASSERT(!build_context.no_rtti);
 	GB_ASSERT(!build_context.no_rtti);
 
 
@@ -280,12 +280,13 @@ 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);
 	LLVMTypeRef *modified_types = lb_setup_modified_types_for_type_info(m, global_type_info_data_entity_count);
 	defer (gb_free(heap_allocator(), modified_types));
 	defer (gb_free(heap_allocator(), modified_types));
 	for_array(type_info_type_index, info->type_info_types) {
 	for_array(type_info_type_index, info->type_info_types) {
-		Type *t = info->type_info_types[type_info_type_index].type;
+		auto const &tt = info->type_info_types[type_info_type_index];
+		Type *t = tt.type;
 		if (t == nullptr || t == t_invalid) {
 		if (t == nullptr || t == t_invalid) {
 			continue;
 			continue;
 		}
 		}
 
 
-		isize entry_index = lb_type_info_index(info, t, false);
+		isize entry_index = lb_type_info_index(info, tt, false);
 		if (entry_index <= 0) {
 		if (entry_index <= 0) {
 			continue;
 			continue;
 		}
 		}

+ 19 - 4
src/name_canonicalization.cpp

@@ -48,6 +48,15 @@ gb_internal gbString temp_canonical_string(Type *type);
 struct TypeInfoPair;
 struct TypeInfoPair;
 struct TypeSet;
 struct TypeSet;
 
 
+gb_internal GB_COMPARE_PROC(type_info_pair_cmp) {
+	TypeInfoPair *x = cast(TypeInfoPair *)a;
+	TypeInfoPair *y = cast(TypeInfoPair *)b;
+	if (x->hash == y->hash) {
+		return 0;
+	}
+	return x->hash < y->hash ? -1 : +1;
+}
+
 static constexpr u64 TYPE_SET_TOMBSTONE = ~(u64)(0ull);
 static constexpr u64 TYPE_SET_TOMBSTONE = ~(u64)(0ull);
 
 
 gb_internal void  type_set_init   (TypeSet *s, isize capacity);
 gb_internal void  type_set_init   (TypeSet *s, isize capacity);
@@ -136,7 +145,7 @@ gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) {
 		usize hash_index = cast(usize)hash & mask;
 		usize hash_index = cast(usize)hash & mask;
 		for (usize i = 0; i < s->capacity; i++) {
 		for (usize i = 0; i < s->capacity; i++) {
 			Type *key = s->keys[hash_index].type;
 			Type *key = s->keys[hash_index].type;
-			if (are_types_identical(key, pair.type)) {
+			if (are_types_identical_unique_tuples(key, pair.type)) {
 				return hash_index;
 				return hash_index;
 			} else if (key == 0) {
 			} else if (key == 0) {
 				return -1;
 				return -1;
@@ -154,7 +163,7 @@ gb_internal isize type_set__find(TypeSet *s, Type *ptr) {
 		usize hash_index = cast(usize)hash & mask;
 		usize hash_index = cast(usize)hash & mask;
 		for (usize i = 0; i < s->capacity; i++) {
 		for (usize i = 0; i < s->capacity; i++) {
 			Type *key = s->keys[hash_index].type;
 			Type *key = s->keys[hash_index].type;
-			if (are_types_identical(key, ptr)) {
+			if (are_types_identical_unique_tuples(key, ptr)) {
 				return hash_index;
 				return hash_index;
 			} else if (key == 0) {
 			} else if (key == 0) {
 				return -1;
 				return -1;
@@ -224,7 +233,7 @@ gb_internal bool type_set_update(TypeSet *s, TypeInfoPair pair) { // returns tru
 	GB_ASSERT(hash_index < s->capacity);
 	GB_ASSERT(hash_index < s->capacity);
 	for (usize i = 0; i < s->capacity; i++) {
 	for (usize i = 0; i < s->capacity; i++) {
 		TypeInfoPair *key = &s->keys[hash_index];
 		TypeInfoPair *key = &s->keys[hash_index];
-		GB_ASSERT(!are_types_identical(key->type, pair.type));
+		GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type));
 		if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) {
 		if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) {
 			*key = pair;
 			*key = pair;
 			s->count++;
 			s->count++;
@@ -274,6 +283,9 @@ gb_internal gbString write_canonical_params(gbString w, Type *params) {
 			if (i > 0) {
 			if (i > 0) {
 				w = gb_string_appendc(w, CANONICAL_PARAM_SEPARATOR);
 				w = gb_string_appendc(w, CANONICAL_PARAM_SEPARATOR);
 			}
 			}
+			w = gb_string_append_length(w, v->token.string.text, v->token.string.len);
+			w = gb_string_appendc(w, CANONICAL_TYPE_SEPARATOR);
+
 			if (v->kind == Entity_Variable) {
 			if (v->kind == Entity_Variable) {
 				if (v->flags&EntityFlag_CVarArg) {
 				if (v->flags&EntityFlag_CVarArg) {
 					w = gb_string_appendc(w, CANONICAL_PARAM_C_VARARG);
 					w = gb_string_appendc(w, CANONICAL_PARAM_C_VARARG);
@@ -466,14 +478,17 @@ write_base_name:
 	switch (e->kind) {
 	switch (e->kind) {
 	case Entity_TypeName:
 	case Entity_TypeName:
 		{
 		{
+
 			Type *params = nullptr;
 			Type *params = nullptr;
 			Entity *parent = type_get_polymorphic_parent(e->type, &params);
 			Entity *parent = type_get_polymorphic_parent(e->type, &params);
-			if (parent) {
+			if (parent && (parent->token.string == e->token.string)) {
 				w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len);
 				w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len);
 				w = write_canonical_params(w, params);
 				w = write_canonical_params(w, params);
 			} else {
 			} else {
 				w = gb_string_append_length(w, e->token.string.text, e->token.string.len);
 				w = gb_string_append_length(w, e->token.string.text, e->token.string.len);
 			}
 			}
+			gb_unused(parent);
+
 		}
 		}
 		// Handle parapoly stuff here?
 		// Handle parapoly stuff here?
 		return w;
 		return w;