name_canonicalization.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. gb_internal GB_COMPARE_PROC(type_info_pair_cmp) {
  2. TypeInfoPair *x = cast(TypeInfoPair *)a;
  3. TypeInfoPair *y = cast(TypeInfoPair *)b;
  4. if (x->hash == y->hash) {
  5. return 0;
  6. }
  7. return x->hash < y->hash ? -1 : +1;
  8. }
  9. gb_internal gbAllocator type_set_allocator(void) {
  10. return heap_allocator();
  11. }
  12. gb_internal TypeSetIterator begin(TypeSet &set) noexcept {
  13. usize index = 0;
  14. while (index < set.capacity) {
  15. TypeInfoPair key = set.keys[index];
  16. if (key.hash != 0 && key.hash != TYPE_SET_TOMBSTONE) {
  17. break;
  18. }
  19. index++;
  20. }
  21. return TypeSetIterator{&set, index};
  22. }
  23. gb_internal TypeSetIterator end(TypeSet &set) noexcept {
  24. return TypeSetIterator{&set, set.capacity};
  25. }
  26. gb_internal void type_set_init(TypeSet *s, isize capacity) {
  27. GB_ASSERT(s->keys == nullptr);
  28. if (capacity != 0) {
  29. capacity = next_pow2_isize(gb_max(16, capacity));
  30. s->keys = gb_alloc_array(type_set_allocator(), TypeInfoPair, capacity);
  31. // This memory will be zeroed, no need to explicitly zero it
  32. }
  33. s->count = 0;
  34. s->capacity = capacity;
  35. }
  36. gb_internal void type_set_destroy(TypeSet *s) {
  37. gb_free(type_set_allocator(), s->keys);
  38. s->keys = nullptr;
  39. s->count = 0;
  40. s->capacity = 0;
  41. }
  42. gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) {
  43. GB_ASSERT(pair.type != nullptr);
  44. GB_ASSERT(pair.hash != 0);
  45. if (s->count != 0) {
  46. usize hash = pair.hash;
  47. usize mask = s->capacity-1;
  48. usize hash_index = cast(usize)hash & mask;
  49. for (usize i = 0; i < s->capacity; i++) {
  50. Type *key = s->keys[hash_index].type;
  51. if (are_types_identical_unique_tuples(key, pair.type)) {
  52. return hash_index;
  53. } else if (key == 0) {
  54. return -1;
  55. }
  56. hash_index = (hash_index+1)&mask;
  57. }
  58. }
  59. return -1;
  60. }
  61. gb_internal isize type_set__find(TypeSet *s, Type *ptr) {
  62. GB_ASSERT(ptr != 0);
  63. if (s->count != 0) {
  64. usize hash = cast(usize)type_hash_canonical_type(ptr);
  65. usize mask = s->capacity-1;
  66. usize hash_index = cast(usize)hash & mask;
  67. for (usize i = 0; i < s->capacity; i++) {
  68. Type *key = s->keys[hash_index].type;
  69. if (are_types_identical_unique_tuples(key, ptr)) {
  70. return hash_index;
  71. } else if (key == 0) {
  72. return -1;
  73. }
  74. hash_index = (hash_index+1)&mask;
  75. }
  76. }
  77. return -1;
  78. }
  79. gb_internal bool type_set__full(TypeSet *s) {
  80. return 0.75f * s->capacity <= s->count;
  81. }
  82. gb_internal gb_inline void type_set_grow(TypeSet *old_set) {
  83. if (old_set->capacity == 0) {
  84. type_set_init(old_set);
  85. return;
  86. }
  87. TypeSet new_set = {};
  88. type_set_init(&new_set, gb_max(old_set->capacity<<1, 16));
  89. for (TypeInfoPair const &set : *old_set) {
  90. bool was_new = type_set_update(&new_set, set);
  91. GB_ASSERT(!was_new);
  92. }
  93. GB_ASSERT(old_set->count == new_set.count);
  94. type_set_destroy(old_set);
  95. *old_set = new_set;
  96. }
  97. gb_internal gb_inline bool type_set_exists(TypeSet *s, Type *ptr) {
  98. return type_set__find(s, ptr) >= 0;
  99. }
  100. gb_internal gb_inline bool type_set_exists(TypeSet *s, TypeInfoPair pair) {
  101. return type_set__find(s, pair) >= 0;
  102. }
  103. gb_internal gb_inline TypeInfoPair *type_set_retrieve(TypeSet *s, Type *type) {
  104. isize index = type_set__find(s, type);
  105. if (index >= 0) {
  106. return &s->keys[index];
  107. }
  108. return nullptr;
  109. }
  110. gb_internal bool type_set_update(TypeSet *s, TypeInfoPair pair) { // returns true if it previously existsed
  111. if (type_set_exists(s, pair)) {
  112. return true;
  113. }
  114. if (s->keys == nullptr) {
  115. type_set_init(s);
  116. } else if (type_set__full(s)) {
  117. type_set_grow(s);
  118. }
  119. GB_ASSERT(s->count < s->capacity);
  120. GB_ASSERT(s->capacity >= 0);
  121. usize mask = s->capacity-1;
  122. usize hash = cast(usize)pair.hash;
  123. usize hash_index = (cast(usize)hash) & mask;
  124. GB_ASSERT(hash_index < s->capacity);
  125. for (usize i = 0; i < s->capacity; i++) {
  126. TypeInfoPair *key = &s->keys[hash_index];
  127. GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type));
  128. if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) {
  129. *key = pair;
  130. s->count++;
  131. return false;
  132. }
  133. hash_index = (hash_index+1)&mask;
  134. }
  135. GB_PANIC("ptr set out of memory");
  136. return false;
  137. }
  138. gb_internal bool type_set_update(TypeSet *s, Type *ptr) { // returns true if it previously existsed
  139. TypeInfoPair pair = {ptr, type_hash_canonical_type(ptr)};
  140. return type_set_update(s, pair);
  141. }
  142. gb_internal Type *type_set_add(TypeSet *s, Type *ptr) {
  143. type_set_update(s, ptr);
  144. return ptr;
  145. }
  146. gb_internal Type *type_set_add(TypeSet *s, TypeInfoPair pair) {
  147. type_set_update(s, pair);
  148. return pair.type;
  149. }
  150. gb_internal void type_set_remove(TypeSet *s, Type *ptr) {
  151. isize index = type_set__find(s, ptr);
  152. if (index >= 0) {
  153. GB_ASSERT(s->count > 0);
  154. s->keys[index].type = nullptr;
  155. s->keys[index].hash = TYPE_SET_TOMBSTONE;
  156. s->count--;
  157. }
  158. }
  159. gb_internal gb_inline void type_set_clear(TypeSet *s) {
  160. s->count = 0;
  161. gb_zero_size(s->keys, s->capacity*gb_size_of(*s->keys));
  162. }
  163. #define TYPE_WRITER_PROC(name) bool name(TypeWriter *w, void const *ptr, isize len)
  164. typedef TYPE_WRITER_PROC(TypeWriterProc);
  165. struct TypeWriter {
  166. TypeWriterProc *proc;
  167. void *user_data;
  168. };
  169. bool type_writer_append(TypeWriter *w, void const *ptr, isize len) {
  170. return w->proc(w, ptr, len);
  171. }
  172. bool type_writer_appendb(TypeWriter *w, char b) {
  173. return w->proc(w, &b, 1);
  174. }
  175. bool type_writer_appendc(TypeWriter *w, char const *str) {
  176. isize len = gb_strlen(str);
  177. return w->proc(w, str, len);
  178. }
  179. bool type_writer_append_fmt(TypeWriter *w, char const *fmt, ...) {
  180. va_list va;
  181. char *str;
  182. va_start(va, fmt);
  183. str = gb_bprintf_va(fmt, va);
  184. va_end(va);
  185. return type_writer_appendc(w, str);
  186. }
  187. TYPE_WRITER_PROC(type_writer_string_writer_proc) {
  188. gbString *s = cast(gbString *)&w->user_data;
  189. *s = gb_string_append_length(*s, ptr, len);
  190. return true;
  191. }
  192. void type_writer_make_string(TypeWriter *w, gbAllocator allocator) {
  193. w->user_data = gb_string_make(allocator, "");
  194. w->proc = type_writer_string_writer_proc;
  195. }
  196. void type_writer_destroy_string(TypeWriter *w) {
  197. gb_string_free(cast(gbString)w->user_data);
  198. }
  199. TYPE_WRITER_PROC(type_writer_hasher_writer_proc) {
  200. u64 *seed = cast(u64 *)w->user_data;
  201. *seed = fnv64a(ptr, len, *seed);
  202. return true;
  203. }
  204. void type_writer_make_hasher(TypeWriter *w, u64 *hash) {
  205. w->user_data = hash;
  206. w->proc = type_writer_hasher_writer_proc;
  207. }
  208. gb_internal void write_canonical_params(TypeWriter *w, Type *params) {
  209. type_writer_appendc(w, "(");
  210. defer (type_writer_appendc(w, ")"));
  211. if (params == nullptr) {
  212. return;
  213. }
  214. GB_ASSERT(params->kind == Type_Tuple);
  215. for_array(i, params->Tuple.variables) {
  216. Entity *v = params->Tuple.variables[i];
  217. if (i > 0) {
  218. type_writer_appendc(w, CANONICAL_PARAM_SEPARATOR);
  219. }
  220. type_writer_append(w, v->token.string.text, v->token.string.len);
  221. type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
  222. switch (v->kind) {
  223. case Entity_Variable:
  224. if (v->flags&EntityFlag_CVarArg) {
  225. type_writer_appendc(w, CANONICAL_PARAM_C_VARARG);
  226. }
  227. if (v->flags&EntityFlag_Ellipsis) {
  228. Type *slice = base_type(v->type);
  229. type_writer_appendc(w, CANONICAL_PARAM_VARARG);
  230. GB_ASSERT(v->type->kind == Type_Slice);
  231. write_type_to_canonical_string(w, slice->Slice.elem);
  232. } else {
  233. write_type_to_canonical_string(w, v->type);
  234. }
  235. break;
  236. case Entity_TypeName:
  237. type_writer_appendc(w, CANONICAL_PARAM_TYPEID);
  238. write_type_to_canonical_string(w, v->type);
  239. break;
  240. case Entity_Constant:
  241. {
  242. type_writer_appendc(w, CANONICAL_PARAM_CONST);
  243. gbString s = exact_value_to_string(v->Constant.value, 1<<16);
  244. type_writer_append(w, s, gb_string_length(s));
  245. gb_string_free(s);
  246. }
  247. break;
  248. default:
  249. GB_PANIC("TODO(bill): handle non type/const parapoly parameter values");
  250. break;
  251. }
  252. }
  253. return;
  254. }
  255. gb_internal u64 type_hash_canonical_type(Type *type) {
  256. if (type == nullptr) {
  257. return 0;
  258. }
  259. u64 hash = fnv64a(nullptr, 0);
  260. TypeWriter w = {};
  261. type_writer_make_hasher(&w, &hash);
  262. write_type_to_canonical_string(&w, type);
  263. return hash ? hash : 1;
  264. }
  265. gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) {
  266. TypeWriter w = {};
  267. type_writer_make_string(&w, allocator);
  268. write_type_to_canonical_string(&w, type);
  269. gbString s = cast(gbString)w.user_data;
  270. return make_string(cast(u8 const *)s, gb_string_length(s));
  271. }
  272. gb_internal gbString temp_canonical_string(Type *type) {
  273. TypeWriter w = {};
  274. type_writer_make_string(&w, temporary_allocator());
  275. write_type_to_canonical_string(&w, type);
  276. return cast(gbString)w.user_data;
  277. }
  278. gb_internal gbString string_canonical_entity_name(gbAllocator allocator, Entity *e) {
  279. TypeWriter w = {};
  280. type_writer_make_string(&w, allocator);
  281. write_canonical_entity_name(&w, e);
  282. return cast(gbString)w.user_data;
  283. }
  284. gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) {
  285. GB_ASSERT(e != nullptr);
  286. if (e->kind == Entity_Procedure || e->kind == Entity_TypeName) {
  287. if (e->kind == Entity_Procedure && (e->Procedure.is_export || e->Procedure.is_foreign)) {
  288. // no prefix
  289. return;
  290. }
  291. if (e->parent_proc_decl) {
  292. Entity *p = e->parent_proc_decl->entity;
  293. write_canonical_parent_prefix(w, p);
  294. type_writer_append(w, p->token.string.text, p->token.string.len);
  295. if (is_type_polymorphic(p->type)) {
  296. type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
  297. write_type_to_canonical_string(w, p->type);
  298. }
  299. type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
  300. } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) {
  301. type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
  302. if (e->pkg->name == "llvm") {
  303. type_writer_appendc(w, "$");
  304. }
  305. type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
  306. } else {
  307. String file_name = filename_without_directory(e->file->fullpath);
  308. type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
  309. if (e->pkg->name == "llvm") {
  310. type_writer_appendc(w, "$");
  311. }
  312. type_writer_append_fmt(w, CANONICAL_NAME_SEPARATOR "%.*s" CANONICAL_NAME_SEPARATOR, LIT(file_name));
  313. }
  314. } else {
  315. GB_PANIC("TODO(bill): handle entity kind: %d", e->kind);
  316. }
  317. if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) {
  318. String file_name = filename_without_directory(e->file->fullpath);
  319. type_writer_append_fmt(w, CANONICAL_ANON_PREFIX "_%.*s:%d", LIT(file_name), e->token.pos.offset);
  320. } else {
  321. type_writer_append(w, e->token.string.text, e->token.string.len);
  322. }
  323. if (is_type_polymorphic(e->type)) {
  324. type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
  325. write_type_to_canonical_string(w, e->type);
  326. }
  327. type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
  328. return;
  329. }
  330. gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) {
  331. GB_ASSERT(e != nullptr);
  332. if (e->token.string == "_") {
  333. GB_PANIC("_ string");
  334. }
  335. if (e->token.string.len == 0) {
  336. GB_PANIC("empty string");
  337. }
  338. if (e->kind == Entity_Variable) {
  339. bool is_foreign = e->Variable.is_foreign;
  340. bool is_export = e->Variable.is_export;
  341. if (e->Variable.link_name.len > 0) {
  342. type_writer_append(w, e->Variable.link_name.text, e->Variable.link_name.len);
  343. return;
  344. } else if (is_foreign || is_export) {
  345. type_writer_append(w, e->token.string.text, e->token.string.len);
  346. return;
  347. }
  348. } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
  349. type_writer_append(w, e->Procedure.link_name.text, e->Procedure.link_name.len);
  350. return;
  351. } else if (e->kind == Entity_Procedure && e->Procedure.is_export) {
  352. type_writer_append(w, e->token.string.text, e->token.string.len);
  353. return;
  354. }
  355. bool write_scope_index_suffix = false;
  356. if (e->scope->flags & (ScopeFlag_Builtin)) {
  357. goto write_base_name;
  358. } else if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 ||
  359. e->flags & EntityFlag_NotExported) {
  360. Scope *s = e->scope;
  361. while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) {
  362. if (s->parent == nullptr) {
  363. break;
  364. }
  365. s = s->parent;
  366. }
  367. if (s->decl_info != nullptr && s->decl_info->entity) {
  368. Entity *parent = s->decl_info->entity;
  369. write_canonical_parent_prefix(w, parent);
  370. if (e->scope->index > 0) {
  371. write_scope_index_suffix = true;
  372. }
  373. goto write_base_name;
  374. } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) {
  375. String file_name = filename_without_directory(s->file->fullpath);
  376. type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
  377. if (e->pkg->name == "llvm") {
  378. type_writer_appendc(w, "$");
  379. }
  380. type_writer_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name)));
  381. goto write_base_name;
  382. } else if (s->flags & (ScopeFlag_Builtin)) {
  383. goto write_base_name;
  384. }
  385. gb_printf_err("%s WEIRD ENTITY TYPE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info);
  386. auto const print_scope_flags = [](Scope *s) {
  387. if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg ");
  388. if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin ");
  389. if (s->flags & ScopeFlag_Global) gb_printf_err("Global ");
  390. if (s->flags & ScopeFlag_File) gb_printf_err("File ");
  391. if (s->flags & ScopeFlag_Init) gb_printf_err("Init ");
  392. if (s->flags & ScopeFlag_Proc) gb_printf_err("Proc ");
  393. if (s->flags & ScopeFlag_Type) gb_printf_err("Type ");
  394. if (s->flags & ScopeFlag_HasBeenImported) gb_printf_err("HasBeenImported ");
  395. if (s->flags & ScopeFlag_ContextDefined) gb_printf_err("ContextDefined ");
  396. gb_printf_err("\n");
  397. };
  398. print_scope_flags(s);
  399. GB_PANIC("weird entity %.*s", LIT(e->token.string));
  400. }
  401. if (e->pkg != nullptr) {
  402. type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
  403. type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
  404. }
  405. write_base_name:
  406. switch (e->kind) {
  407. case Entity_TypeName:
  408. {
  409. Type *params = nullptr;
  410. Entity *parent = type_get_polymorphic_parent(e->type, &params);
  411. if (parent && (parent->token.string == e->token.string)) {
  412. type_writer_append(w, parent->token.string.text, parent->token.string.len);
  413. write_canonical_params(w, params);
  414. } else {
  415. type_writer_append(w, e->token.string.text, e->token.string.len);
  416. }
  417. }
  418. break;
  419. case Entity_Constant:
  420. // For debug symbols only
  421. /*fallthrough*/
  422. case Entity_Procedure:
  423. case Entity_Variable:
  424. type_writer_append(w, e->token.string.text, e->token.string.len);
  425. if (is_type_polymorphic(e->type)) {
  426. type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
  427. write_type_to_canonical_string(w, e->type);
  428. }
  429. break;
  430. default:
  431. GB_PANIC("TODO(bill): entity kind %d", e->kind);
  432. break;
  433. }
  434. if (write_scope_index_suffix) {
  435. GB_ASSERT(e != nullptr && e->scope != nullptr);
  436. type_writer_append_fmt(w, CANONICAL_NAME_SEPARATOR "$%d", e->scope->index);
  437. }
  438. return;
  439. }
  440. gb_internal bool is_in_doc_writer(void);
  441. // NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string
  442. gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
  443. if (type == nullptr) {
  444. type_writer_appendc(w, CANONICAL_NONE_TYPE); // none/void type
  445. return;
  446. }
  447. type = default_type(type);
  448. GB_ASSERT(!is_type_untyped(type));
  449. switch (type->kind) {
  450. case Type_Basic:
  451. type_writer_append(w, type->Basic.name.text, type->Basic.name.len);
  452. return;
  453. case Type_Pointer:
  454. type_writer_appendb(w, '^');
  455. write_type_to_canonical_string(w, type->Pointer.elem);
  456. return;
  457. case Type_MultiPointer:
  458. type_writer_appendc(w, "[^]");
  459. write_type_to_canonical_string(w, type->Pointer.elem);
  460. return;
  461. case Type_SoaPointer:
  462. type_writer_appendc(w, "#soa^");
  463. write_type_to_canonical_string(w, type->Pointer.elem);
  464. return;
  465. case Type_EnumeratedArray:
  466. if (type->EnumeratedArray.is_sparse) {
  467. type_writer_appendc(w, "#sparse");
  468. }
  469. type_writer_appendb(w, '[');
  470. write_type_to_canonical_string(w, type->EnumeratedArray.index);
  471. type_writer_appendb(w, ']');
  472. write_type_to_canonical_string(w, type->EnumeratedArray.elem);
  473. return;
  474. case Type_Array:
  475. type_writer_append_fmt(w, "[%lld]", cast(long long)type->Array.count);
  476. write_type_to_canonical_string(w, type->Array.elem);
  477. return;
  478. case Type_Slice:
  479. type_writer_appendc(w, "[]");
  480. write_type_to_canonical_string(w, type->Array.elem);
  481. return;
  482. case Type_DynamicArray:
  483. type_writer_appendc(w, "[dynamic]");
  484. write_type_to_canonical_string(w, type->DynamicArray.elem);
  485. return;
  486. case Type_SimdVector:
  487. type_writer_append_fmt(w, "#simd[%lld]", cast(long long)type->SimdVector.count);
  488. write_type_to_canonical_string(w, type->SimdVector.elem);
  489. return;
  490. case Type_Matrix:
  491. if (type->Matrix.is_row_major) {
  492. type_writer_appendc(w, "#row_major ");
  493. }
  494. type_writer_append_fmt(w, "matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count);
  495. write_type_to_canonical_string(w, type->Matrix.elem);
  496. return;
  497. case Type_Map:
  498. type_writer_appendc(w, "map[");
  499. write_type_to_canonical_string(w, type->Map.key);
  500. type_writer_appendc(w, "]");
  501. write_type_to_canonical_string(w, type->Map.value);
  502. return;
  503. case Type_Enum:
  504. type_writer_appendc(w, "enum");
  505. if (type->Enum.base_type != nullptr) {
  506. type_writer_appendb(w, ' ');
  507. write_type_to_canonical_string(w, type->Enum.base_type);
  508. type_writer_appendb(w, ' ');
  509. }
  510. type_writer_appendb(w, '{');
  511. for_array(i, type->Enum.fields) {
  512. Entity *f = type->Enum.fields[i];
  513. GB_ASSERT(f->kind == Entity_Constant);
  514. if (i > 0) {
  515. type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
  516. }
  517. type_writer_append(w, f->token.string.text, f->token.string.len);
  518. type_writer_appendc(w, "=");
  519. gbString s = exact_value_to_string(f->Constant.value, 1<<16);
  520. type_writer_append(w, s, gb_string_length(s));
  521. gb_string_free(s);
  522. }
  523. type_writer_appendb(w, '}');
  524. return;
  525. case Type_BitSet:
  526. type_writer_appendc(w, "bit_set[");
  527. if (type->BitSet.elem == nullptr) {
  528. type_writer_appendc(w, CANONICAL_NONE_TYPE);
  529. } else if (is_type_enum(type->BitSet.elem)) {
  530. write_type_to_canonical_string(w, type->BitSet.elem);
  531. } else {
  532. type_writer_append_fmt(w, "%lld", type->BitSet.lower);
  533. type_writer_append_fmt(w, CANONICAL_RANGE_OPERATOR);
  534. type_writer_append_fmt(w, "%lld", type->BitSet.upper);
  535. }
  536. if (type->BitSet.underlying != nullptr) {
  537. type_writer_appendc(w, ";");
  538. write_type_to_canonical_string(w, type->BitSet.underlying);
  539. }
  540. type_writer_appendc(w, "]");
  541. return;
  542. case Type_Union:
  543. type_writer_appendc(w, "union");
  544. switch (type->Union.kind) {
  545. case UnionType_no_nil: type_writer_appendc(w, "#no_nil"); break;
  546. case UnionType_shared_nil: type_writer_appendc(w, "#shared_nil"); break;
  547. }
  548. if (type->Union.custom_align != 0) {
  549. type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align);
  550. }
  551. type_writer_appendc(w, "{");
  552. for_array(i, type->Union.variants) {
  553. Type *t = type->Union.variants[i];
  554. if (i > 0) type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
  555. write_type_to_canonical_string(w, t);
  556. }
  557. type_writer_appendc(w, "}");
  558. return;
  559. case Type_Struct:
  560. if (type->Struct.soa_kind != StructSoa_None) {
  561. switch (type->Struct.soa_kind) {
  562. case StructSoa_Fixed: type_writer_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break;
  563. case StructSoa_Slice: type_writer_appendc(w, "#soa[]"); break;
  564. case StructSoa_Dynamic: type_writer_appendc(w, "#soa[dynamic]"); break;
  565. default: GB_PANIC("Unknown StructSoaKind"); break;
  566. }
  567. return write_type_to_canonical_string(w, type->Struct.soa_elem);
  568. }
  569. type_writer_appendc(w, "struct");
  570. if (type->Struct.is_packed) type_writer_appendc(w, "#packed");
  571. if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union");
  572. if (type->Struct.is_no_copy) type_writer_appendc(w, "#no_copy");
  573. 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);
  574. 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);
  575. if (type->Struct.custom_align != 0) type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align);
  576. type_writer_appendb(w, '{');
  577. for_array(i, type->Struct.fields) {
  578. Entity *f = type->Struct.fields[i];
  579. GB_ASSERT(f->kind == Entity_Variable);
  580. if (i > 0) {
  581. type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
  582. }
  583. type_writer_append(w, f->token.string.text, f->token.string.len);
  584. type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
  585. write_type_to_canonical_string(w, f->type);
  586. String tag = {};
  587. if (type->Struct.tags != nullptr) {
  588. tag = type->Struct.tags[i];
  589. }
  590. if (tag.len != 0) {
  591. String s = quote_to_ascii(heap_allocator(), tag);
  592. type_writer_append(w, s.text, s.len);
  593. gb_free(heap_allocator(), s.text);
  594. }
  595. }
  596. type_writer_appendb(w, '}');
  597. return;
  598. case Type_BitField:
  599. type_writer_appendc(w, "bit_field");
  600. write_type_to_canonical_string(w, type->BitField.backing_type);
  601. type_writer_appendc(w, " {");
  602. for (isize i = 0; i < type->BitField.fields.count; i++) {
  603. Entity *f = type->BitField.fields[i];
  604. if (i > 0) {
  605. type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
  606. }
  607. type_writer_append(w, f->token.string.text, f->token.string.len);
  608. type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
  609. write_type_to_canonical_string(w, f->type);
  610. type_writer_appendc(w, CANONICAL_BIT_FIELD_SEPARATOR);
  611. type_writer_append_fmt(w, "%u", type->BitField.bit_sizes[i]);
  612. }
  613. type_writer_appendc(w, " }");
  614. return;
  615. case Type_Proc:
  616. type_writer_appendc(w, "proc");
  617. if (default_calling_convention() != type->Proc.calling_convention) {
  618. type_writer_appendc(w, "\"");
  619. type_writer_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]);
  620. type_writer_appendc(w, "\"");
  621. }
  622. write_canonical_params(w, type->Proc.params);
  623. if (type->Proc.result_count > 0) {
  624. type_writer_appendc(w, "->");
  625. write_canonical_params(w, type->Proc.results);
  626. }
  627. return;
  628. case Type_Generic:
  629. if (is_in_doc_writer()) {
  630. type_writer_appendc(w, "$");
  631. type_writer_append(w, type->Generic.name.text, type->Generic.name.len);
  632. type_writer_append_fmt(w, "%lld", cast(long long)type->Generic.id);
  633. } else {
  634. GB_PANIC("Type_Generic should never be hit");
  635. }
  636. return;
  637. case Type_Named:
  638. if (type->Named.type_name != nullptr) {
  639. write_canonical_entity_name(w, type->Named.type_name);
  640. return;
  641. } else {
  642. type_writer_append(w, type->Named.name.text, type->Named.name.len);
  643. }
  644. return;
  645. case Type_Tuple:
  646. type_writer_appendc(w, "params");
  647. write_canonical_params(w, type);
  648. return;
  649. default:
  650. GB_PANIC("unknown type kind %d %.*s", type->kind, LIT(type_strings[type->kind]));
  651. break;
  652. }
  653. return;
  654. }