kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

type.c (40739B)


      1 /* C type construction.
      2  *
      3  * Types are interned per-Pool: a single `type_void(pool)` returns the same
      4  * Type* on every call against the same pool, and structurally-equal calls
      5  * to type_prim/type_ptr/type_func collapse to the same Type*. The cache is
      6  * a small open structure stored through Pool.type_cache (opaque to other
      7  * consumers).
      8  *
      9  * Storage: every Type and every supporting array (TY_FUNC param vectors,
     10  * TY_STRUCT field arrays) is allocated from the Pool's arena, so pointers
     11  * are stable for the Pool's lifetime.
     12  *
     13  * v1 covers what the cg test harness drives:
     14  *   void / scalars / pointer / function / struct / union
     15  * Other constructors (array, qualified, enum) and predicates have minimal
     16  * implementations sufficient for the cg test surface; they will grow with
     17  * the parser. */
     18 
     19 #include "type/type.h"
     20 
     21 #include <stdint.h>
     22 #include <string.h>
     23 
     24 #define NUM_PRIM_KINDS ((unsigned)TY_LDOUBLE + 1u)
     25 
     26 typedef struct TypeListNode TypeListNode;
     27 struct TypeListNode {
     28   TypeListNode* next;
     29   Type ty;
     30 };
     31 
     32 static u32 type_fnv_ptr(u32 h, const void* q) {
     33   u64 u = (u64)(uintptr_t)q;
     34   h = (h ^ (u32)u) * 16777619u;
     35   h = (h ^ (u32)(u >> 32)) * 16777619u;
     36   return h;
     37 }
     38 
     39 /* Structural hash + equality over a (non-tagged) derived type's identity
     40  * fields. These hash-cons TY_PTR / TY_ARRAY / TY_FUNC and qualified variants of
     41  * non-tagged types: two independently built `int*` Types hash and compare equal
     42  * and so collapse to one canonical node. They compare fields, never raw bytes,
     43  * so a structural node's union tail and padding may stay uninitialized. */
     44 static u32 type_struct_hash(const Type* t) {
     45   u32 h = 2166136261u;
     46   h = (h ^ (u32)t->kind) * 16777619u;
     47   h = (h ^ (u32)t->qual) * 16777619u;
     48   switch (t->kind) {
     49     case TY_PTR:
     50       h = type_fnv_ptr(h, t->ptr.pointee);
     51       break;
     52     case TY_ARRAY:
     53       h = type_fnv_ptr(h, t->arr.elem);
     54       h = (h ^ t->arr.count) * 16777619u;
     55       h = (h ^ (u32)t->arr.incomplete) * 16777619u;
     56       break;
     57     case TY_FUNC: {
     58       u16 i;
     59       h = type_fnv_ptr(h, t->fn.ret);
     60       h = (h ^ (u32)t->fn.nparams) * 16777619u;
     61       h = (h ^ (u32)t->fn.variadic) * 16777619u;
     62       for (i = 0; i < t->fn.nparams; ++i) h = type_fnv_ptr(h, t->fn.params[i]);
     63       break;
     64     }
     65     default: /* qualified primitive: kind + qual is the whole key */
     66       break;
     67   }
     68   return h;
     69 }
     70 
     71 static int type_struct_eq(const Type* a, const Type* b) {
     72   if (a->kind != b->kind || a->qual != b->qual) return 0;
     73   switch (a->kind) {
     74     case TY_PTR:
     75       return a->ptr.pointee == b->ptr.pointee;
     76     case TY_ARRAY:
     77       return a->arr.elem == b->arr.elem && a->arr.count == b->arr.count &&
     78              a->arr.incomplete == b->arr.incomplete;
     79     case TY_FUNC: {
     80       u16 i;
     81       if (a->fn.ret != b->fn.ret || a->fn.nparams != b->fn.nparams ||
     82           a->fn.variadic != b->fn.variadic)
     83         return 0;
     84       for (i = 0; i < a->fn.nparams; ++i)
     85         if (a->fn.params[i] != b->fn.params[i]) return 0;
     86       return 1;
     87     }
     88     default: /* qualified primitive: kind + qual already matched */
     89       return 1;
     90   }
     91 }
     92 
     93 /* Structural intern SET: the canonical Type* IS the stored element and
     94  * membership is decided structurally (type_struct_eq) — which a scalar
     95  * key->value map cannot express, hence KIT_HASHSET_DEFINE. Interns
     96  * ptr/array/func + qualified non-tagged types; tagged types are interned by
     97  * declaration identity on `derived` and never enter this set. Replaces the
     98  * former O(types) linear scan of one flat derived list (which made each
     99  * derivation O(types) → type construction O(types^2)). */
    100 KIT_HASHSET_DEFINE(TypeInternSet, const Type*, type_struct_hash,
    101                    type_struct_eq);
    102 
    103 /* Completed record layout id, keyed by record identity. A record's identity is
    104  * its tag id (same_record_type is tag-id equality), so a plain u32->id map
    105  * captures it; the Pool is 1:1 with a compiler so no compiler key is needed.
    106  * Replaces the former per-lookup list scan (O(records^2) for record-heavy TUs).
    107  * Tag id 0 (TAG_NONE) never names a stored record, so it is safe as the empty
    108  * key sentinel. */
    109 KIT_HASHMAP_DEFINE(CgRecordMap, u32, KitCgTypeId, kit_hash_u32);
    110 
    111 static inline u32 type_ptr_hash(const Type* t) {
    112   return kit_hash_u64((uint64_t)(uintptr_t)t);
    113 }
    114 
    115 /* Canonical-unqualified Type* memo, keyed by the qualified Type*. Collapses the
    116  * O(derived) linear scan type_unqual runs for a complete tagged type (the hot
    117  * const-record path) to one lookup. Only stable answers are inserted (a
    118  * complete record's unqualified node never changes); incomplete/enum results
    119  * are left uncached because they can still change as a forward record
    120  * completes. */
    121 KIT_HASHMAP_DEFINE(CgUnqualMemo, const Type*, const Type*, type_ptr_hash);
    122 
    123 typedef struct PoolTypeCache {
    124   /* Direct slots for void + primitive kinds (TY_VOID..TY_LDOUBLE). */
    125   const Type* prim[NUM_PRIM_KINDS];
    126   /* Structurally-interned ptr/array/func + qualified non-tagged types. */
    127   TypeInternSet structural;
    128   /* Identity-interned tagged types (struct/union/enum, qualified or not) and
    129    * the throwaway record-builder results: a list, scanned only by the (rare)
    130    * tag-based type_qualified / type_unqual paths and never per derivation. */
    131   TypeListNode* derived;
    132   /* Completed record layout ids, keyed by tag id. */
    133   CgRecordMap cg_records;
    134   /* Records whose CG completion is currently in flight, keyed by tag id ->
    135    * decl id. Self-/mutually-recursive records reach themselves through a
    136    * pointer field mid-completion; this lets type_cg_record_layout hand back the
    137    * still-incomplete decl id (a pointer to an incomplete record is legal)
    138    * instead of recursing into a second completion of the same record. */
    139   CgRecordMap cg_records_completing;
    140   /* Canonical-unqualified node per qualified Type* (stable answers only). */
    141   CgUnqualMemo unqual;
    142   /* Tag id allocator (1-based; TAG_NONE = 0). */
    143   u32 next_tag;
    144 } PoolTypeCache;
    145 
    146 static PoolTypeCache* cache_get(Pool* p) {
    147   PoolTypeCache* c = (PoolTypeCache*)p->type_cache;
    148   if (c) return c;
    149   c = arena_new(p->arena, PoolTypeCache);
    150   if (!c) return NULL;
    151   memset(c, 0, sizeof *c);
    152   c->next_tag = 1;
    153   /* Both tables run on the pool's arena-heap facade: a resize orphans the old
    154    * array into the arena (reclaimed wholesale at teardown), so no fini hook is
    155    * needed. Lazy (cap 0): the first insert allocates. */
    156   TypeInternSet_init_cap(&c->structural, &p->arena_heap, 0);
    157   CgRecordMap_init_cap(&c->cg_records, &p->arena_heap, 0);
    158   CgRecordMap_init_cap(&c->cg_records_completing, &p->arena_heap, 0);
    159   CgUnqualMemo_init_cap(&c->unqual, &p->arena_heap, 0);
    160   p->type_cache = c;
    161   return c;
    162 }
    163 
    164 static Type* alloc_type_node(Pool* p, PoolTypeCache* c) {
    165   TypeListNode* n = arena_new(p->arena, TypeListNode);
    166   if (!n) return NULL;
    167   memset(n, 0, sizeof *n);
    168   n->next = c->derived;
    169   c->derived = n;
    170   return &n->ty;
    171 }
    172 
    173 /* Bare structural-type node: arena-allocated, NOT linked into `derived`, NOT
    174  * zeroed. Each constructor writes exactly the fields its kind reads; the
    175  * structural set compares those fields (not raw bytes), so the union tail and
    176  * padding may stay uninitialized. */
    177 static Type* alloc_struct_type(Pool* p) {
    178   Type* t = arena_new(p->arena, Type);
    179   /* cg_id is read before structural fields, so initialize it even though the
    180    * union tail is intentionally left undefined (see the header). Qualified /
    181    * unqual paths that do `*t = *base` inherit the cache, which is correct since
    182    * lowering ignores qualifiers today. */
    183   if (t) t->cg_id = KIT_CG_TYPE_NONE;
    184   return t;
    185 }
    186 
    187 const Type* type_void(Pool* p) { return type_prim(p, TY_VOID); }
    188 
    189 const Type* type_prim(Pool* p, TypeKind kind) {
    190   PoolTypeCache* c = cache_get(p);
    191   if (!c) return NULL;
    192   if ((unsigned)kind >= NUM_PRIM_KINDS) return NULL;
    193   if (c->prim[kind]) return c->prim[kind];
    194   Type* t = alloc_type_node(p, c);
    195   if (!t) return NULL;
    196   t->kind = (u16)kind;
    197   t->qual = 0;
    198   c->prim[kind] = t;
    199   return t;
    200 }
    201 
    202 const Type* type_ptr(Pool* p, const Type* pointee) {
    203   PoolTypeCache* c = cache_get(p);
    204   Type probe;
    205   const Type* found;
    206   Type* t;
    207   if (!c) return NULL;
    208   probe.kind = TY_PTR;
    209   probe.qual = 0;
    210   probe.ptr.pointee = pointee;
    211   found = TypeInternSet_find(&c->structural, &probe);
    212   if (found) return found;
    213   t = alloc_struct_type(p);
    214   if (!t) return NULL;
    215   t->kind = TY_PTR;
    216   t->qual = 0;
    217   t->ptr.pointee = pointee;
    218   TypeInternSet_add(&c->structural, t);
    219   return t;
    220 }
    221 
    222 const Type* type_array(Pool* p, const Type* elem, u32 count, int incomplete) {
    223   PoolTypeCache* c = cache_get(p);
    224   Type probe;
    225   const Type* found;
    226   Type* t;
    227   if (!c) return NULL;
    228   probe.kind = TY_ARRAY;
    229   probe.qual = 0;
    230   probe.arr.elem = elem;
    231   probe.arr.count = count;
    232   probe.arr.incomplete = (u8)(incomplete ? 1 : 0);
    233   found = TypeInternSet_find(&c->structural, &probe);
    234   if (found) return found;
    235   t = alloc_struct_type(p);
    236   if (!t) return NULL;
    237   t->kind = TY_ARRAY;
    238   t->qual = 0;
    239   t->arr.elem = elem;
    240   t->arr.count = count;
    241   t->arr.incomplete = (u8)(incomplete ? 1 : 0);
    242   TypeInternSet_add(&c->structural, t);
    243   return t;
    244 }
    245 
    246 const Type* type_func(Pool* p, const Type* ret, const Type** params, u16 n,
    247                       int variadic) {
    248   PoolTypeCache* c = cache_get(p);
    249   Type probe;
    250   const Type* found;
    251   Type* t;
    252   if (!c) return NULL;
    253   /* Borrow the caller's params array for the lookup; type_struct_eq compares it
    254    * element-wise. Only on a miss do we allocate a persistent copy. */
    255   probe.kind = TY_FUNC;
    256   probe.qual = 0;
    257   probe.fn.ret = ret;
    258   probe.fn.params = params;
    259   probe.fn.nparams = n;
    260   probe.fn.variadic = (u8)(variadic ? 1 : 0);
    261   found = TypeInternSet_find(&c->structural, &probe);
    262   if (found) return found;
    263   t = alloc_struct_type(p);
    264   if (!t) return NULL;
    265   t->kind = TY_FUNC;
    266   t->qual = 0;
    267   t->fn.ret = ret;
    268   t->fn.nparams = n;
    269   t->fn.variadic = (u8)(variadic ? 1 : 0);
    270   if (n) {
    271     const Type** dst = arena_array(p->arena, const Type*, n);
    272     if (!dst) return NULL;
    273     for (u16 i = 0; i < n; ++i) dst[i] = params[i];
    274     t->fn.params = dst;
    275   } else {
    276     t->fn.params = NULL;
    277   }
    278   TypeInternSet_add(&c->structural, t);
    279   return t;
    280 }
    281 
    282 /* Semantic identity of a tagged type for interning: kind + qual + the rec/enm
    283  * identity payload. Replaces a memcmp over sizeof(Type) — which worked only
    284  * because every tagged node carries zeroed padding (alloc_type_node memsets and
    285  * struct assignment propagates it), a latent footgun that also forced the
    286  * lowered-id cache off the node onto a side map. `incomplete` is part of the
    287  * key (unlike type_compatible) because the qualified-snapshot model keeps an
    288  * incomplete and a later-completed `const struct S` as distinct nodes. `n` is
    289  * an interned node; `base` + the wanted `qual` describe the target (the payload
    290  * is base's). */
    291 static int type_tagged_eq(const Type* n, const Type* base, u16 qual) {
    292   if (n->kind != base->kind || n->qual != qual) return 0;
    293   switch ((TypeKind)base->kind) {
    294     case TY_STRUCT:
    295     case TY_UNION:
    296       return n->rec.tag_id == base->rec.tag_id && n->rec.tag == base->rec.tag &&
    297              n->rec.fields == base->rec.fields &&
    298              n->rec.nfields == base->rec.nfields &&
    299              n->rec.incomplete == base->rec.incomplete &&
    300              n->rec.packed == base->rec.packed &&
    301              n->rec.max_align == base->rec.max_align &&
    302              n->rec.align_override == base->rec.align_override;
    303     case TY_ENUM:
    304       return n->enm.tag_id == base->enm.tag_id && n->enm.tag == base->enm.tag &&
    305              n->enm.base == base->enm.base;
    306     default:
    307       return 0;
    308   }
    309 }
    310 
    311 const Type* type_qualified(Pool* p, const Type* base, u16 qual) {
    312   PoolTypeCache* c;
    313   Type* t;
    314   if (!base || qual == 0) return base;
    315   c = cache_get(p);
    316   if (!c) return NULL;
    317   if (base->kind == TY_STRUCT || base->kind == TY_UNION ||
    318       base->kind == TY_ENUM) {
    319     /* Tagged types are identity-interned on `derived` by semantic payload
    320      * (type_tagged_eq), not a raw-byte compare. */
    321     for (TypeListNode* n = c->derived; n; n = n->next) {
    322       if (type_tagged_eq(&n->ty, base, qual)) return &n->ty;
    323     }
    324     t = alloc_type_node(p, c);
    325     if (!t) return NULL;
    326     *t = *base;
    327     t->qual = qual;
    328     return t;
    329   }
    330   /* Non-tagged: structurally interned (qualified prim / ptr / array / func). */
    331   {
    332     Type probe = *base;
    333     const Type* found;
    334     probe.qual = qual;
    335     found = TypeInternSet_find(&c->structural, &probe);
    336     if (found) return found;
    337     t = alloc_struct_type(p);
    338     if (!t) return NULL;
    339     *t = *base;
    340     t->qual = qual;
    341     TypeInternSet_add(&c->structural, t);
    342     return t;
    343   }
    344 }
    345 
    346 /* ---- aggregates ---- */
    347 
    348 struct TypeRecordBuilder {
    349   Pool* pool;
    350   TypeKind kind; /* TY_STRUCT or TY_UNION */
    351   TagId tag_id;
    352   Sym tag;
    353   Field* fields;
    354   u32 nfields;
    355   u32 cap;
    356   TypeRecordOpts opts;
    357 };
    358 
    359 TagId type_tag_new(Pool* p, TagDeclKind kind, Sym spelling, SrcLoc loc) {
    360   PoolTypeCache* c = cache_get(p);
    361   if (!c) return TAG_NONE;
    362   (void)kind;
    363   (void)spelling;
    364   (void)loc;
    365   return (TagId)(c->next_tag++);
    366 }
    367 
    368 TypeRecordBuilder* type_record_begin(Pool* p, TypeKind kind, TagId tag_id,
    369                                      Sym tag) {
    370   TypeRecordOpts opts;
    371   memset(&opts, 0, sizeof opts);
    372   return type_record_begin_ex(p, kind, tag_id, tag, opts);
    373 }
    374 
    375 TypeRecordBuilder* type_record_begin_ex(Pool* p, TypeKind kind, TagId tag_id,
    376                                         Sym tag, TypeRecordOpts opts) {
    377   TypeRecordBuilder* b = arena_new(p->arena, TypeRecordBuilder);
    378   if (!b) return NULL;
    379   memset(b, 0, sizeof *b);
    380   b->pool = p;
    381   b->kind = kind;
    382   b->tag_id = tag_id;
    383   b->tag = tag;
    384   b->opts = opts;
    385   return b;
    386 }
    387 
    388 void type_record_field(TypeRecordBuilder* b, Field f) {
    389   if (b->nfields == b->cap) {
    390     u32 nc = b->cap ? b->cap * 2 : 4;
    391     Field* nf = arena_array(b->pool->arena, Field, nc);
    392     if (!nf) return;
    393     if (b->fields) memcpy(nf, b->fields, sizeof(Field) * b->nfields);
    394     b->fields = nf;
    395     b->cap = nc;
    396   }
    397   b->fields[b->nfields++] = f;
    398 }
    399 
    400 const Type* type_record_end(Pool* p, TypeRecordBuilder* b) {
    401   PoolTypeCache* c = cache_get(p);
    402   if (!c) return NULL;
    403   Type* t = alloc_type_node(p, c);
    404   if (!t) return NULL;
    405   t->kind = (u16)b->kind;
    406   t->qual = 0;
    407   t->rec.tag_id = b->tag_id;
    408   t->rec.tag = b->tag;
    409   t->rec.fields = b->fields;
    410   t->rec.nfields = (u16)b->nfields;
    411   t->rec.incomplete = 0;
    412   t->rec.packed = b->opts.packed;
    413   t->rec.max_align = b->opts.max_align;
    414   t->rec.align_override = b->opts.align_override;
    415   return t;
    416 }
    417 
    418 Type* type_record_forward(Pool* p, TypeKind kind, TagId tag_id, Sym tag) {
    419   PoolTypeCache* c = cache_get(p);
    420   if (!c) return NULL;
    421   Type* t = alloc_type_node(p, c);
    422   if (!t) return NULL;
    423   t->kind = (u16)kind;
    424   t->qual = 0;
    425   t->rec.tag_id = tag_id;
    426   t->rec.tag = tag;
    427   t->rec.fields = NULL;
    428   t->rec.nfields = 0;
    429   t->rec.incomplete = 1;
    430   t->rec.packed = 0;
    431   t->rec.max_align = 0;
    432   t->rec.align_override = 0;
    433   return t;
    434 }
    435 
    436 void type_record_install(Type* forward, const Field* fields, u16 nfields) {
    437   if (!forward) return;
    438   forward->rec.fields = fields;
    439   forward->rec.nfields = nfields;
    440   forward->rec.incomplete = 0;
    441 }
    442 
    443 const Type* type_enum(Pool* p, TagId tag_id, Sym tag, const Type* base) {
    444   PoolTypeCache* c = cache_get(p);
    445   if (!c) return NULL;
    446   Type* t = alloc_type_node(p, c);
    447   if (!t) return NULL;
    448   t->kind = TY_ENUM;
    449   t->qual = 0;
    450   t->enm.tag_id = tag_id;
    451   t->enm.tag = tag;
    452   t->enm.base = base;
    453   return t;
    454 }
    455 
    456 /* ---- predicates / utilities ---- */
    457 
    458 const Type* type_unqual(Pool* p, const Type* t) {
    459   PoolTypeCache* c;
    460   Type* nt;
    461   if (!t || t->qual == 0) return t;
    462   if ((unsigned)t->kind < NUM_PRIM_KINDS)
    463     return type_prim(p, (TypeKind)t->kind);
    464   c = cache_get(p);
    465   if (!c) return NULL;
    466   if (t->kind == TY_STRUCT || t->kind == TY_UNION || t->kind == TY_ENUM) {
    467     /* Tagged types are identity-interned on `derived`. */
    468     if ((t->kind == TY_STRUCT || t->kind == TY_UNION) &&
    469         t->rec.tag_id != TAG_NONE) {
    470       /* The only memoized case: a complete record's unqualified node is fixed
    471        * for the pool's lifetime, so this O(derived) scan can be skipped after
    472        * the first hit. The memo holds only struct/union entries, so it is
    473        * consulted here rather than taxing the (single-hash) non-tagged path. */
    474       const Type* const* hit = CgUnqualMemo_get(&c->unqual, t);
    475       if (hit) return *hit;
    476       for (TypeListNode* n = c->derived; n; n = n->next) {
    477         if (n->ty.kind == t->kind && n->ty.qual == 0 &&
    478             n->ty.rec.tag_id == t->rec.tag_id && !n->ty.rec.incomplete) {
    479           /* The incomplete/enum fall-throughs below stay uncached — their
    480            * result can still change as a forward record completes. */
    481           CgUnqualMemo_set(&c->unqual, t, &n->ty);
    482           return &n->ty;
    483         }
    484       }
    485     }
    486     for (TypeListNode* n = c->derived; n; n = n->next) {
    487       if (type_tagged_eq(&n->ty, t, 0)) return &n->ty;
    488     }
    489     nt = alloc_type_node(p, c);
    490     if (!nt) return NULL;
    491     *nt = *t;
    492     nt->qual = 0;
    493     return nt;
    494   }
    495   /* Non-tagged: structurally interned (qualified prim is handled above as a
    496    * prim; here that leaves ptr / array / func). */
    497   {
    498     Type probe = *t;
    499     const Type* found;
    500     probe.qual = 0;
    501     found = TypeInternSet_find(&c->structural, &probe);
    502     if (found) return found;
    503     nt = alloc_struct_type(p);
    504     if (!nt) return NULL;
    505     *nt = *t;
    506     nt->qual = 0;
    507     TypeInternSet_add(&c->structural, nt);
    508     return nt;
    509   }
    510 }
    511 
    512 const Type* type_promoted(Pool* p, const Type* t) {
    513   if (!t) return t;
    514   switch (t->kind) {
    515     case TY_BOOL:
    516     case TY_CHAR:
    517     case TY_SCHAR:
    518     case TY_UCHAR:
    519     case TY_SHORT:
    520     case TY_USHORT:
    521       return type_prim(p, TY_INT);
    522     default:
    523       return t;
    524   }
    525 }
    526 
    527 static int type_compatible_inner(const Type* a, const Type* b, unsigned depth) {
    528   u16 i;
    529   if (depth > 64) return 0;
    530   if (a == b) return 1;
    531   if (!a || !b) return 0;
    532   if (a->qual != b->qual) return 0;
    533   if (a->kind != b->kind) return 0;
    534   switch (a->kind) {
    535     case TY_VOID:
    536     case TY_BOOL:
    537     case TY_CHAR:
    538     case TY_SCHAR:
    539     case TY_UCHAR:
    540     case TY_SHORT:
    541     case TY_USHORT:
    542     case TY_INT:
    543     case TY_UINT:
    544     case TY_LONG:
    545     case TY_ULONG:
    546     case TY_LLONG:
    547     case TY_ULLONG:
    548     case TY_INT128:
    549     case TY_UINT128:
    550     case TY_FLOAT:
    551     case TY_DOUBLE:
    552     case TY_LDOUBLE:
    553       return 1;
    554     case TY_PTR:
    555       return type_compatible_inner(a->ptr.pointee, b->ptr.pointee, depth + 1);
    556     case TY_ARRAY:
    557       if (!type_compatible_inner(a->arr.elem, b->arr.elem, depth + 1)) return 0;
    558       if (a->arr.incomplete || b->arr.incomplete) return 1;
    559       return a->arr.count == b->arr.count;
    560     case TY_FUNC:
    561       if (a->fn.variadic != b->fn.variadic) return 0;
    562       if (a->fn.nparams != b->fn.nparams) return 0;
    563       if (!type_compatible_inner(a->fn.ret, b->fn.ret, depth + 1)) return 0;
    564       for (i = 0; i < a->fn.nparams; ++i) {
    565         if (!type_compatible_inner(a->fn.params[i], b->fn.params[i], depth + 1))
    566           return 0;
    567       }
    568       return 1;
    569     case TY_STRUCT:
    570     case TY_UNION:
    571       return a->rec.tag_id != TAG_NONE && a->rec.tag_id == b->rec.tag_id;
    572     case TY_ENUM:
    573       if (a->enm.tag_id != TAG_NONE || b->enm.tag_id != TAG_NONE)
    574         return a->enm.tag_id == b->enm.tag_id;
    575       return type_compatible_inner(a->enm.base, b->enm.base, depth + 1);
    576     default:
    577       return 0;
    578   }
    579 }
    580 
    581 int type_compatible(const Type* a, const Type* b) {
    582   return type_compatible_inner(a, b, 0);
    583 }
    584 
    585 const Type* type_composite(Pool* p, const Type* a, const Type* b) {
    586   const Type* elem;
    587   const Type** params;
    588   u16 i;
    589   if (!type_compatible(a, b)) return NULL;
    590   if (a == b) return a;
    591   if (!a || !b) return NULL;
    592   switch (a->kind) {
    593     case TY_ARRAY:
    594       elem = type_composite(p, a->arr.elem, b->arr.elem);
    595       if (!elem) elem = a->arr.elem;
    596       if (a->arr.incomplete && !b->arr.incomplete)
    597         return type_array(p, elem, b->arr.count, 0);
    598       if (b->arr.incomplete && !a->arr.incomplete)
    599         return type_array(p, elem, a->arr.count, 0);
    600       return type_array(p, elem, a->arr.count, a->arr.incomplete);
    601     case TY_PTR: {
    602       const Type* pointee = type_composite(p, a->ptr.pointee, b->ptr.pointee);
    603       if (!pointee) pointee = a->ptr.pointee;
    604       /* Preserve the pointer's own qualifiers (e.g. the inner `const` of
    605        * `const char* const*`); type_ptr alone yields an unqualified pointer. */
    606       return type_qualified(p, type_ptr(p, pointee), a->qual);
    607     }
    608     case TY_FUNC:
    609       if (a->fn.nparams == 0) return a;
    610       params = arena_array(p->arena, const Type*, a->fn.nparams);
    611       if (!params) return NULL;
    612       for (i = 0; i < a->fn.nparams; ++i) {
    613         params[i] = type_composite(p, a->fn.params[i], b->fn.params[i]);
    614         if (!params[i]) params[i] = a->fn.params[i];
    615       }
    616       return type_func(p, type_composite(p, a->fn.ret, b->fn.ret), params,
    617                        a->fn.nparams, a->fn.variadic);
    618     default:
    619       return a;
    620   }
    621 }
    622 
    623 /* Single source of truth for per-TypeKind scalar facts. Indexed directly by
    624  * TypeKind (sized to TY_ENUM + 1); the aggregate kinds PTR/ARRAY/FUNC/STRUCT/
    625  * UNION are zero-filled holes. Columns:
    626  *   is_signed  - signed integer (drives sign-extension / signed cg ops)
    627  *   is_int     - integer type (bool/char/.../enum)
    628  *   is_fp      - floating-point type
    629  *   rank       - C integer conversion rank (0 for non-integers)
    630  *   uvariant   - corresponding unsigned TypeKind (TY_UINT for non-integers,
    631  *                matching the historical default)
    632  * Accessors below read this table instead of re-enumerating the kinds. */
    633 typedef struct TypeKindProps {
    634   u8 is_signed;
    635   u8 is_int;
    636   u8 is_fp;
    637   u8 rank;
    638   u8 uvariant; /* TypeKind */
    639 } TypeKindProps;
    640 
    641 static const TypeKindProps kTypeKindProps[TY_ENUM + 1] = {
    642     [TY_VOID] = {0, 0, 0, 0, TY_UINT},
    643     [TY_BOOL] = {0, 1, 0, 1, TY_UINT},
    644     [TY_CHAR] = {1, 1, 0, 2, TY_UINT},
    645     [TY_SCHAR] = {1, 1, 0, 2, TY_UINT},
    646     [TY_UCHAR] = {0, 1, 0, 2, TY_UINT},
    647     [TY_SHORT] = {1, 1, 0, 3, TY_UINT},
    648     [TY_USHORT] = {0, 1, 0, 3, TY_UINT},
    649     [TY_INT] = {1, 1, 0, 4, TY_UINT},
    650     [TY_UINT] = {0, 1, 0, 4, TY_UINT},
    651     [TY_LONG] = {1, 1, 0, 5, TY_ULONG},
    652     [TY_ULONG] = {0, 1, 0, 5, TY_ULONG},
    653     [TY_LLONG] = {1, 1, 0, 6, TY_ULLONG},
    654     [TY_ULLONG] = {0, 1, 0, 6, TY_ULLONG},
    655     [TY_INT128] = {1, 1, 0, 7, TY_UINT128},
    656     [TY_UINT128] = {0, 1, 0, 7, TY_UINT128},
    657     [TY_FLOAT] = {0, 0, 1, 0, TY_UINT},
    658     [TY_DOUBLE] = {0, 0, 1, 0, TY_UINT},
    659     [TY_LDOUBLE] = {0, 0, 1, 0, TY_UINT},
    660     /* PTR/ARRAY/FUNC/STRUCT/UNION: zero-filled holes (uvariant 0 == TY_VOID
    661      * is never read for non-integers; callers map non-int to TY_UINT). */
    662     [TY_ENUM] = {1, 1, 0, 4, TY_UINT},
    663 };
    664 
    665 static const TypeKindProps* type_kind_props(TypeKind k) {
    666   if ((unsigned)k > (unsigned)TY_ENUM) return &kTypeKindProps[TY_VOID];
    667   return &kTypeKindProps[k];
    668 }
    669 
    670 int type_kind_is_int(TypeKind k) { return type_kind_props(k)->is_int; }
    671 int type_kind_is_fp(TypeKind k) { return type_kind_props(k)->is_fp; }
    672 int type_kind_is_signed_integer(TypeKind k) {
    673   return type_kind_props(k)->is_signed;
    674 }
    675 u32 type_kind_int_rank(TypeKind k) { return type_kind_props(k)->rank; }
    676 TypeKind type_kind_unsigned_variant(TypeKind k) {
    677   const TypeKindProps* p = type_kind_props(k);
    678   return p->is_int ? (TypeKind)p->uvariant : TY_UINT;
    679 }
    680 
    681 int type_is_int(const Type* t) {
    682   return t ? type_kind_is_int((TypeKind)t->kind) : 0;
    683 }
    684 
    685 int type_is_arith(const Type* t) {
    686   if (!t) return 0;
    687   return type_kind_is_int((TypeKind)t->kind) ||
    688          type_kind_is_fp((TypeKind)t->kind);
    689 }
    690 
    691 int type_is_ptr(const Type* t) { return t && t->kind == TY_PTR; }
    692 
    693 int type_is_signed_integer(const Type* t) {
    694   return t ? type_kind_is_signed_integer((TypeKind)t->kind) : 0;
    695 }
    696 
    697 static KitCgTypeId type_cg_builtin(KitCompiler* c, TypeKind kind) {
    698   /* Hot path: one builtin id per query, no whole-table copy. The target spec
    699    * (a by-value struct) is only consulted for the two data-model-dependent
    700    * widths, so it is fetched lazily inside those cases rather than per call. */
    701   switch (kind) {
    702     case TY_VOID:
    703       return kit_cg_type_builtin(c, KIT_CG_BUILTIN_VOID);
    704     case TY_BOOL:
    705       return kit_cg_type_builtin(c, KIT_CG_BUILTIN_BOOL);
    706     case TY_CHAR:
    707     case TY_SCHAR:
    708     case TY_UCHAR:
    709       return kit_cg_type_builtin(c, KIT_CG_BUILTIN_I8);
    710     case TY_SHORT:
    711     case TY_USHORT:
    712       return kit_cg_type_builtin(c, KIT_CG_BUILTIN_I16);
    713     case TY_INT:
    714     case TY_UINT:
    715       return kit_cg_type_builtin(c, KIT_CG_BUILTIN_I32);
    716     case TY_LONG:
    717     case TY_ULONG:
    718       return kit_cg_type_builtin(
    719           c, kit_target_uses_lp64(kit_compiler_target_spec(c))
    720                  ? KIT_CG_BUILTIN_I64
    721                  : KIT_CG_BUILTIN_I32);
    722     case TY_LLONG:
    723     case TY_ULLONG:
    724       return kit_cg_type_builtin(c, KIT_CG_BUILTIN_I64);
    725     case TY_INT128:
    726     case TY_UINT128:
    727       return kit_cg_type_builtin(c, KIT_CG_BUILTIN_I128);
    728     case TY_FLOAT:
    729       return kit_cg_type_builtin(c, KIT_CG_BUILTIN_F32);
    730     case TY_DOUBLE:
    731       return kit_cg_type_builtin(c, KIT_CG_BUILTIN_F64);
    732     case TY_LDOUBLE:
    733       /* `long double` is IEEE-754 binary128 on targets that follow the quad
    734        * psABI (RISC-V, aarch64-linux, wasm32); elsewhere it aliases `double`.
    735        * See kit_target_long_double_is_binary128. */
    736       return kit_cg_type_builtin(
    737           c, kit_target_long_double_is_binary128(kit_compiler_target_spec(c))
    738                  ? KIT_CG_BUILTIN_F128
    739                  : KIT_CG_BUILTIN_F64);
    740     default:
    741       break;
    742   }
    743   return KIT_CG_TYPE_NONE;
    744 }
    745 
    746 /* Source spelling + debug encoding per integer/char TypeKind. CG integer
    747  * storage is width-only; this table drives the separate debug channel so C
    748  * signedness and spelling reach DWARF without changing the operational type id.
    749  * Kinds with a NULL name use the debug producer's default derivation. */
    750 typedef struct ScalarDbgSpec {
    751   const char* name;
    752   u8 enc; /* KitCgDebugEncoding */
    753 } ScalarDbgSpec;
    754 
    755 static const ScalarDbgSpec kScalarDbg[TY_ENUM + 1] = {
    756     [TY_CHAR] = {"char", KIT_CG_DEBUG_ENC_SIGNED_CHAR},
    757     [TY_SCHAR] = {"signed char", KIT_CG_DEBUG_ENC_SIGNED_CHAR},
    758     [TY_UCHAR] = {"unsigned char", KIT_CG_DEBUG_ENC_UNSIGNED_CHAR},
    759     [TY_SHORT] = {"short", KIT_CG_DEBUG_ENC_SIGNED},
    760     [TY_USHORT] = {"unsigned short", KIT_CG_DEBUG_ENC_UNSIGNED},
    761     [TY_INT] = {"int", KIT_CG_DEBUG_ENC_SIGNED},
    762     [TY_UINT] = {"unsigned int", KIT_CG_DEBUG_ENC_UNSIGNED},
    763     [TY_LONG] = {"long", KIT_CG_DEBUG_ENC_SIGNED},
    764     [TY_ULONG] = {"unsigned long", KIT_CG_DEBUG_ENC_UNSIGNED},
    765     [TY_LLONG] = {"long long", KIT_CG_DEBUG_ENC_SIGNED},
    766     [TY_ULLONG] = {"unsigned long long", KIT_CG_DEBUG_ENC_UNSIGNED},
    767     [TY_INT128] = {"__int128", KIT_CG_DEBUG_ENC_SIGNED},
    768     [TY_UINT128] = {"unsigned __int128", KIT_CG_DEBUG_ENC_UNSIGNED},
    769 };
    770 
    771 /* Lower a scalar TypeKind to its operational CG type id: a bare storage builtin
    772  * for scalar kinds, or NONE for non-scalar kinds (caller falls through to the
    773  * structural lowering). Pure function of (kind, target), like type_cg_builtin.
    774  */
    775 static KitCgTypeId type_cg_scalar(KitCompiler* c, TypeKind kind) {
    776   return type_cg_builtin(c, kind);
    777 }
    778 
    779 typedef enum TypeCgMode {
    780   TYPE_CG_VALUE,
    781 } TypeCgMode;
    782 
    783 typedef struct TypeCgLower {
    784   KitCompiler* c;
    785   Pool* p;
    786   PoolTypeCache* cache;
    787   /* Raised whenever lowering passes through a still-incomplete record; scoped
    788    * per subtree by type_cg_lower so a node is memoized only when its whole
    789    * lowering was incomplete-free (and thus stable for the pool's lifetime). */
    790   int saw_incomplete;
    791 } TypeCgLower;
    792 
    793 static KitCgTypeId type_cg_lower(TypeCgLower* l, const Type* t,
    794                                  TypeCgMode mode);
    795 
    796 /* Record identity is its tag id (records are never structurally interned), so
    797  * the memo is a plain tag-id -> layout-id map. Only ever called with STRUCT/
    798  * UNION types, so t->rec is live; complete records always carry a non-zero tag,
    799  * so tag 0 is free to serve as the map's empty-key sentinel. */
    800 static KitCgTypeId type_cg_record_memo_get(PoolTypeCache* cache, KitCompiler* c,
    801                                            const Type* t) {
    802   const KitCgTypeId* hit;
    803   (void)c;
    804   if (!cache) return KIT_CG_TYPE_NONE;
    805   hit = CgRecordMap_get(&cache->cg_records, t->rec.tag_id);
    806   return hit ? *hit : KIT_CG_TYPE_NONE;
    807 }
    808 
    809 static void type_cg_record_memo_put(Pool* p, PoolTypeCache* cache,
    810                                     KitCompiler* c, const Type* t,
    811                                     KitCgTypeId id) {
    812   (void)p;
    813   (void)c;
    814   if (!cache || !t || id == KIT_CG_TYPE_NONE) return;
    815   if (t->kind != TY_STRUCT && t->kind != TY_UNION) return;
    816   if (t->rec.tag_id == TAG_NONE) return;
    817   CgRecordMap_set(&cache->cg_records, t->rec.tag_id, id);
    818 }
    819 
    820 static KitCgTypeId type_cg_record_decl_id(TypeCgLower* l, const Type* t) {
    821   KitCgTypeId id;
    822   if (!l || !t || (t->kind != TY_STRUCT && t->kind != TY_UNION)) {
    823     return KIT_CG_TYPE_NONE;
    824   }
    825   id = type_cg_record_memo_get(l->cache, l->c, t);
    826   if (id != KIT_CG_TYPE_NONE) return id;
    827   id = kit_cg_type_record_decl(l->c, t->rec.tag, t->kind == TY_UNION);
    828   type_cg_record_memo_put(l->p, l->cache, l->c, t, id);
    829   return id;
    830 }
    831 
    832 static KitCgTypeId type_cg_record_layout(TypeCgLower* l, const Type* t) {
    833   KitCgFieldDesc* fields = NULL;
    834   KitCgRecordDesc desc;
    835   KitCgTypeId id;
    836   int tracked = 0;
    837   if (!l || !t || (t->kind != TY_STRUCT && t->kind != TY_UNION)) {
    838     return KIT_CG_TYPE_NONE;
    839   }
    840   id = type_cg_record_decl_id(l, t);
    841   if (id == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    842   if (t->rec.incomplete) {
    843     l->saw_incomplete = 1;
    844     return id;
    845   }
    846   if (kit_cg_type_is_complete(l->c, id)) return id;
    847   /* Cycle safety net. Recursion *through a pointer* is already broken in the
    848    * TY_PTR case (the pointee takes the decl id, never re-entering here), so the
    849    * valid self-/mutual-reference shapes never reach this guard. What can still
    850    * re-enter mid-completion is a by-value path back to an in-flight record --
    851    * e.g. the invalid `struct N { struct N arr[10]; }`, where the array forces
    852    * its incomplete element to lay out. Hand back the still-incomplete decl id
    853    * (the array then fails the sized-element check, surfacing a clean error)
    854    * rather than recursing into a second completion and overflowing the stack.
    855    * Track every in-flight record so mutual by-value cycles are covered too.
    856    * Anonymous records carry no tag but cannot name themselves, so they never
    857    * reach this guard. */
    858   if (t->rec.tag_id != TAG_NONE) {
    859     if (CgRecordMap_get(&l->cache->cg_records_completing, t->rec.tag_id)) {
    860       l->saw_incomplete = 1;
    861       return id;
    862     }
    863     CgRecordMap_set(&l->cache->cg_records_completing, t->rec.tag_id, id);
    864     tracked = 1;
    865   }
    866   if (t->rec.nfields) {
    867     fields = arena_zarray(l->p->arena, KitCgFieldDesc, t->rec.nfields);
    868     if (!fields) {
    869       id = KIT_CG_TYPE_NONE;
    870       goto done;
    871     }
    872     for (u32 i = 0; i < t->rec.nfields; ++i) {
    873       fields[i].name = t->rec.fields[i].name;
    874       fields[i].type = type_cg_lower(l, t->rec.fields[i].type, TYPE_CG_VALUE);
    875       fields[i].align_override = t->rec.fields[i].align_override;
    876       fields[i].max_align = t->rec.fields[i].max_align;
    877       if (t->rec.max_align &&
    878           (fields[i].max_align == 0 || t->rec.max_align < fields[i].max_align))
    879         fields[i].max_align = t->rec.max_align;
    880       if (t->rec.fields[i].flags & FIELD_BITFIELD) {
    881         fields[i].flags |= KIT_CG_FIELD_BITFIELD;
    882         /* A zero-width bit-field is carried to CG as bit_width 0 (the layout
    883          * barrier); CG keys off BITFIELD && bit_width==0, no separate flag. */
    884         fields[i].bit_width = t->rec.fields[i].bitfield_width;
    885         fields[i].bit_signed = type_is_signed_integer(t->rec.fields[i].type);
    886       }
    887       if (t->rec.fields[i].packed && fields[i].align_override == 0) {
    888         fields[i].align_override = 1;
    889       }
    890       if (t->rec.packed && fields[i].align_override == 0) {
    891         fields[i].align_override = 1;
    892       }
    893     }
    894   }
    895   memset(&desc, 0, sizeof desc);
    896   desc.tag = t->rec.tag;
    897   desc.fields = fields;
    898   desc.nfields = t->rec.nfields;
    899   desc.is_union = t->kind == TY_UNION;
    900   desc.align_override = t->rec.align_override;
    901   if (kit_cg_type_record_complete(l->c, id, &desc) != KIT_OK)
    902     id = KIT_CG_TYPE_NONE;
    903 done:
    904   /* Clear the in-flight marker so a later, independent lowering of the same tag
    905    * (now CG-complete) takes the fast is_complete path rather than this guard.
    906    */
    907   if (tracked) CgRecordMap_del(&l->cache->cg_records_completing, t->rec.tag_id);
    908   return id;
    909 }
    910 
    911 static KitCgTypeId type_cg_lower(TypeCgLower* l, const Type* t,
    912                                  TypeCgMode mode) {
    913   KitCgTypeId id;
    914   int cacheable;
    915   int outer_incomplete;
    916   if (!l || !t) return KIT_CG_TYPE_NONE;
    917   /* Check the cache BEFORE the builtin switch: a cached cg_id (whether a
    918    * builtin id stamped below or a non-builtin lowering) always equals what the
    919    * switch would recompute, so this hoist only short-circuits already-lowered
    920    * types -- byte-identical, but skips the recompute. */
    921   cacheable = (mode == TYPE_CG_VALUE);
    922   if (cacheable && t->cg_id != KIT_CG_TYPE_NONE)
    923     return t->cg_id; /* cached => was incomplete-free => still stable */
    924   id = type_cg_scalar(l->c, (TypeKind)t->kind);
    925   if (id != KIT_CG_TYPE_NONE) {
    926     /* type_cg_scalar is a pure function of t->kind (and the fixed target), so
    927      * a scalar id is mode-independent and incomplete-free: stamp it on the
    928      * node so the next VALUE-mode crossing short-circuits above. Scalar ids are
    929      * never 0, so they can't alias the NONE sentinel. */
    930     if (cacheable) ((Type*)t)->cg_id = id;
    931     return id;
    932   }
    933   /* Scope saw_incomplete to this subtree so the post-recursion check reflects
    934    * only whether *this* node's lowering touched an incomplete record. */
    935   outer_incomplete = l->saw_incomplete;
    936   l->saw_incomplete = 0;
    937   switch ((TypeKind)t->kind) {
    938     case TY_PTR: {
    939       /* A pointer needs only its pointee's nominal identity, never its layout,
    940        * so a record/union pointee lowers to its (possibly incomplete) decl id
    941        * instead of being completed here. This is what makes a forward-declared
    942        * record used only through pointers legal without ever completing it, and
    943        * it breaks self-/mutual-reference cycles (struct N { struct N* next; },
    944        * A<->B) at the pointer rather than recursing into completion. A record
    945        * is completed only when something needs its layout -- a by-value local,
    946        * field, param/result, array element, sizeof, or member access -- all of
    947        * which lower the record itself, not a pointer to it. */
    948       const Type* pointee = t->ptr.pointee;
    949       KitCgTypeId pid;
    950       if (pointee->kind == TY_STRUCT || pointee->kind == TY_UNION) {
    951         pid = type_cg_record_decl_id(l, pointee);
    952         if (pid != KIT_CG_TYPE_NONE && !kit_cg_type_is_complete(l->c, pid))
    953           l->saw_incomplete = 1;
    954       } else {
    955         pid = type_cg_lower(l, pointee, TYPE_CG_VALUE);
    956       }
    957       id = pid == KIT_CG_TYPE_NONE ? KIT_CG_TYPE_NONE
    958                                    : kit_cg_type_ptr(l->c, pid, 0);
    959       break;
    960     }
    961     case TY_ARRAY:
    962       id = kit_cg_type_array(l->c, type_cg_lower(l, t->arr.elem, mode),
    963                              t->arr.count);
    964       break;
    965     case TY_FUNC: {
    966       KitCgFuncParam* params = NULL;
    967       KitCgFuncSig sig;
    968       memset(&sig, 0, sizeof sig);
    969       sig.result.type = type_cg_lower(l, t->fn.ret, TYPE_CG_VALUE);
    970       sig.nparams = t->fn.nparams;
    971       sig.abi_variadic = t->fn.variadic;
    972       sig.call_conv = KIT_CG_CC_TARGET_C;
    973       if (t->fn.nparams) {
    974         params = arena_zarray(l->p->arena, KitCgFuncParam, t->fn.nparams);
    975         if (!params) {
    976           id = KIT_CG_TYPE_NONE;
    977           break;
    978         }
    979         for (u32 i = 0; i < t->fn.nparams; ++i) {
    980           params[i].type = type_cg_lower(l, t->fn.params[i], TYPE_CG_VALUE);
    981         }
    982       }
    983       sig.params = params;
    984       id = kit_cg_type_func(l->c, sig);
    985       break;
    986     }
    987     case TY_STRUCT:
    988     case TY_UNION:
    989       id = type_cg_record_layout(l, t);
    990       break;
    991     case TY_ENUM: {
    992       KitCgTypeId ebase = type_cg_lower(l, t->enm.base, mode);
    993       KitCgEnumValue* evs = NULL;
    994       u32 nv = t->enm.nconsts;
    995       if (nv) {
    996         evs = arena_array(l->p->arena, KitCgEnumValue, nv);
    997         if (!evs) {
    998           nv = 0;
    999         } else {
   1000           for (u32 i = 0; i < nv; ++i) {
   1001             evs[i].name = t->enm.consts[i].name;
   1002             evs[i].value = (u64)t->enm.consts[i].value;
   1003           }
   1004         }
   1005       }
   1006       id = kit_cg_type_enum(l->c, t->enm.tag, ebase, evs, nv);
   1007       break;
   1008     }
   1009     default:
   1010       id = KIT_CG_TYPE_NONE;
   1011       break;
   1012   }
   1013   if (cacheable && id != KIT_CG_TYPE_NONE && !l->saw_incomplete) {
   1014     /* The node is the canonical interned type and we own its storage (arena);
   1015      * the const is only the public contract. Stashing the stable lowering here
   1016      * is exactly what dropping the memcmp interning bought us. */
   1017     ((Type*)t)->cg_id = id;
   1018   }
   1019   /* Propagate this subtree's incompleteness to the enclosing lowering. */
   1020   l->saw_incomplete |= outer_incomplete;
   1021   return id;
   1022 }
   1023 
   1024 KitCgTypeId type_cg_id_in_pool(KitCompiler* c, Pool* p, const Type* t) {
   1025   TypeCgLower l;
   1026   if (!p) return KIT_CG_TYPE_NONE;
   1027   /* TypeCgLower has exactly these four fields; explicit init writes the same
   1028    * values the memset+assignments did, skipping a per-crossing struct clear. */
   1029   l.c = c;
   1030   l.p = p;
   1031   l.cache = cache_get(p);
   1032   l.saw_incomplete = 0;
   1033   return type_cg_lower(&l, t, TYPE_CG_VALUE);
   1034 }
   1035 
   1036 typedef struct TypeCgDebugLower {
   1037   KitCg* cg;
   1038   KitCompiler* c;
   1039   Pool* p;
   1040   PoolTypeCache* cache;
   1041 } TypeCgDebugLower;
   1042 
   1043 static KitCgDebugType type_cg_debug_scalar(TypeCgDebugLower* l, TypeKind kind) {
   1044   KitCgTypeId storage = type_cg_builtin(l->c, kind);
   1045   const ScalarDbgSpec* s;
   1046   uint32_t bytes;
   1047   if (storage == KIT_CG_TYPE_NONE) return KIT_CG_DEBUG_TYPE_NONE;
   1048   if ((unsigned)kind > (unsigned)TY_ENUM) {
   1049     return kit_cg_debug_of_type(l->cg, storage);
   1050   }
   1051   s = &kScalarDbg[kind];
   1052   if (!s->name) return kit_cg_debug_of_type(l->cg, storage);
   1053   bytes = (uint32_t)kit_cg_type_size(l->c, storage);
   1054   if (!bytes) bytes = 1;
   1055   return kit_cg_debug_base(l->cg, kit_sym_intern(l->c, kit_slice_cstr(s->name)),
   1056                            (KitCgDebugEncoding)s->enc, bytes);
   1057 }
   1058 
   1059 static KitCgDebugType type_cg_debug_record_decl(TypeCgDebugLower* l,
   1060                                                 const Type* t) {
   1061   TypeCgLower op;
   1062   KitCgTypeId id;
   1063   op.c = l->c;
   1064   op.p = l->p;
   1065   op.cache = l->cache;
   1066   op.saw_incomplete = 0;
   1067   id = type_cg_record_decl_id(&op, t);
   1068   return kit_cg_debug_of_type(l->cg, id);
   1069 }
   1070 
   1071 static KitCgDebugType type_cg_debug_lower(TypeCgDebugLower* l, const Type* t) {
   1072   KitCgDebugType id;
   1073   if (!l || !t) return KIT_CG_DEBUG_TYPE_NONE;
   1074 
   1075   id = type_cg_debug_scalar(l, (TypeKind)t->kind);
   1076   if (id != KIT_CG_DEBUG_TYPE_NONE) return id;
   1077 
   1078   switch ((TypeKind)t->kind) {
   1079     case TY_PTR: {
   1080       const Type* pointee = t->ptr.pointee;
   1081       KitCgDebugType pd;
   1082       if (pointee->kind == TY_STRUCT || pointee->kind == TY_UNION) {
   1083         pd = type_cg_debug_record_decl(l, pointee);
   1084       } else {
   1085         pd = type_cg_debug_lower(l, pointee);
   1086       }
   1087       id = kit_cg_debug_ptr(l->cg, pd);
   1088       break;
   1089     }
   1090     case TY_ARRAY:
   1091       id = kit_cg_debug_array(l->cg, type_cg_debug_lower(l, t->arr.elem),
   1092                               t->arr.incomplete ? 0u : t->arr.count);
   1093       break;
   1094     case TY_FUNC: {
   1095       KitCgDebugType* params = NULL;
   1096       KitCgDebugType ret = type_cg_debug_lower(l, t->fn.ret);
   1097       if (t->fn.nparams) {
   1098         params = arena_zarray(l->p->arena, KitCgDebugType, t->fn.nparams);
   1099         if (!params) {
   1100           id = KIT_CG_DEBUG_TYPE_NONE;
   1101           break;
   1102         }
   1103         for (u32 i = 0; i < t->fn.nparams; ++i) {
   1104           params[i] = type_cg_debug_lower(l, t->fn.params[i]);
   1105         }
   1106       }
   1107       id = kit_cg_debug_func(l->cg, ret, params, t->fn.nparams, t->fn.variadic);
   1108       break;
   1109     }
   1110     case TY_STRUCT:
   1111     case TY_UNION: {
   1112       KitCgTypeId op_id = type_cg_id_in_pool(l->c, l->p, t);
   1113       id = kit_cg_debug_of_type(l->cg, op_id);
   1114       break;
   1115     }
   1116     case TY_ENUM: {
   1117       KitCgTypeId op_id = type_cg_id_in_pool(l->c, l->p, t);
   1118       KitCgDebugType base = type_cg_debug_lower(l, t->enm.base);
   1119       id = kit_cg_debug_enum(l->cg, op_id, base);
   1120       break;
   1121     }
   1122     default:
   1123       id = KIT_CG_DEBUG_TYPE_NONE;
   1124       break;
   1125   }
   1126 
   1127   return id;
   1128 }
   1129 
   1130 KitCgDebugType type_cg_debug_in_pool(KitCg* cg, KitCompiler* c, Pool* p,
   1131                                      const Type* t) {
   1132   TypeCgDebugLower l;
   1133   if (!cg || !p) return KIT_CG_DEBUG_TYPE_NONE;
   1134   l.cg = cg;
   1135   l.c = c;
   1136   l.p = p;
   1137   l.cache = cache_get(p);
   1138   return type_cg_debug_lower(&l, t);
   1139 }