resolver.c 109.7 KiB raw
1
#include <assert.h>
2
#include <limits.h>
3
#include <stdint.h>
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <string.h>
7
8
#include "ast.h"
9
#include "io.h"
10
#include "limits.h"
11
#include "module.h"
12
#include "resolver.h"
13
#include "riscv.h"
14
#include "strings.h"
15
#include "symtab.h"
16
#include "util.h"
17
18
#define max(a, b) (a > b ? a : b)
19
20
#define DEFAULT_SIZE  4
21
#define DEFAULT_ALIGN 4
22
23
static type_t *alloc_type(
24
    resolve_t  *t,
25
    typeclass_t kind,
26
    const char *name,
27
    usize       namel,
28
    i32         size,
29
    i32         align
30
);
31
static type_t *alloc_array_type(resolve_t *t, type_t *elem, usize length);
32
static type_t *alloc_slice_type(
33
    resolve_t *t, type_t *elem, type_t *base, bool mut
34
);
35
static type_t *alloc_union_type(resolve_t *t, union_decl_t *uni);
36
static type_t *alloc_result_type(resolve_t *t, type_t *payload, type_t *err);
37
static type_t *alloc_record_type(resolve_t *t, record_decl_t *rec);
38
static type_t *alloc_anonymous_record_type(resolve_t *t);
39
static type_t *alloc_ptr_type(resolve_t *t, type_t *base, bool mut);
40
static type_t *alloc_opt_type(resolve_t *t, type_t *elem);
41
static type_t *resolve_node(resolve_t *t, node_t *n, type_t *expected_type);
42
static type_t *resolve_var(resolve_t *t, node_t *n);
43
static type_t *resolve_const(resolve_t *t, node_t *n);
44
static type_t *resolve_static(resolve_t *t, node_t *n);
45
static type_t *resolve_use(resolve_t *t, node_t *n);
46
static type_t *resolve_mod_decl(resolve_t *t, node_t *n);
47
static bool    resolve_mod_def(resolve_t *t, module_t *module);
48
static type_t *resolve_scope(resolve_t *t, node_t *n);
49
static type_t *resolve_block(resolve_t *t, node_t *n);
50
static type_t *resolve_fn_def(resolve_t *t, node_t *n);
51
static type_t *resolve_fn_decl(resolve_t *t, node_t *n);
52
static type_t *resolve_number(resolve_t *t, node_t *n, type_t *expected);
53
static type_t *resolve_builtin(resolve_t *t, node_t *n, type_t *expected);
54
static bool    resolve_decls(resolve_t *t, module_t *module);
55
static type_t *resolve_throw(resolve_t *t, node_t *n);
56
static type_t *resolve_try_expr(resolve_t *t, node_t *n, type_t *expected);
57
static bool    declare_record(resolve_t *t, node_t *n);
58
static bool    declare_enum(resolve_t *t, node_t *n);
59
static type_t *resolve_tuple_record_constructor(
60
    resolve_t *t, node_t *call, type_t *record_type
61
);
62
static type_t *type_unify(
63
    resolve_t *t, type_t *a, type_t *b, node_t *n, bool co, const char *ctx
64
);
65
static type_t   *resolve_type(resolve_t *t, node_t *n);
66
static symbol_t *resolve_name(resolve_t *t, node_t *n, symkind_t kind);
67
static bool      resolve_const_usize(resolve_t *t, node_t *expr, usize *value);
68
static bool      symbol_add(resolve_t *t, node_t *ident, node_t *n);
69
static void      finalize_type_layout(resolve_t *t);
70
static void      module_scope_path(node_t *node, char *path_str);
71
static bool      node_is_super(const node_t *n);
72
static module_t *module_super_ancestor(module_t *mod, usize depth);
73
static bool      node_diverges(node_t *n);
74
75
/* Initialize type checker. */
76
void resolve_init(resolve_t *t, module_manager_t *mm) {
77
    t->fn              = NULL;
78
    t->global          = symtab_scope(NULL, NULL);
79
    t->scope           = t->global;
80
    t->mm              = mm;
81
    t->module          = NULL;
82
    t->recordid        = 0;
83
    t->ctx             = TC_CTX_NORMAL;
84
    t->types.nsympool  = 0;
85
    t->types.ntypepool = 0;
86
    t->types.type_bool = alloc_type(t, TYPE_BOOL, "bool", 4, 1, 1);
87
    t->types.type_char =
88
        alloc_type(t, TYPE_I8, "i8", 2, sizeof(i8), sizeof(i8));
89
    t->types.type_i8 = alloc_type(t, TYPE_I8, "i8", 2, sizeof(i8), sizeof(i8));
90
    t->types.type_i16 =
91
        alloc_type(t, TYPE_I16, "i16", 3, sizeof(i16), sizeof(i16));
92
    t->types.type_i32 =
93
        alloc_type(t, TYPE_I32, "i32", 3, sizeof(i32), sizeof(i32));
94
    t->types.type_u8 = alloc_type(t, TYPE_U8, "u8", 2, sizeof(u8), sizeof(u8));
95
    t->types.type_u16 =
96
        alloc_type(t, TYPE_U16, "u16", 3, sizeof(u16), sizeof(u16));
97
    t->types.type_u32 =
98
        alloc_type(t, TYPE_U32, "u32", 3, sizeof(u32), sizeof(u32));
99
    t->types.type_str    = alloc_slice_type(t, t->types.type_u8, NULL, false);
100
    t->types.type_void   = alloc_type(t, TYPE_VOID, "void", 4, 0, 0);
101
    t->types.type_opaque = alloc_type(t, TYPE_OPAQUE, "opaque", 6, 0, 0);
102
    t->types.type_never  = alloc_type(t, TYPE_NEVER, "never", 5, 0, 0);
103
104
    /* Add root module to global scope
105
     * so it can be accessed with `::module` */
106
    if (mm->root && mm->root->ast && mm->root->ast->sym) {
107
        /* Root module declarations are checked later, so just add the symbol */
108
        symtab_add_symbol(t->global, mm->root->ast->sym);
109
    }
110
}
111
112
symbol_t **types_alloc_sympool(types_t *t, u8 n) {
113
    assert(t->nsympool + n <= MAX_SYMPTR_POOL);
114
    symbol_t **ptr  = &t->sympool[t->nsympool];
115
    t->nsympool    += n;
116
    return ptr;
117
}
118
119
type_t **types_alloc_typepool(types_t *t, u8 n) {
120
    assert(t->ntypepool + n <= MAX_TYPEPTR_POOL);
121
    type_t **ptr  = &t->typepool[t->ntypepool];
122
    t->ntypepool += n;
123
    return ptr;
124
}
125
126
type_t *deref_type(type_t *ref) {
127
    type_t *target = ref->info.ptr.target;
128
129
    return target;
130
}
131
132
bool ident_eq(node_t *ident, const char *str, usize len) {
133
    const char *ident_str = ident->val.ident.name;
134
    usize       ident_len = ident->val.ident.length;
135
136
    return ident_len == len && (memcmp(ident_str, str, len) == 0);
137
}
138
139
static bool node_is_super(const node_t *n) {
140
    return n && n->cls == NODE_SUPER;
141
}
142
143
static module_t *module_super_ancestor(module_t *mod, usize depth) {
144
    module_t *current = mod;
145
146
    for (usize i = 0; i < depth; i++) {
147
        if (!current || !current->parent)
148
            return NULL;
149
        current = current->parent;
150
    }
151
    return current;
152
}
153
154
inline bool type_is_packed(type_t *t) {
155
    switch (t->cls) {
156
    case TYPE_RECORD:
157
        if ((i32)t->info.srt.packedsize != t->size) {
158
            return false;
159
        }
160
        break;
161
    case TYPE_ARRAY:
162
    case TYPE_SLICE:
163
    default:
164
        break;
165
    }
166
    return true;
167
}
168
169
inline bool type_is_numeric(typeclass_t t) {
170
    return t >= TYPE_I8 && t <= TYPE_U32;
171
}
172
173
inline bool type_is_address(typeclass_t t) {
174
    return t == TYPE_PTR || t == TYPE_SLICE || t == TYPE_FN;
175
}
176
177
inline bool type_is_compound(type_t *t) {
178
    typeclass_t cls = t->cls;
179
180
    return cls == TYPE_ARRAY || cls == TYPE_RECORD || cls == TYPE_SLICE ||
181
           cls == TYPE_PTR || cls == TYPE_OPT || cls == TYPE_RESULT ||
182
           cls == TYPE_FN || type_is_union_with_payload(t);
183
}
184
185
inline bool type_is_passed_by_ref(type_t *t) {
186
    typeclass_t cls = t->cls;
187
188
    return cls == TYPE_ARRAY || cls == TYPE_RECORD || cls == TYPE_SLICE ||
189
           cls == TYPE_OPT || cls == TYPE_RESULT ||
190
           type_is_union_with_payload(t);
191
}
192
193
inline bool type_is_union_with_payload(type_t *ty) {
194
    return ty->cls == TYPE_UNION && ty->info.uni.has_payload;
195
}
196
197
inline bool type_is_tagged_value(type_t *ty) {
198
    return ty->cls == TYPE_OPT || ty->cls == TYPE_RESULT ||
199
           type_is_union_with_payload(ty);
200
}
201
202
inline bool type_is_primitive(type_t *t) {
203
    return !type_is_compound(t);
204
}
205
206
inline bool type_is_int(typeclass_t t) {
207
    return t >= TYPE_I8 && t <= TYPE_U32;
208
}
209
210
inline bool type_is_unsigned(typeclass_t t) {
211
    return t == TYPE_U8 || t == TYPE_U16 || t == TYPE_U32;
212
}
213
214
bool type_coercible(type_t *a, type_t *b) {
215
    if (a == b)
216
        return true;
217
218
    /* Handle slice coercion: *mut [T] can coerce to *[T] */
219
    if (a->cls == TYPE_SLICE && b->cls == TYPE_SLICE) {
220
        if (a->info.slc.elem != b->info.slc.elem)
221
            return false;
222
        /* Mutable can coerce to immutable, but not vice versa */
223
        if (!a->info.slc.mut && b->info.slc.mut)
224
            return false;
225
        return true;
226
    }
227
    /* Handle pointer coercion: *mut T can coerce to *T */
228
    if (a->cls == TYPE_PTR && b->cls == TYPE_PTR) {
229
        if (a->info.ptr.target != b->info.ptr.target)
230
            return false;
231
        if (!a->info.ptr.mut && b->info.ptr.mut)
232
            return false;
233
        return true;
234
    }
235
    return false;
236
}
237
238
/* Unify two types, attempting to find the most general unifier.
239
 * Returns the unified type on success, or `NULL` if types cannot be unified.
240
 * If `n` and `context` are provided, reports an error on failure. */
241
static type_t *type_unify(
242
    resolve_t  *t,
243
    type_t     *a,
244
    type_t     *b,
245
    node_t     *n,      /* Node to report error on, or NULL for silent */
246
    bool        coerce, /* Allow safe type coercion */
247
    const char *context /* Context string for error message */
248
) {
249
    /* If the pointers are equal, they're already unified */
250
    if (a == b)
251
        return a;
252
    /* If they are both `NULL`, there's nothing we can do */
253
    if (!a && !b)
254
        return NULL;
255
256
    /* Treat `never` as compatible with any type. */
257
    if (a && a->cls == TYPE_NEVER)
258
        return b ? b : a;
259
    if (b && b->cls == TYPE_NEVER)
260
        return a ? a : b;
261
262
    /* If one type is NULL, create optional of the other type */
263
    if (!a && b && (b->cls == TYPE_OPT))
264
        return alloc_opt_type(t, b);
265
    if (!b && a && (a->cls == TYPE_OPT))
266
        return alloc_opt_type(t, a);
267
268
    /* If either type is `NULL` and the other is not an optional, bail,
269
     * because we have an error. */
270
    if (!a || !b) {
271
        return NULL;
272
    }
273
    /* Handle coercion of T to ?T */
274
    if (coerce) {
275
        if (b->cls == TYPE_OPT && a->cls != TYPE_OPT) {
276
            if (type_unify(t, a, b->info.opt.elem, n, coerce, context)) {
277
                return b; /* a unifies with ?T's element, result is ?T */
278
            }
279
            /* Try to unify a with the optional's element type */
280
            type_t *unified =
281
                type_unify(t, a, b->info.opt.elem, NULL, coerce, NULL);
282
            if (unified) {
283
                return alloc_opt_type(t, unified);
284
            }
285
        }
286
    }
287
    /* Handle pointer types */
288
    if (a->cls == TYPE_PTR && b->cls == TYPE_PTR) {
289
        /* Allow coercion from *T to *opaque and *mut T to *mut opaque */
290
        if (coerce && (a->info.ptr.target->cls == TYPE_OPAQUE ||
291
                       b->info.ptr.target->cls == TYPE_OPAQUE)) {
292
            return a->info.ptr.target->cls == TYPE_OPAQUE ? a : b;
293
        }
294
295
        type_t *unified = type_unify(
296
            t, a->info.ptr.target, b->info.ptr.target, NULL, coerce, NULL
297
        );
298
        if (unified) {
299
            /* When coercing *mut T to *T, prefer immutable target */
300
            if (coerce && a->info.ptr.mut && !b->info.ptr.mut) {
301
                return b;
302
            }
303
            if (unified == a->info.ptr.target) {
304
                return a;
305
            } else if (unified == b->info.ptr.target) {
306
                return b;
307
            } else {
308
                return alloc_ptr_type(t, unified, a->info.ptr.mut);
309
            }
310
        }
311
        goto error;
312
    }
313
    /* Handle numeric type unification - promote to wider type */
314
    if (type_is_numeric(a->cls) && type_is_numeric(b->cls)) {
315
        /* Return the "wider" type based on size and signedness */
316
        if (a->size > b->size) {
317
            return a;
318
        } else if (b->size > a->size) {
319
            return b;
320
        } else {
321
            /* Same size - prefer unsigned over signed */
322
            if ((a->cls >= TYPE_U8 && a->cls <= TYPE_U32) &&
323
                (b->cls >= TYPE_I8 && b->cls <= TYPE_I32)) {
324
                return a; /* a is unsigned, b is signed */
325
            } else if ((b->cls >= TYPE_U8 && b->cls <= TYPE_U32) &&
326
                       (a->cls >= TYPE_I8 && a->cls <= TYPE_I32)) {
327
                return b; /* b is unsigned, a is signed */
328
            } else {
329
                return a; /* Default to first type if same category */
330
            }
331
        }
332
    }
333
    /* Handle array types */
334
    if (a->cls == TYPE_ARRAY && b->cls == TYPE_ARRAY) {
335
        /* Arrays must have same length to unify */
336
        if (a->info.ary.length != b->info.ary.length) {
337
            goto error;
338
        }
339
        /* Unify element types */
340
        type_t *unified = type_unify(
341
            t, a->info.ary.elem, b->info.ary.elem, NULL, false, NULL
342
        );
343
        if (unified) {
344
            /* If element types are already the same, return existing array */
345
            if (unified == a->info.ary.elem) {
346
                return a;
347
            } else if (unified == b->info.ary.elem) {
348
                return b;
349
            } else {
350
                return alloc_array_type(t, unified, a->info.ary.length);
351
            }
352
        }
353
        goto error;
354
    }
355
    /* Handle slice types */
356
    if (a->cls == TYPE_SLICE && b->cls == TYPE_SLICE) {
357
        /* Allow coercion from *[T] to *[opaque] */
358
        if (coerce && (a->info.slc.elem->cls == TYPE_OPAQUE ||
359
                       b->info.slc.elem->cls == TYPE_OPAQUE)) {
360
            return a->info.slc.elem->cls == TYPE_OPAQUE ? a : b;
361
        }
362
        type_t *unified = type_unify(
363
            t, a->info.slc.elem, b->info.slc.elem, NULL, false, NULL
364
        );
365
        if (unified) {
366
            /* When coercing *mut [T] to *[T], prefer immutable target */
367
            if (coerce && a->info.slc.mut && !b->info.slc.mut) {
368
                return b;
369
            }
370
            if (unified == a->info.slc.elem) {
371
                return a;
372
            } else if (unified == b->info.slc.elem) {
373
                return b;
374
            } else {
375
                return alloc_slice_type(t, unified, NULL, a->info.slc.mut);
376
            }
377
        }
378
        goto error;
379
    }
380
    /* Handle optional types */
381
    if (a->cls == TYPE_OPT && b->cls == TYPE_OPT) {
382
        type_t *unified = type_unify(
383
            t, a->info.opt.elem, b->info.opt.elem, NULL, coerce, NULL
384
        );
385
        if (unified) {
386
            if (unified == a->info.opt.elem) {
387
                return a;
388
            } else if (unified == b->info.opt.elem) {
389
                return b;
390
            } else {
391
                return alloc_opt_type(t, unified);
392
            }
393
        }
394
        goto error;
395
    }
396
    if (a->cls == TYPE_RESULT && b->cls == TYPE_RESULT) {
397
        if (a->info.res.err != b->info.res.err)
398
            goto error;
399
400
        type_t *payload = type_unify(
401
            t, a->info.res.payload, b->info.res.payload, NULL, coerce, NULL
402
        );
403
404
        if (payload) {
405
            if (payload == a->info.res.payload) {
406
                return a;
407
            } else if (payload == b->info.res.payload) {
408
                return b;
409
            }
410
        }
411
        goto error;
412
    }
413
    /* Handle array to slice conversion */
414
    if (a->cls == TYPE_ARRAY && b->cls == TYPE_SLICE) {
415
        if (b->info.slc.mut) {
416
            goto error;
417
        }
418
        type_t *unified = type_unify(
419
            t, a->info.ary.elem, b->info.slc.elem, NULL, coerce, NULL
420
        );
421
        if (unified && unified == a->info.ary.elem) {
422
            return a->slice; /* Convert array to its slice type */
423
        }
424
        goto error;
425
    }
426
    if (b->cls == TYPE_ARRAY && a->cls == TYPE_SLICE) {
427
        if (a->info.slc.mut) {
428
            goto error;
429
        }
430
        type_t *unified = type_unify(
431
            t, a->info.slc.elem, b->info.ary.elem, NULL, coerce, NULL
432
        );
433
        if (unified && unified == b->info.ary.elem) {
434
            return b->slice; /* Convert array to its slice type */
435
        }
436
        goto error;
437
    }
438
    if (a->cls == TYPE_FN && b->cls == TYPE_FN) {
439
        usize nparams = a->info.fun.nparams;
440
        if (b->info.fun.nparams != nparams) {
441
            goto error;
442
        }
443
        for (usize i = 0; i < nparams; i++) {
444
            type_t *pa = a->info.fun.params[i];
445
            type_t *pb = b->info.fun.params[i];
446
447
            if (pa != pb)
448
                goto error;
449
        }
450
        if (a->info.fun.ret != b->info.fun.ret)
451
            goto error;
452
453
        return a;
454
    }
455
456
error:
457
    return NULL;
458
}
459
460
static type_t *resolve_throw(resolve_t *t, node_t *n) {
461
    type_t *fn_ret   = t->fn->node->type->info.fun.ret;
462
    type_t *err_type = fn_ret->info.res.err;
463
464
    if (!resolve_node(t, n->val.throw_stmt.expr, err_type))
465
        return NULL;
466
467
    return (n->type = fn_ret);
468
}
469
470
static type_t *resolve_try_expr(resolve_t *t, node_t *n, type_t *expected) {
471
    bool    optional   = n->val.try_expr.optional;
472
    node_t *expr       = n->val.try_expr.expr;
473
    node_t *catch_expr = n->val.try_expr.catch_expr;
474
475
    resolve_ctx_t pctx = t->ctx;
476
    t->ctx             = TC_CTX_TRY;
477
    type_t *expr_type  = resolve_node(t, expr, NULL);
478
    t->ctx             = pctx;
479
480
    if (!expr_type)
481
        return NULL;
482
    type_t *payload = expr_type->info.res.payload;
483
484
    /* `try?` converts errors to nil and returns an optional type. */
485
    if (optional) {
486
        if (payload->cls != TYPE_OPT) {
487
            payload = alloc_opt_type(t, payload);
488
        }
489
        return (n->type = payload);
490
    }
491
492
    if (catch_expr) {
493
        node_t *catch_binding = catch_expr->val.catch_clause.binding;
494
        node_t *catch_body    = catch_expr->val.catch_clause.body;
495
        type_t *err_type      = expr_type->info.res.err;
496
497
        /* If there's a binding, create a scope and add the error variable. */
498
        if (catch_binding) {
499
            catch_expr->val.catch_clause.scope = symtab_scope(t->scope, NULL);
500
            t->scope = catch_expr->val.catch_clause.scope;
501
502
            catch_binding->type = err_type;
503
            if (!symbol_add(t, catch_binding, catch_binding))
504
                return NULL;
505
506
            catch_binding->sym->e.var.typ   = err_type;
507
            catch_binding->sym->e.var.align = err_type->align;
508
            catch_binding->sym->scope       = t->scope;
509
        }
510
        type_t *catch_type = resolve_node(t, catch_body, NULL);
511
512
        if (catch_binding) {
513
            t->scope = t->scope->parent;
514
        }
515
        if (!catch_type)
516
            return NULL;
517
        if (catch_type->cls != TYPE_NEVER)
518
            return (n->type = t->types.type_void);
519
520
        /* Divergent catch block: fall through and keep payload type. */
521
    }
522
523
    if (expected) {
524
        type_t *target = expected;
525
526
        if (expected->cls == TYPE_RESULT)
527
            target = expected->info.res.payload;
528
529
        type_t *unified = type_unify(t, payload, target, n, true, NULL);
530
        if (unified)
531
            payload = unified;
532
    }
533
    return (n->type = payload);
534
}
535
536
/* Process a submodule declaration */
537
static type_t *resolve_mod_decl(resolve_t *t, node_t *n) {
538
    node_t *name = n->val.mod_decl.ident;
539
540
    char rel[MAX_PATH_LEN] = { 0 };
541
    strncpy(rel, name->val.ident.name, name->val.ident.length);
542
543
    /* Convert to path relative to current module and find it */
544
    module_t *submod =
545
        module_manager_find_relative(t->mm, t->module->path, rel);
546
    if (!submod)
547
        return NULL;
548
    symbol_t *sym = symtab_scope_lookup(
549
        t->scope, name->val.ident.name, name->val.ident.length, SYM_MODULE
550
    );
551
    if (sym) {
552
        n->sym = sym;
553
    } else {
554
        if (!symbol_add(t, name, n)) { /* Add module to current scope */
555
            return NULL;
556
        }
557
    }
558
    if (!resolve_decls(t, submod)) {
559
        return NULL;
560
    }
561
    /* For mod declarations, also do full type checking */
562
    if (!resolve_mod_def(t, submod)) {
563
        return NULL;
564
    }
565
    n->sym->e.mod          = submod;
566
    n->sym->e.mod->attribs = n->val.mod_decl.attribs
567
                                 ? n->val.mod_decl.attribs->val.attrib
568
                                 : ATTRIB_NONE;
569
    module_path(submod->qualified, t->module->qualified);
570
    module_qualify(submod->qualified, name);
571
572
    return (n->type = t->types.type_void);
573
}
574
575
/* Helper function to look up a symbol in a module's scope */
576
static type_t *module_lookup(
577
    resolve_t *t, node_t *n, node_t *child, module_t *module
578
) {
579
    /* If the module hasn't been checked yet, check it on-demand.
580
     * This allows parent modules to reference submodule types. */
581
    if (!module->scope && !module->declared &&
582
        module->state != MODULE_STATE_VISITING) {
583
        if (!resolve_decls(t, module)) {
584
            return NULL;
585
        }
586
    }
587
    if (!module->scope)
588
        return NULL;
589
590
    symbol_t *sym = symtab_scope_lookup(
591
        module->scope, child->val.ident.name, child->val.ident.length, SYM_ANY
592
    );
593
    if (!sym)
594
        return NULL;
595
    n->sym  = sym;
596
    n->type = sym->node->type;
597
598
    return n->type;
599
}
600
601
static symbol_t *union_variant_lookup(type_t *typ, node_t *n) {
602
    for (usize i = 0; i < typ->info.uni.nvariants; i++) {
603
        symbol_t *v = typ->info.uni.variants[i];
604
        if (ident_eq(n, v->name, v->length)) {
605
            return v;
606
        }
607
    }
608
    return NULL;
609
}
610
611
/* Look up a record field by name. */
612
static symbol_t *record_field_lookup(type_t *typ, node_t *n) {
613
    for (usize i = 0; i < typ->info.srt.nfields; i++) {
614
        symbol_t *f = typ->info.srt.fields[i];
615
        if (ident_eq(n, f->name, f->length)) {
616
            return f;
617
        }
618
    }
619
    return NULL;
620
}
621
622
/* Add a field to a record type. */
623
static bool record_field_add(
624
    resolve_t *t,
625
    type_t    *rec_typ,
626
    node_t    *field,
627
    node_t    *field_ident,
628
    type_t    *field_typ
629
) {
630
    (void)t;
631
    const char *field_name;
632
    usize       field_len;
633
    char        tuple_name[16];
634
635
    if (field_ident) {
636
        field_name = field_ident->val.ident.name;
637
        field_len  = field_ident->val.ident.length;
638
    } else {
639
        /* Tuple field: generate synthetic name based on index */
640
        snprintf(
641
            tuple_name,
642
            sizeof(tuple_name),
643
            "%u",
644
            (unsigned)rec_typ->info.srt.nfields
645
        );
646
        field_name = strings_alloc(tuple_name);
647
        field_len  = strlen(field_name);
648
    }
649
    field->type = field_typ;
650
651
    /* Nb. Since we're modifying the record size as we add fields, we always
652
     * add new fields at the end of the record. */
653
    i32 field_align    = field_typ->align;
654
    i32 aligned_offset = align(rec_typ->size, field_align);
655
656
    /* Keep track of packed size */
657
    rec_typ->info.srt.packedsize += field_typ->size;
658
659
    field->sym = alloc_symbol((symbol_t){
660
        .name = field_name,
661
        .length = field_len,
662
        .node = field,
663
        .kind = SYM_FIELD,
664
        .e.field = {
665
            .typ = field_typ,
666
            .offset = (i32)aligned_offset,
667
        },
668
    });
669
    /* Update record size to include this new field */
670
    rec_typ->size = aligned_offset + field_typ->size;
671
672
    /* Update record alignment to be the maximum of its current alignment
673
     * and the new field's alignment */
674
    rec_typ->align =
675
        (rec_typ->align > field_typ->align) ? rec_typ->align : field_typ->align;
676
    /* Add field to record type. */
677
    rec_typ->info.srt.fields[rec_typ->info.srt.nfields++] = field->sym;
678
679
    return true;
680
}
681
682
static bool update_i32(i32 *dst, i32 value) {
683
    if (*dst == value)
684
        return false;
685
    *dst = value;
686
    return true;
687
}
688
689
static bool update_bool(bool *dst, bool value) {
690
    if (*dst == value)
691
        return false;
692
    *dst = value;
693
    return true;
694
}
695
696
static bool update_record_layout(type_t *strct_typ) {
697
    i32  size         = 0;
698
    i32  record_align = 1;
699
    u32  packedsize   = 0;
700
    bool changed      = false;
701
702
    for (usize i = 0; i < strct_typ->info.srt.nfields; i++) {
703
        symbol_t *field_sym  = strct_typ->info.srt.fields[i];
704
        type_t   *field_type = field_sym->e.field.typ;
705
706
        i32 field_align = field_type->align ? field_type->align : DEFAULT_ALIGN;
707
        i32 field_size  = field_type->size;
708
        i32 offset      = align(size, field_align);
709
710
        if (field_sym->e.field.offset != offset) {
711
            field_sym->e.field.offset = offset;
712
            changed                   = true;
713
        }
714
715
        size = offset + field_size;
716
        if (field_align > record_align)
717
            record_align = field_align;
718
719
        packedsize += (u32)field_size;
720
    }
721
    /* Round overall size up to record alignment to match C layout. */
722
    size = align(size, record_align);
723
724
    changed |= update_i32(&strct_typ->size, size);
725
    changed |= update_i32(&strct_typ->align, record_align);
726
    if (strct_typ->info.srt.packedsize != packedsize) {
727
        strct_typ->info.srt.packedsize = packedsize;
728
        changed                        = true;
729
    }
730
731
    return changed;
732
}
733
734
static bool update_array_layout(type_t *typ) {
735
    type_t *elem = typ->info.ary.elem;
736
    if (!elem)
737
        return false;
738
739
    i32  elem_align = elem->align ? elem->align : DEFAULT_ALIGN;
740
    i32  size       = elem->size * (i32)typ->info.ary.length;
741
    bool changed    = false;
742
743
    changed |= update_i32(&typ->size, size);
744
    changed |= update_i32(&typ->align, elem_align);
745
746
    return changed;
747
}
748
749
static bool update_opt_layout(type_t *typ) {
750
    type_t *elem = typ->info.opt.elem;
751
    if (!elem)
752
        return false;
753
754
    i32  elem_align = elem->align ? elem->align : DEFAULT_ALIGN;
755
    i32  alignment  = max(elem_align, TAG_SIZE);
756
    i32  val_offset = align(TAG_SIZE, elem_align);
757
    i32  size       = align(val_offset + elem->size, alignment);
758
    bool changed    = false;
759
760
    changed |= update_i32(&typ->size, size);
761
    changed |= update_i32(&typ->align, alignment);
762
763
    return changed;
764
}
765
766
static bool update_result_layout(resolve_t *t, type_t *typ) {
767
    type_t *payload = typ->info.res.payload;
768
    type_t *err     = typ->info.res.err;
769
770
    i32 payload_align =
771
        payload == t->types.type_void ? TAG_SIZE : payload->align;
772
    i32 err_align = err == t->types.type_void ? TAG_SIZE : err->align;
773
    i32 alignment = max(max(payload_align, err_align), TAG_SIZE);
774
775
    i32  payload_size = payload == t->types.type_void ? 0 : payload->size;
776
    i32  err_size     = err == t->types.type_void ? 0 : err->size;
777
    i32  val_offset   = align(TAG_SIZE, alignment);
778
    i32  value_size   = align(max(payload_size, err_size), alignment);
779
    i32  size         = val_offset + value_size;
780
    bool changed      = false;
781
782
    changed |= update_i32(&typ->size, size);
783
    changed |= update_i32(&typ->align, alignment);
784
785
    return changed;
786
}
787
788
static bool update_enum_layout(type_t *typ) {
789
    i32  new_align   = typ->info.uni.base ? typ->info.uni.base->align : 0;
790
    bool has_payload = false;
791
    i32  variantsize = 0;
792
    bool changed     = false;
793
794
    if (new_align <= 0)
795
        new_align = TAG_SIZE;
796
797
    for (usize i = 0; i < typ->info.uni.nvariants; i++) {
798
        symbol_t *variant_sym = typ->info.uni.variants[i];
799
        if (!variant_sym || !variant_sym->node)
800
            continue;
801
802
        node_t *variant_node = variant_sym->node;
803
        type_t *payload      = variant_node->type;
804
805
        if (!payload || payload->cls == TYPE_VOID)
806
            continue;
807
808
        has_payload = true;
809
        if (payload->size > variantsize)
810
            variantsize = payload->size;
811
        if (payload->align > new_align)
812
            new_align = payload->align;
813
    }
814
815
    if (new_align <= 0)
816
        new_align = TAG_SIZE;
817
818
    i32 size = typ->info.uni.base ? typ->info.uni.base->size : TAG_SIZE;
819
    if (has_payload) {
820
        i32 val_offset = align(TAG_SIZE, new_align);
821
        i32 aligned_payload =
822
            variantsize > 0 ? align(variantsize, new_align) : 0;
823
        size = val_offset + aligned_payload;
824
    }
825
    changed |= update_bool(&typ->info.uni.has_payload, has_payload);
826
    changed |= update_i32(&typ->info.uni.variantsize, variantsize);
827
    changed |= update_i32(&typ->align, new_align);
828
    changed |= update_i32(&typ->size, size);
829
830
    return changed;
831
}
832
833
static bool update_type_layout(resolve_t *t, type_t *typ) {
834
    switch (typ->cls) {
835
    case TYPE_ARRAY:
836
        return update_array_layout(typ);
837
    case TYPE_UNION:
838
        return update_enum_layout(typ);
839
    case TYPE_RECORD:
840
        return update_record_layout(typ);
841
    case TYPE_OPT:
842
        return update_opt_layout(typ);
843
    case TYPE_RESULT:
844
        return update_result_layout(t, typ);
845
    default:
846
        return false;
847
    }
848
}
849
850
static void finalize_type_layout(resolve_t *t) {
851
    usize max_passes = t->types.nobjects ? t->types.nobjects : 1;
852
    for (usize pass = 0; pass < max_passes; pass++) {
853
        bool changed = false;
854
855
        for (usize i = 0; i < t->types.nobjects; i++) {
856
            type_t *typ = &t->types.objects[i];
857
            if (update_type_layout(t, typ))
858
                changed = true;
859
        }
860
        if (!changed)
861
            return;
862
    }
863
    bail("type layout failed to stabilize");
864
}
865
866
static bool declare_enum(resolve_t *t, node_t *n) {
867
    union_decl_t *decl = &n->val.union_decl;
868
869
    if (!n->sym) {
870
        if (!symbol_add(t, decl->name, n))
871
            return false;
872
        if (!n->sym)
873
            return false;
874
    }
875
    if (!n->type) {
876
        type_t *typ        = alloc_union_type(t, decl);
877
        n->sym->e.typ.info = n->type = typ;
878
    } else if (!n->sym->e.typ.info) {
879
        n->sym->e.typ.info = n->type;
880
    }
881
    return true;
882
}
883
884
static bool declare_record(resolve_t *t, node_t *n) {
885
    record_decl_t *decl = &n->val.record_decl;
886
887
    if (!n->sym) {
888
        if (!symbol_add(t, decl->name, n))
889
            return false;
890
        if (!n->sym)
891
            return false;
892
    }
893
    if (!n->type) {
894
        type_t *strct_typ  = alloc_record_type(t, decl);
895
        n->sym->e.typ.info = n->type = strct_typ;
896
    } else if (!n->sym->e.typ.info) {
897
        n->sym->e.typ.info = n->type;
898
    }
899
    return true;
900
}
901
902
static bool resolve_const_usize(resolve_t *t, node_t *expr, usize *value) {
903
    if (expr->cls == NODE_NUMBER) {
904
        *value = expr->val.number.value.u;
905
        return true;
906
    }
907
    symbol_t *sym = expr->sym;
908
909
    if (!sym && (expr->cls == NODE_IDENT || expr->cls == NODE_SCOPE)) {
910
        sym = resolve_name(t, expr, SYM_CONSTANT);
911
912
        if (!sym)
913
            return false;
914
    }
915
916
    if (!sym || sym->kind != SYM_CONSTANT || !sym->node ||
917
        sym->node->cls != NODE_CONST)
918
        return false;
919
920
    node_t *value_node = sym->node->val.constant.value;
921
    if (!value_node || value_node->cls != NODE_NUMBER)
922
        return false;
923
    *value = value_node->val.number.value.u;
924
925
    return true;
926
}
927
928
static bool resolve_record_literal_fields(
929
    resolve_t *t, node_t *lit, type_t *record_type
930
) {
931
    node_t **lit_fields =
932
        nodespan_ptrs(&t->module->parser, lit->val.record_lit.fields);
933
    for (usize i = 0; i < lit->val.record_lit.fields.len; i++) {
934
        node_t             *field_init = lit_fields[i];
935
        record_lit_field_t *init       = &field_init->val.record_lit_field;
936
937
        symbol_t *field_sym = record_field_lookup(record_type, init->name);
938
        if (!field_sym)
939
            return false;
940
941
        type_t *field_typ = field_sym->e.field.typ;
942
943
        if (!resolve_node(t, init->value, field_typ))
944
            return false;
945
946
        field_init->sym = field_sym;
947
    }
948
    return true;
949
}
950
951
static bool resolve_record_literal_types(
952
    resolve_t *t,
953
    node_t    *type_node,
954
    type_t    *expected,
955
    type_t   **out_record,
956
    type_t   **out_result,
957
    symbol_t **out_variant
958
) {
959
    type_t   *record_type = NULL;
960
    type_t   *result_type = NULL;
961
    symbol_t *variant_sym = NULL;
962
963
    /* Explicit type annotation: either
964
     * `Type { ... }` or
965
     * `module::Type { ... }`, or
966
     * `Enum::Variant { ... }` */
967
    if (type_node) {
968
        switch (type_node->cls) {
969
        case NODE_SCOPE:
970
        case NODE_IDENT: {
971
            symbol_t *sym = resolve_name(t, type_node, SYM_ANY);
972
            if (!sym)
973
                return false;
974
975
            type_t *resolved = type_node->type;
976
            if (!resolved && sym->node)
977
                resolved = sym->node->type;
978
979
            if (type_node->cls == NODE_SCOPE && sym->kind == SYM_VARIANT &&
980
                sym->node->cls == NODE_UNION_VARIANT) {
981
                if (!resolved || resolved->cls != TYPE_UNION)
982
                    return false;
983
984
                type_t *variant_type = sym->node->type;
985
                if (!variant_type || variant_type->cls != TYPE_RECORD)
986
                    return false;
987
988
                record_type = variant_type;
989
                result_type = resolved;
990
                variant_sym = sym;
991
992
                break;
993
            }
994
995
            if (!resolved) {
996
                resolved = resolve_type(t, type_node);
997
                if (!resolved)
998
                    return false;
999
            }
1000
1001
            if (resolved->cls != TYPE_RECORD)
1002
                return false;
1003
1004
            record_type = resolved;
1005
            result_type = record_type;
1006
1007
            break;
1008
        }
1009
        case NODE_RECORD_TYPE: {
1010
            type_t *resolved = resolve_type(t, type_node);
1011
            if (!resolved)
1012
                return false;
1013
1014
            if (resolved->cls != TYPE_RECORD)
1015
                return false;
1016
1017
            record_type = resolved;
1018
            result_type = record_type;
1019
1020
            break;
1021
        }
1022
        default:
1023
            return false;
1024
        }
1025
    } else {
1026
        /* No explicit type: fall back to the expected type from context */
1027
        if (!expected)
1028
            return false;
1029
1030
        if (expected->cls == TYPE_OPT)
1031
            expected = expected->info.opt.elem;
1032
1033
        if (expected->cls != TYPE_RECORD)
1034
            return false;
1035
1036
        record_type = expected;
1037
        result_type = record_type;
1038
    }
1039
1040
    *out_record = record_type;
1041
    *out_result = result_type;
1042
    if (out_variant)
1043
        *out_variant = variant_sym;
1044
1045
    return true;
1046
}
1047
1048
static bool anonymous_record_equals(
1049
    resolve_t *t, type_t *typ, record_type_t *stype
1050
) {
1051
    if (typ->info.srt.nfields != stype->fields.len)
1052
        return false;
1053
1054
    node_t **fields = nodespan_ptrs(&t->module->parser, stype->fields);
1055
    for (usize i = 0; i < stype->fields.len; i++) {
1056
        node_t   *field_node = fields[i];
1057
        symbol_t *field_sym  = typ->info.srt.fields[i];
1058
1059
        if (field_node->type != field_sym->e.field.typ)
1060
            return false;
1061
1062
        if (!ident_eq(
1063
                field_node->val.var.ident, field_sym->name, field_sym->length
1064
            ))
1065
            return false;
1066
    }
1067
    return true;
1068
}
1069
1070
static type_t *anonymous_record_lookup(resolve_t *t, record_type_t *stype) {
1071
    for (usize i = 0; i < t->types.nobjects; i++) {
1072
        type_t *typ = &t->types.objects[i];
1073
1074
        if (typ->cls != TYPE_RECORD || !typ->info.srt.anonymous)
1075
            continue;
1076
        if (anonymous_record_equals(t, typ, stype))
1077
            return typ;
1078
    }
1079
    return NULL;
1080
}
1081
1082
static bool union_variant_add(
1083
    resolve_t *t, type_t *typ, node_t *v, usize idx, i32 *iota
1084
) {
1085
    (void)idx;
1086
    union_variant_t *variant = &v->val.union_variant;
1087
    const char      *name    = variant->name->val.ident.name;
1088
    const usize      length  = variant->name->val.ident.length;
1089
1090
    symbol_t *sym = alloc_symbol((symbol_t){
1091
        .name   = name,
1092
        .length = length,
1093
        .node   = v,
1094
        .kind   = SYM_VARIANT,
1095
    });
1096
1097
    if (variant->type) {
1098
        type_t *payload = resolve_type(t, variant->type);
1099
        if (!payload)
1100
            return false;
1101
1102
        v->type        = payload;
1103
        variant->value = *iota;
1104
        *iota          = variant->value + 1;
1105
    } else {
1106
        v->type = t->types.type_void;
1107
1108
        if (variant->value_expr) {
1109
            if (!resolve_number(t, variant->value_expr, t->types.type_i32))
1110
                return false;
1111
1112
            variant->value = variant->value_expr->val.number.value.i;
1113
            *iota          = variant->value + 1;
1114
        } else {
1115
            variant->value = *iota;
1116
            *iota          = variant->value + 1;
1117
        }
1118
    }
1119
    assert(typ->info.uni.nvariants < MAX_UNION_VARIANTS);
1120
    typ->info.uni.variants[typ->info.uni.nvariants++] = sym;
1121
    update_enum_layout(typ);
1122
1123
    return true;
1124
}
1125
1126
/* Allocate a type. */
1127
static type_t *alloc_type(
1128
    resolve_t  *t,
1129
    typeclass_t kind,
1130
    const char *name,
1131
    usize       namelen,
1132
    i32         size,
1133
    i32         align
1134
) {
1135
    if (t->types.nobjects >= MAX_TYPES) {
1136
        bail("type overflow: too many types");
1137
        return NULL;
1138
    }
1139
    type_t *slot = &t->types.objects[t->types.nobjects++];
1140
1141
    slot->name      = name;
1142
    slot->namelen   = namelen;
1143
    slot->cls       = kind;
1144
    slot->size      = size;
1145
    slot->align     = align;
1146
    slot->ptr       = NULL;
1147
    slot->ptr_mut   = NULL;
1148
    slot->slice     = NULL;
1149
    slot->slice_mut = NULL;
1150
1151
    /* For non-pointer types, allocate a pointer type and
1152
     * link it to the target type. */
1153
    if (kind != TYPE_PTR) {
1154
        slot->ptr = alloc_ptr_type(t, slot, false);
1155
    }
1156
    return slot;
1157
}
1158
1159
/* Allocate a slice type.
1160
 * `base` can be `NULL` for things like `*[u8]` from string literals. */
1161
static type_t *alloc_slice_type(
1162
    resolve_t *t, type_t *elem, type_t *base, bool mut
1163
) {
1164
    if (base) {
1165
        if (!mut && base->slice) {
1166
            return base->slice;
1167
        }
1168
        if (mut && base->slice_mut) {
1169
            return base->slice_mut;
1170
        }
1171
    } else {
1172
        if (!mut && elem->slice) {
1173
            return elem->slice;
1174
        }
1175
        if (mut && elem->slice_mut) {
1176
            return elem->slice_mut;
1177
        }
1178
    }
1179
1180
    char buf[MAX_STRING_LEN] = { 0 };
1181
    if (mut) {
1182
        snprintf(
1183
            buf, MAX_STRING_LEN, "*mut [%.*s]", (int)elem->namelen, elem->name
1184
        );
1185
    } else {
1186
        snprintf(
1187
            buf, MAX_STRING_LEN, "*[%.*s]", (int)elem->namelen, elem->name
1188
        );
1189
    }
1190
    const char *name = strings_alloc(buf);
1191
1192
    type_t *typ =
1193
        alloc_type(t, TYPE_SLICE, name, strlen(name), WORD_SIZE * 2, WORD_SIZE);
1194
    typ->info.slc.elem = elem;
1195
    typ->info.slc.base = base;
1196
    typ->info.slc.mut  = mut;
1197
1198
    if (base) {
1199
        if (!mut) {
1200
            base->slice = typ;
1201
        } else {
1202
            base->slice_mut = typ;
1203
        }
1204
    } else {
1205
        if (!mut) {
1206
            elem->slice = typ;
1207
        } else {
1208
            elem->slice_mut = typ;
1209
        }
1210
    }
1211
    return typ;
1212
}
1213
1214
/* Allocate a pointer type. */
1215
static type_t *alloc_ptr_type(resolve_t *t, type_t *base, bool mut) {
1216
    if (!mut && base->ptr) {
1217
        return base->ptr;
1218
    }
1219
    if (mut && base->ptr_mut) {
1220
        return base->ptr_mut;
1221
    }
1222
1223
    char buf[MAX_STRING_LEN] = { 0 };
1224
    if (mut) {
1225
        snprintf(
1226
            buf, MAX_STRING_LEN, "*mut %.*s", (int)base->namelen, base->name
1227
        );
1228
    } else {
1229
        snprintf(buf, MAX_STRING_LEN, "*%.*s", (int)base->namelen, base->name);
1230
    }
1231
    const char *name = strings_alloc(buf);
1232
1233
    type_t *typ =
1234
        alloc_type(t, TYPE_PTR, name, strlen(name), WORD_SIZE, WORD_SIZE);
1235
    typ->info.ptr.target = base;
1236
    typ->info.ptr.mut    = mut;
1237
1238
    if (!mut) {
1239
        base->ptr = typ;
1240
    } else {
1241
        base->ptr_mut = typ;
1242
    }
1243
    return typ;
1244
}
1245
1246
/* Allocate an array type. */
1247
static type_t *alloc_array_type(resolve_t *t, type_t *elem, usize length) {
1248
    /* First check if we already have this array type */
1249
    for (usize i = 0; i < t->types.nobjects; i++) {
1250
        type_t *typ = &t->types.objects[i];
1251
1252
        if (typ->cls == TYPE_ARRAY && typ->info.ary.elem == elem &&
1253
            typ->info.ary.length == length) {
1254
            return typ;
1255
        }
1256
    }
1257
    char buf[MAX_STRING_LEN] = { 0 };
1258
    snprintf(
1259
        buf,
1260
        MAX_STRING_LEN,
1261
        "[%.*s; %ld]",
1262
        (int)elem->namelen,
1263
        elem->name,
1264
        length
1265
    );
1266
    const char *name = strings_alloc(buf);
1267
1268
    type_t *array_type = alloc_type(t, TYPE_ARRAY, name, strlen(name), 0, 0);
1269
1270
    array_type->info.ary.elem   = elem;
1271
    array_type->info.ary.length = length;
1272
    update_array_layout(array_type);
1273
1274
    array_type->slice = alloc_slice_type(t, elem, array_type, false);
1275
    array_type->ptr   = alloc_ptr_type(t, array_type, false);
1276
1277
    return array_type;
1278
}
1279
1280
static type_t *alloc_union_type(resolve_t *t, union_decl_t *uni) {
1281
    type_t *typ = alloc_type(
1282
        t,
1283
        TYPE_UNION,
1284
        uni->name->val.ident.name,
1285
        uni->name->val.ident.length,
1286
        WORD_SIZE,
1287
        WORD_SIZE
1288
    );
1289
    /* TODO: use correct type based on union variants.
1290
     * For now, default all enums to an `i32` base type. */
1291
    typ->info.uni.decl     = uni;
1292
    typ->info.uni.base     = t->types.type_i32;
1293
    typ->info.uni.variants = types_alloc_sympool(&t->types, MAX_UNION_VARIANTS);
1294
    typ->info.uni.nvariants   = 0;
1295
    typ->info.uni.variantsize = 0;
1296
    typ->info.uni.has_payload = false;
1297
1298
    return typ;
1299
}
1300
1301
static type_t *alloc_fn_type(
1302
    resolve_t *t, node_t *n, type_t *ret, usize nparams
1303
) {
1304
    type_t *type = alloc_type(
1305
        t,
1306
        TYPE_FN,
1307
        n->sym ? n->sym->name : "#fn",
1308
        n->sym ? n->sym->length : 3,
1309
        DEFAULT_SIZE,
1310
        DEFAULT_ALIGN
1311
    );
1312
    type->info.fun.ret     = ret ? ret : t->types.type_void;
1313
    type->info.fun.params  = types_alloc_typepool(&t->types, MAX_FN_PARAMS);
1314
    type->info.fun.throws  = types_alloc_typepool(&t->types, MAX_FN_THROWS);
1315
    type->info.fun.nparams = nparams;
1316
    type->info.fun.nthrows = 0;
1317
1318
    return (n->type = type);
1319
}
1320
1321
static type_t *alloc_record_type(resolve_t *t, record_decl_t *srt) {
1322
    type_t *typ = alloc_type(
1323
        t,
1324
        TYPE_RECORD,
1325
        srt->name->val.ident.name,
1326
        srt->name->val.ident.length,
1327
        0, /* Size will be updated when we add fields */
1328
        DEFAULT_ALIGN
1329
    );
1330
    typ->info.srt.fields  = types_alloc_sympool(&t->types, MAX_RECORD_FIELDS);
1331
    typ->info.srt.nfields = 0;
1332
    typ->info.srt.packedsize = 0;
1333
    typ->info.srt.anonymous  = false;
1334
    typ->info.srt.tuple      = srt->tuple;
1335
1336
    return typ;
1337
}
1338
1339
static type_t *alloc_anonymous_record_type(resolve_t *t) {
1340
    char buf[32];
1341
    snprintf(buf, sizeof(buf), "record#%u", (unsigned)t->recordid++);
1342
    const char *name = strings_alloc(buf);
1343
1344
    type_t *typ = alloc_type(
1345
        t,
1346
        TYPE_RECORD,
1347
        name,
1348
        strlen(name),
1349
        0, /* Size will be updated when we add fields */
1350
        DEFAULT_ALIGN
1351
    );
1352
    typ->info.srt.fields  = types_alloc_sympool(&t->types, MAX_RECORD_FIELDS);
1353
    typ->info.srt.nfields = 0;
1354
    typ->info.srt.packedsize = 0;
1355
    typ->info.srt.anonymous  = true;
1356
1357
    return typ;
1358
}
1359
1360
/* Allocate an optional type. */
1361
static type_t *alloc_opt_type(resolve_t *t, type_t *elem) {
1362
    /* First check if we already have this optional type */
1363
    for (usize i = 0; i < t->types.nobjects; i++) {
1364
        type_t *typ = &t->types.objects[i];
1365
1366
        if (typ->cls == TYPE_OPT && typ->info.opt.elem == elem) {
1367
            return typ;
1368
        }
1369
    }
1370
    char buf[MAX_STRING_LEN] = { 0 };
1371
    snprintf(buf, MAX_STRING_LEN, "?%.*s", (int)elem->namelen, elem->name);
1372
    const char *name = strings_alloc(buf);
1373
1374
    type_t *opt_type = alloc_type(t, TYPE_OPT, name, strlen(name), 0, 0);
1375
1376
    opt_type->info.opt.elem = elem;
1377
    update_opt_layout(opt_type);
1378
1379
    return opt_type;
1380
}
1381
1382
static type_t *alloc_result_type(resolve_t *t, type_t *payload, type_t *err) {
1383
    /* Find existing result type that matches this one. */
1384
    for (usize i = 0; i < t->types.nobjects; i++) {
1385
        type_t *typ = &t->types.objects[i];
1386
1387
        if (typ->cls == TYPE_RESULT && typ->info.res.payload == payload &&
1388
            typ->info.res.err == err) {
1389
            return typ;
1390
        }
1391
    }
1392
1393
    char buf[MAX_STRING_LEN] = { 0 };
1394
    snprintf(
1395
        buf,
1396
        MAX_STRING_LEN,
1397
        "result<%.*s, %.*s>",
1398
        (int)err->namelen,
1399
        err->name,
1400
        (int)payload->namelen,
1401
        payload->name
1402
    );
1403
    const char *name = strings_alloc(buf);
1404
1405
    type_t *result_typ = alloc_type(t, TYPE_RESULT, name, strlen(name), 0, 0);
1406
1407
    result_typ->info.res.err     = err;
1408
    result_typ->info.res.payload = payload;
1409
    update_result_layout(t, result_typ);
1410
1411
    return result_typ;
1412
}
1413
1414
static bool resolve_fn_throws(
1415
    resolve_t *t, type_t *fn_type, nodespan_t throws, type_t *ret_payload
1416
) {
1417
    usize nthrows = throws.len;
1418
    if (nthrows == 0) {
1419
        fn_type->info.fun.ret = ret_payload;
1420
        return true;
1421
    }
1422
    if (nthrows > MAX_FN_THROWS)
1423
        bail("too many throw types");
1424
1425
    node_t **throw_nodes = nodespan_ptrs(&t->module->parser, throws);
1426
    for (usize i = 0; i < nthrows; i++) {
1427
        node_t *thrown     = throw_nodes[i];
1428
        type_t *thrown_typ = resolve_type(t, thrown);
1429
1430
        if (!thrown_typ)
1431
            return false;
1432
        fn_type->info.fun.throws[i] = thrown_typ;
1433
        fn_type->info.fun.nthrows++;
1434
    }
1435
    type_t *thrown_typ = fn_type->info.fun.throws[0];
1436
    type_t *result_typ = alloc_result_type(t, ret_payload, thrown_typ);
1437
1438
    fn_type->info.fun.ret = result_typ;
1439
1440
    return true;
1441
}
1442
1443
static bool union_variant_validate_args(
1444
    resolve_t *t, node_t *call, symbol_t *variant_sym, node_t **out_arg_expr
1445
) {
1446
    (void)t;
1447
    type_t *variant_type = variant_sym->node->type;
1448
    usize   nargs        = call->val.call.args.len;
1449
1450
    if (variant_type->cls == TYPE_VOID) {
1451
        if (out_arg_expr)
1452
            *out_arg_expr = NULL;
1453
        return nargs == 0;
1454
    }
1455
    if (nargs != 1)
1456
        return false;
1457
1458
    if (out_arg_expr)
1459
        *out_arg_expr =
1460
            nodespan_ptrs(&t->module->parser, call->val.call.args)[0]
1461
                ->val.call_arg.expr;
1462
1463
    return true;
1464
}
1465
1466
/* Check a union constructor call like `Expr::number(42)`. */
1467
static type_t *resolve_enum_constructor(
1468
    resolve_t *t, node_t *call, type_t *union_type, symbol_t *variant_sym
1469
) {
1470
    type_t *variant_type = variant_sym->node->type;
1471
    node_t *arg_expr     = NULL;
1472
1473
    if (!union_variant_validate_args(t, call, variant_sym, &arg_expr))
1474
        return NULL;
1475
1476
    if (arg_expr) {
1477
        if (!resolve_node(t, arg_expr, variant_type))
1478
            return NULL;
1479
    }
1480
1481
    call->sym  = variant_sym;
1482
    call->type = union_type;
1483
1484
    return union_type;
1485
}
1486
1487
/* Check tuple record constructor call */
1488
static type_t *resolve_tuple_record_constructor(
1489
    resolve_t *t, node_t *call, type_t *record_type
1490
) {
1491
    usize nfields = record_type->info.srt.nfields;
1492
    usize nargs   = call->val.call.args.len;
1493
1494
    if (nargs != nfields)
1495
        return NULL;
1496
1497
    /* Type check each argument against the corresponding field type. */
1498
    for (usize i = 0; i < nargs; i++) {
1499
        node_t *arg = nodespan_ptrs(&t->module->parser, call->val.call.args)[i];
1500
        symbol_t *field_sym = record_type->info.srt.fields[i];
1501
        type_t   *field_typ = field_sym->e.field.typ;
1502
1503
        if (!resolve_node(t, arg, field_typ))
1504
            return NULL;
1505
    }
1506
    call->sym = NULL;
1507
1508
    return (call->type = record_type);
1509
}
1510
1511
static bool symbol_add(resolve_t *t, node_t *ident, node_t *n) {
1512
    if (ident->cls == NODE_PLACEHOLDER)
1513
        return true;
1514
1515
    return symtab_add_ident(t->scope, ident, n);
1516
}
1517
1518
static symbol_t *resolve_name(resolve_t *t, node_t *n, symkind_t kind) {
1519
    n->sym = NULL;
1520
1521
    if (n->cls == NODE_SCOPE) {
1522
        if (!resolve_scope(t, n) || !n->sym)
1523
            return NULL;
1524
        if (kind != SYM_ANY && n->sym->kind != kind)
1525
            return NULL;
1526
        return n->sym;
1527
    }
1528
1529
    symbol_t *sym =
1530
        symtab_lookup(t->scope, n->val.ident.name, n->val.ident.length, kind);
1531
1532
    if (!sym && kind == SYM_ANY) {
1533
        sym = symtab_lookup(
1534
            t->scope, n->val.ident.name, n->val.ident.length, SYM_ANY
1535
        );
1536
    }
1537
1538
    if (sym) {
1539
        n->sym = sym;
1540
1541
        if (sym->node && sym->node->type && !n->type)
1542
            n->type = sym->node->type;
1543
1544
        return sym;
1545
    }
1546
    return NULL;
1547
}
1548
1549
/* Resolve a type by looking up its definition if necessary, eg. for custom
1550
 * types defined in the source code. */
1551
static type_t *resolve_type(resolve_t *t, node_t *n) {
1552
    if (n->type)
1553
        return n->type;
1554
1555
    switch (n->cls) {
1556
    case NODE_TYPE:
1557
        switch (n->val.type.tclass) {
1558
        case TYPE_U8:
1559
            return (n->type = t->types.type_u8);
1560
        case TYPE_U16:
1561
            return (n->type = t->types.type_u16);
1562
        case TYPE_U32:
1563
            return (n->type = t->types.type_u32);
1564
        case TYPE_I8:
1565
            return (n->type = t->types.type_i8);
1566
        case TYPE_I16:
1567
            return (n->type = t->types.type_i16);
1568
        case TYPE_I32:
1569
            return (n->type = t->types.type_i32);
1570
        case TYPE_BOOL:
1571
            return (n->type = t->types.type_bool);
1572
        case TYPE_VOID:
1573
            return (n->type = t->types.type_void);
1574
        case TYPE_OPAQUE:
1575
            return (n->type = t->types.type_opaque);
1576
        case TYPE_FN: {
1577
            /* Resolve return type */
1578
            type_t *ret_type = n->val.type.info.fn.ret
1579
                                   ? resolve_type(t, n->val.type.info.fn.ret)
1580
                                   : t->types.type_void;
1581
            if (!ret_type)
1582
                return NULL;
1583
1584
            n->type =
1585
                alloc_fn_type(t, n, ret_type, n->val.type.info.fn.params.len);
1586
1587
            /* Resolve parameter types */
1588
            for (usize i = 0; i < n->val.type.info.fn.params.len; i++) {
1589
                type_t *param_typ = resolve_type(
1590
                    t,
1591
                    nodespan_ptrs(
1592
                        &t->module->parser, n->val.type.info.fn.params
1593
                    )[i]
1594
                );
1595
                if (!param_typ)
1596
                    return NULL;
1597
1598
                n->type->info.fun.params[i] = param_typ;
1599
            }
1600
            if (!resolve_fn_throws(
1601
                    t, n->type, n->val.type.info.fn.throws, ret_type
1602
                ))
1603
                return NULL;
1604
1605
            return n->type;
1606
        }
1607
        case TYPE_ARRAY: {
1608
            type_t *elem_typ = resolve_type(t, n->val.type.elem_type);
1609
1610
            if (!elem_typ)
1611
                return NULL;
1612
1613
            node_t *len_node = n->val.type.info.array.length;
1614
            if (!resolve_node(t, len_node, t->types.type_u32))
1615
                return NULL;
1616
1617
            usize len = 0;
1618
            if (!resolve_const_usize(t, len_node, &len))
1619
                return NULL;
1620
            return (n->type = alloc_array_type(t, elem_typ, len));
1621
        }
1622
        case TYPE_SLICE: {
1623
            type_t *elem_typ = resolve_type(t, n->val.type.elem_type);
1624
            if (!elem_typ)
1625
                return NULL;
1626
1627
            bool mut = n->val.type.info.slice.mut;
1628
            return (n->type = alloc_slice_type(t, elem_typ, NULL, mut));
1629
        }
1630
        case TYPE_UNION:
1631
        case TYPE_RESULT:
1632
        case TYPE_RECORD:
1633
            abort();
1634
        case TYPE_PTR: {
1635
            type_t *elem_typ = resolve_type(t, n->val.type.elem_type);
1636
1637
            if (!elem_typ)
1638
                return NULL;
1639
            bool mut = n->val.type.info.ptr.mut;
1640
1641
            return (n->type = alloc_ptr_type(t, elem_typ, mut));
1642
        }
1643
        case TYPE_OPT: {
1644
            type_t *elem_typ = resolve_type(t, n->val.type.elem_type);
1645
1646
            if (!elem_typ)
1647
                return NULL;
1648
1649
            return (n->type = alloc_opt_type(t, elem_typ));
1650
        }
1651
        default:
1652
            break;
1653
        }
1654
        break;
1655
    case NODE_RECORD_TYPE: {
1656
        record_type_t *stype = &n->val.record_type;
1657
        node_t **fields      = nodespan_ptrs(&t->module->parser, stype->fields);
1658
1659
        for (usize i = 0; i < stype->fields.len; i++) {
1660
            node_t *field = fields[i];
1661
            type_t *typ   = resolve_type(t, field->val.var.type);
1662
1663
            if (!typ)
1664
                return NULL;
1665
1666
            field->type = typ;
1667
        }
1668
        type_t *existing = anonymous_record_lookup(t, stype);
1669
        if (existing)
1670
            return (n->type = existing);
1671
1672
        type_t *typ = alloc_anonymous_record_type(t);
1673
        for (usize i = 0; i < stype->fields.len; i++) {
1674
            node_t *field = fields[i];
1675
1676
            if (!record_field_add(
1677
                    t, typ, field, field->val.var.ident, field->type
1678
                ))
1679
                return NULL;
1680
        }
1681
1682
        return (n->type = typ);
1683
    }
1684
    case NODE_SCOPE:
1685
    case NODE_IDENT: {
1686
        symbol_t *sym = resolve_name(t, n, SYM_TYPE);
1687
1688
        if (!sym)
1689
            return NULL;
1690
1691
        if (!sym->node || !sym->node->type)
1692
            bail("type symbol missing type information");
1693
1694
        return (n->type = sym->node->type);
1695
    }
1696
    default:
1697
        bail("node is not a kind of type, class is %d", n->cls);
1698
    }
1699
    return NULL;
1700
}
1701
1702
static type_t *resolve_number(resolve_t *t, node_t *n, type_t *expected) {
1703
    if (!expected)
1704
        expected = t->types.type_i32;
1705
    if (expected->cls == TYPE_OPT)
1706
        expected = expected->info.opt.elem;
1707
1708
    if (!expected || !type_is_numeric(expected->cls))
1709
        return NULL;
1710
1711
    type_t     *result_type = expected;
1712
    typeclass_t tclass      = expected->cls;
1713
    imm_t       value       = { 0 };
1714
1715
    /* Create a null-terminated copy of the text for strto* functions. */
1716
    static char text[16] = { 0 };
1717
    memcpy(text, n->val.number.text, n->val.number.text_len);
1718
    text[n->val.number.text_len] = '\0';
1719
1720
    /* Manual binary literal parsing since `strtol` doesn't support 0b in this
1721
     * environment. */
1722
    bool is_binary = (text[0] == '0' && (text[1] == 'b' || text[1] == 'B'));
1723
    u32  binval    = 0;
1724
1725
    if (is_binary) {
1726
        for (usize i = 2; text[i]; i++) {
1727
            binval = (binval << 1) + (text[i] - '0');
1728
        }
1729
    }
1730
1731
    /* Parse the number based on the type */
1732
    switch (tclass) {
1733
    case TYPE_I8:
1734
    case TYPE_I16:
1735
    case TYPE_I32: {
1736
        i32 val;
1737
        if (is_binary) {
1738
            val = (i32)binval;
1739
        } else {
1740
            val = strtol(text, NULL, 0);
1741
        }
1742
        value.i = val;
1743
        break;
1744
    }
1745
    case TYPE_U8:
1746
    case TYPE_U16:
1747
    case TYPE_U32: {
1748
        u32 val;
1749
        if (is_binary) {
1750
            val = binval;
1751
        } else {
1752
            val = strtoul(text, NULL, 0);
1753
        }
1754
        value.u = val;
1755
        break;
1756
    }
1757
    default:
1758
        break;
1759
    }
1760
    n->val.number.value = value;
1761
1762
    return (n->type = result_type);
1763
}
1764
1765
static type_t *resolve_builtin(resolve_t *t, node_t *n, type_t *expected) {
1766
    (void)expected;
1767
1768
    builtin_kind_t kind = n->val.builtin.kind;
1769
    node_t **args = nodespan_ptrs(&t->module->parser, n->val.builtin.args);
1770
    type_t  *typ;
1771
1772
    /* @sliceOf is handled separately since it takes two runtime arguments */
1773
    if (kind == BUILTIN_SLICE_OF) {
1774
        /* Check first argument (pointer) */
1775
        type_t *ptr_type = resolve_node(t, args[0], NULL);
1776
        if (!ptr_type)
1777
            return NULL;
1778
1779
        /* Check second argument (length) */
1780
        type_t *len_type = resolve_node(t, args[1], t->types.type_u32);
1781
        if (!len_type)
1782
            return NULL;
1783
1784
        /* Result is a slice of the pointer's element type */
1785
        type_t *elem_type = ptr_type->info.ptr.target;
1786
        bool    mut       = ptr_type->info.ptr.mut;
1787
1788
        return (n->type = alloc_slice_type(t, elem_type, NULL, mut));
1789
    }
1790
1791
    node_t *expr = args[0];
1792
    switch (expr->cls) {
1793
    case NODE_TYPE:
1794
    case NODE_RECORD_TYPE:
1795
        typ = resolve_type(t, expr);
1796
        break;
1797
    default:
1798
        typ = resolve_node(t, expr, NULL);
1799
        break;
1800
    }
1801
    if (!typ)
1802
        return NULL;
1803
1804
    u32 value = 0;
1805
1806
    switch (kind) {
1807
    case BUILTIN_SIZE_OF:
1808
        value = (u32)typ->size;
1809
        break;
1810
    case BUILTIN_ALIGN_OF:
1811
        value = (u32)typ->align;
1812
        if (expr->sym && expr->sym->kind == SYM_VARIABLE &&
1813
            expr->sym->e.var.align > 0) {
1814
            value = (u32)expr->sym->e.var.align;
1815
        }
1816
        break;
1817
    case BUILTIN_SLICE_OF:
1818
        /* Already handled above */
1819
        break;
1820
    }
1821
    n->cls = NODE_NUMBER;
1822
1823
    n->val.number.text     = NULL;
1824
    n->val.number.text_len = 0;
1825
    n->val.number.value.u  = value;
1826
1827
    return (n->type = t->types.type_u32);
1828
}
1829
1830
/* Bind a pattern variable to a field type. Handles identifiers and
1831
 * placeholders. If is_ref_match is true, the binding type is wrapped
1832
 * in a pointer type. */
1833
static bool bind_pattern_var(
1834
    resolve_t *t,
1835
    node_t    *binding,
1836
    type_t    *field_typ,
1837
    bool       is_ref_match,
1838
    bool       ref_mut
1839
) {
1840
    type_t *binding_type =
1841
        is_ref_match ? alloc_ptr_type(t, field_typ, ref_mut) : field_typ;
1842
    if (binding->cls == NODE_IDENT) {
1843
        binding->type = binding_type;
1844
        if (!symbol_add(t, binding, binding))
1845
            return false;
1846
        binding->sym->e.var.typ   = binding_type;
1847
        binding->sym->e.var.align = binding_type->align;
1848
        binding->sym->scope       = t->scope;
1849
    }
1850
    return true;
1851
}
1852
1853
/* Bind pattern variables to record fields. Works for both tuple-style S(x, y)
1854
 * and labeled T { x, y } patterns. Returns false on error.
1855
 * If is_ref_match is true, bindings are pointer types. */
1856
static bool resolve_record_pattern_bindings(
1857
    resolve_t *t,
1858
    node_t    *pattern,
1859
    type_t    *rec_type,
1860
    bool       is_ref_match,
1861
    bool       ref_mut
1862
) {
1863
    if (pattern->cls == NODE_CALL) {
1864
        usize nargs = pattern->val.call.args.len;
1865
        for (usize i = 0; i < nargs; i++) {
1866
            node_t *arg_node =
1867
                nodespan_ptrs(&t->module->parser, pattern->val.call.args)[i];
1868
            node_t   *arg       = (arg_node->cls == NODE_CALL_ARG)
1869
                                      ? arg_node->val.call_arg.expr
1870
                                      : arg_node;
1871
            symbol_t *field_sym = rec_type->info.srt.fields[i];
1872
1873
            if (!bind_pattern_var(
1874
                    t, arg, field_sym->e.field.typ, is_ref_match, ref_mut
1875
                ))
1876
                return false;
1877
            arg_node->sym = field_sym;
1878
        }
1879
    } else if (pattern->cls == NODE_RECORD_LIT) {
1880
        node_t **fields =
1881
            nodespan_ptrs(&t->module->parser, pattern->val.record_lit.fields);
1882
1883
        for (usize f = 0; f < pattern->val.record_lit.fields.len; f++) {
1884
            node_t *field_node  = fields[f];
1885
            node_t *binding     = field_node->val.record_lit_field.value;
1886
            node_t *name_node   = field_node->val.record_lit_field.name;
1887
            node_t *lookup_node = name_node ? name_node : binding;
1888
1889
            symbol_t *field_sym = record_field_lookup(rec_type, lookup_node);
1890
            if (!field_sym)
1891
                return false;
1892
1893
            field_node->sym = field_sym;
1894
1895
            if (!bind_pattern_var(
1896
                    t, binding, field_sym->e.field.typ, is_ref_match, ref_mut
1897
                ))
1898
                return false;
1899
        }
1900
    }
1901
    return true;
1902
}
1903
1904
/* Check a match statement case. */
1905
static type_t *resolve_match_case(resolve_t *t, node_t *n, type_t *match_typ) {
1906
    /* If this is the default (else) case, there are no patterns to check. */
1907
    if (!n->val.match_case.patterns.len) {
1908
        if (!resolve_node(t, n->val.match_case.body, NULL))
1909
            return NULL;
1910
1911
        return (n->type = t->types.type_void);
1912
    }
1913
    scope_t *prev = t->scope;
1914
1915
    /* Check if matching on a pointer to a union - bindings will be pointers */
1916
    bool    is_ref_match = false;
1917
    bool    ref_mut      = false;
1918
    type_t *union_typ    = match_typ;
1919
1920
    if (match_typ->cls == TYPE_PTR &&
1921
        type_is_union_with_payload(match_typ->info.ptr.target)) {
1922
        is_ref_match = true;
1923
        ref_mut      = match_typ->info.ptr.mut;
1924
        union_typ    = match_typ->info.ptr.target;
1925
    }
1926
1927
    if (type_is_union_with_payload((union_typ))) {
1928
        /* Create a shared scope for all patterns in this case */
1929
        scope_t *case_scope        = symtab_scope(t->scope, NULL);
1930
        t->scope                   = case_scope;
1931
        n->val.match_case.variable = NULL;
1932
1933
        /* Check each pattern in this case */
1934
        node_t **patterns =
1935
            nodespan_ptrs(&t->module->parser, n->val.match_case.patterns);
1936
        for (usize p = 0; p < n->val.match_case.patterns.len; p++) {
1937
            node_t *pattern   = patterns[p];
1938
            node_t *callee    = NULL;
1939
            bool    is_call   = (pattern->cls == NODE_CALL);
1940
            bool    is_reclit = (pattern->cls == NODE_RECORD_LIT);
1941
1942
            if (is_call) {
1943
                callee = pattern->val.call.callee;
1944
            } else if (is_reclit) {
1945
                callee = pattern->val.record_lit.type;
1946
                if (!callee)
1947
                    return NULL;
1948
            } else if (pattern->cls == NODE_SCOPE) {
1949
                callee = pattern;
1950
            } else {
1951
                return NULL;
1952
            }
1953
1954
            type_t *parent  = resolve_scope(t, callee);
1955
            node_t *variant = callee->val.access.rval;
1956
1957
            if (!parent)
1958
                return NULL;
1959
1960
            symbol_t *variant_sym = union_variant_lookup(union_typ, variant);
1961
            if (!variant_sym)
1962
                return NULL;
1963
            variant->sym = variant_sym;
1964
1965
            type_t *variant_type = variant_sym->node->type;
1966
1967
            if (variant_type->cls == TYPE_VOID) {
1968
                if (is_call) {
1969
                    if (!union_variant_validate_args(
1970
                            t, pattern, variant_sym, NULL
1971
                        ))
1972
                        return NULL;
1973
                }
1974
            } else if (is_reclit) {
1975
                if (variant_type->cls != TYPE_RECORD)
1976
                    return NULL;
1977
                if (!resolve_record_pattern_bindings(
1978
                        t, pattern, variant_type, is_ref_match, ref_mut
1979
                    ))
1980
                    return NULL;
1981
            } else {
1982
                node_t *arg_expr = NULL;
1983
1984
                if (!union_variant_validate_args(
1985
                        t, pattern, variant_sym, &arg_expr
1986
                    ))
1987
                    return NULL;
1988
1989
                node_t *variable           = arg_expr;
1990
                n->val.match_case.variable = variable;
1991
1992
                /* Create scope for the bound variable.
1993
                 * If matching on a pointer to union, binding is a pointer. */
1994
                type_t *binding_type =
1995
                    is_ref_match ? alloc_ptr_type(t, variant_type, ref_mut)
1996
                                 : variant_type;
1997
                variable->type = binding_type;
1998
1999
                if (variable->cls == NODE_IDENT) {
2000
                    /* Add the bound variable to the scope */
2001
                    if (!symbol_add(t, variable, variable))
2002
                        return NULL;
2003
2004
                    variable->sym->e.var.typ   = binding_type;
2005
                    variable->sym->e.var.align = binding_type->align;
2006
                    variable->sym->scope       = t->scope;
2007
                }
2008
            }
2009
            /* Set the pattern type to the union type. */
2010
            pattern->type = match_typ;
2011
        }
2012
    } else if (match_typ->cls == TYPE_RECORD) {
2013
        /* Record pattern matching: `match rec { case T(x) => ... }` */
2014
        scope_t *case_scope        = symtab_scope(t->scope, NULL);
2015
        t->scope                   = case_scope;
2016
        n->val.match_case.variable = NULL;
2017
2018
        node_t **patterns =
2019
            nodespan_ptrs(&t->module->parser, n->val.match_case.patterns);
2020
        for (usize p = 0; p < n->val.match_case.patterns.len; p++) {
2021
            node_t *pattern = patterns[p];
2022
            if (!resolve_record_pattern_bindings(
2023
                    t, pattern, match_typ, false, false
2024
                ))
2025
                return NULL;
2026
            pattern->type = match_typ;
2027
        }
2028
    } else {
2029
        bool pctx = t->ctx;
2030
        t->ctx    = TC_CTX_PATTERN;
2031
2032
        /* Check each pattern in this case */
2033
        node_t **patterns2 =
2034
            nodespan_ptrs(&t->module->parser, n->val.match_case.patterns);
2035
        for (usize p = 0; p < n->val.match_case.patterns.len; p++) {
2036
            node_t *pattern = patterns2[p];
2037
            if (!resolve_node(t, pattern, match_typ))
2038
                return NULL;
2039
        }
2040
        t->ctx = pctx;
2041
    }
2042
    if (n->val.match_case.guard) {
2043
        if (!resolve_node(t, n->val.match_case.guard, t->types.type_bool))
2044
            return NULL;
2045
    }
2046
    /* Check case body */
2047
    if (!resolve_node(t, n->val.match_case.body, NULL)) {
2048
        t->scope = prev;
2049
        return NULL;
2050
    }
2051
    t->scope = prev;
2052
2053
    return (n->type = t->types.type_void);
2054
}
2055
2056
static type_t *resolve_call_fn_ptr(resolve_t *t, symbol_t *sym, node_t *call) {
2057
    node_t *fn = sym->node;
2058
2059
    if (fn->type->cls != TYPE_FN)
2060
        return NULL;
2061
2062
    /* Check each argument type. */
2063
    for (usize i = 0; i < call->val.call.args.len; i++) {
2064
        node_t *arg_node =
2065
            nodespan_ptrs(&t->module->parser, call->val.call.args)[i];
2066
        type_t *param_typ = fn->type->info.fun.params[i];
2067
2068
        if (!resolve_node(t, arg_node->val.call_arg.expr, param_typ))
2069
            return NULL;
2070
    }
2071
    call->sym = sym;
2072
2073
    return (call->type = fn->type->info.fun.ret);
2074
}
2075
2076
static type_t *resolve_call_fn(resolve_t *t, symbol_t *sym, node_t *call) {
2077
    node_t *fn = sym->node;
2078
2079
    if (fn->type->cls != TYPE_FN)
2080
        return NULL;
2081
2082
    sym->e.fn.used = true;
2083
2084
    /* Check each argument type. */
2085
    for (usize i = 0; i < call->val.call.args.len; i++) {
2086
        node_t *arg_node =
2087
            nodespan_ptrs(&t->module->parser, call->val.call.args)[i];
2088
        node_t *param_node =
2089
            nodespan_ptrs(&sym->scope->mod->parser, fn->val.fn_decl.params)[i];
2090
        type_t *param_type = resolve_type(t, param_node->val.param.type);
2091
2092
        if (!resolve_node(t, arg_node->val.call_arg.expr, param_type))
2093
            return NULL;
2094
    }
2095
    call->sym = sym;
2096
2097
    return (call->type = fn->type->info.fun.ret);
2098
}
2099
2100
/* Helper function to build a module path from NODE_ACCESS nodes */
2101
static void module_scope_path(node_t *node, char *path_str) {
2102
    if (node->cls == NODE_IDENT) {
2103
        strncat(path_str, node->val.ident.name, node->val.ident.length);
2104
    } else if (node->cls == NODE_SUPER) {
2105
        strlcat(path_str, "super", MAX_PATH_LEN);
2106
    } else if (node->cls == NODE_SCOPE) {
2107
        module_scope_path(node->val.access.lval, path_str);
2108
        strlcat(path_str, "::", MAX_PATH_LEN);
2109
        module_scope_path(node->val.access.rval, path_str);
2110
    } else {
2111
    }
2112
}
2113
2114
static type_t *resolve_use(resolve_t *t, node_t *n) {
2115
    /* Extract the import path from the `use` node */
2116
    node_t *path_node = n->val.use_decl.path;
2117
    bool    wildcard  = n->val.use_decl.wildcard;
2118
2119
    /* Get the last component (symbol name) and parent scope */
2120
    node_t *last   = path_node;
2121
    node_t *parent = NULL;
2122
2123
    while (last && (last->cls == NODE_SCOPE)) {
2124
        parent = last->val.access.lval;
2125
        last   = last->val.access.rval;
2126
    }
2127
2128
    /* Try to find as a module first */
2129
    char filepath[MAX_PATH_LEN] = { 0 };
2130
    module_scope_path(path_node, filepath);
2131
    module_t *imported =
2132
        module_manager_find_relative(t->mm, t->module->path, filepath);
2133
2134
    if (imported) {
2135
        /* Module import: check both declarations and definitions */
2136
        if (!resolve_decls(t, imported)) {
2137
            return NULL;
2138
        }
2139
        bool in_decl_phase = t->module && !t->module->declared;
2140
2141
        if (!in_decl_phase) {
2142
            if (!resolve_mod_def(t, imported)) {
2143
                return NULL;
2144
            }
2145
        }
2146
        if (wildcard) {
2147
            /* Re-export all public symbols from the imported module */
2148
            for (usize i = 0; i < imported->scope->nsymbols; i++) {
2149
                symbol_t *sym = imported->scope->symbols[i];
2150
                if (!sym || !sym->node)
2151
                    continue;
2152
2153
                /* Only re-export public symbols */
2154
                attrib_t sym_attribs = 0;
2155
                switch (sym->kind) {
2156
                case SYM_FUNCTION:
2157
                    sym_attribs = sym->e.fn.attribs;
2158
                    break;
2159
                case SYM_TYPE:
2160
                    /* Check if it's a record or union declaration */
2161
                    if (sym->node->cls == NODE_RECORD) {
2162
                        node_t *attribs_node =
2163
                            sym->node->val.record_decl.attribs;
2164
                        if (attribs_node &&
2165
                            attribs_node->cls == NODE_ATTRIBUTE) {
2166
                            sym_attribs = attribs_node->val.attrib;
2167
                        }
2168
                    } else if (sym->node->cls == NODE_UNION) {
2169
                        node_t *attribs_node =
2170
                            sym->node->val.union_decl.attribs;
2171
                        if (attribs_node &&
2172
                            attribs_node->cls == NODE_ATTRIBUTE) {
2173
                            sym_attribs = attribs_node->val.attrib;
2174
                        }
2175
                    }
2176
                    break;
2177
                case SYM_MODULE:
2178
                    /* Check module declaration attributes */
2179
                    if (sym->node->cls == NODE_MOD) {
2180
                        node_t *attribs_node = sym->node->val.mod_decl.attribs;
2181
                        if (attribs_node &&
2182
                            attribs_node->cls == NODE_ATTRIBUTE) {
2183
                            sym_attribs = attribs_node->val.attrib;
2184
                        }
2185
                    }
2186
                    break;
2187
                default:
2188
                    /* Skip other symbol types for now */
2189
                    continue;
2190
                }
2191
2192
                if (sym_attribs & ATTRIB_PUB) {
2193
                    if (!symtab_add_alias(t->scope, sym->node, sym)) {
2194
                        /* Symbol already exists, skip it */
2195
                    }
2196
                }
2197
            }
2198
            return (n->type = t->types.type_void);
2199
        } else {
2200
            /* Regular module import */
2201
            if (!symbol_add(t, last, n)) {
2202
                return NULL;
2203
            }
2204
            n->sym->e.mod = imported;
2205
            n->sym->scope = imported->scope;
2206
2207
            return (n->type = t->types.type_void);
2208
        }
2209
    }
2210
2211
    /* Try function/symbol import if there's a parent scope */
2212
    if (parent) {
2213
        char modulepath[MAX_PATH_LEN] = { 0 };
2214
        module_scope_path(parent, modulepath);
2215
        module_t *parent_mod =
2216
            module_manager_find_relative(t->mm, t->module->path, modulepath);
2217
2218
        if (parent_mod && resolve_mod_def(t, parent_mod)) {
2219
            symbol_t *sym = symtab_scope_lookup(
2220
                parent_mod->scope,
2221
                last->val.ident.name,
2222
                last->val.ident.length,
2223
                SYM_ANY
2224
            );
2225
            if (sym) { /* Add alias with qualified name */
2226
                symtab_add_alias(t->scope, last, sym);
2227
2228
                n->sym        = sym;
2229
                n->sym->scope = parent_mod->scope;
2230
2231
                return (n->type = t->types.type_void);
2232
            }
2233
        }
2234
    }
2235
    return NULL;
2236
}
2237
2238
/* Scope access, eg. `foo::bar` */
2239
static type_t *resolve_scope(resolve_t *t, node_t *n) {
2240
    node_t *parent = n->val.access.lval;
2241
    node_t *child  = n->val.access.rval;
2242
2243
    /* Handle absolute path from global root: ::module::symbol */
2244
    if (parent == NULL) {
2245
        /* Look up module in global scope */
2246
        symbol_t *sym = symtab_lookup(
2247
            t->global,
2248
            child->val.ident.name,
2249
            child->val.ident.length,
2250
            SYM_MODULE
2251
        );
2252
        if (sym) {
2253
            n->sym = sym;
2254
            return (n->type = t->types.type_void);
2255
        }
2256
        return NULL;
2257
    }
2258
2259
    /* Handle `super::` references */
2260
    if (node_is_super(parent)) {
2261
        if (!t->module)
2262
            return NULL;
2263
2264
        module_t *target = module_super_ancestor(t->module, 1);
2265
        if (!target)
2266
            return NULL;
2267
        if (!target->declared && target->state != MODULE_STATE_VISITING) {
2268
            if (!resolve_decls(t, target)) {
2269
                return NULL;
2270
            }
2271
        }
2272
        if (target->ast && target->ast->sym) {
2273
            parent->sym  = target->ast->sym;
2274
            parent->type = t->types.type_void;
2275
        }
2276
        return module_lookup(t, n, child, target);
2277
    }
2278
2279
    /* Handle direct module access: module::symbol */
2280
    if (parent->cls == NODE_IDENT) {
2281
        symbol_t *sym = resolve_name(t, parent, SYM_MODULE);
2282
        if (sym) {
2283
            return module_lookup(t, n, child, sym->e.mod);
2284
        }
2285
    } else if (parent->cls == NODE_SCOPE) {
2286
        /* Handle recursive scope access: foo::bar::baz */
2287
        type_t *parent_type = resolve_scope(t, parent);
2288
        if (!parent_type)
2289
            return NULL;
2290
2291
        /* If parent is a module, look up symbol in module scope */
2292
        if (parent->sym && parent->sym->kind == SYM_MODULE) {
2293
            return module_lookup(t, n, child, parent->sym->e.mod);
2294
        }
2295
        /* If parent is a union, handle union scope */
2296
        if (parent_type->cls == TYPE_UNION) {
2297
            symbol_t *sym = union_variant_lookup(parent_type, child);
2298
2299
            if (sym) {
2300
                n->sym = sym;
2301
                return (n->type = parent_type);
2302
            }
2303
        }
2304
        return NULL;
2305
    }
2306
2307
    /* If not a module, treat it as a normal type */
2308
    type_t *parent_type = resolve_node(t, parent, NULL);
2309
    if (!parent_type)
2310
        return NULL;
2311
2312
    /* Handle union variant access */
2313
    if (parent_type->cls == TYPE_UNION) {
2314
        if ((n->sym = union_variant_lookup(parent_type, child))) {
2315
            /* For unions we store the type of the enum, not the variant */
2316
            return (n->type = parent_type);
2317
        }
2318
    }
2319
2320
    return NULL;
2321
}
2322
2323
static type_t *resolve_array_repeat(resolve_t *t, node_t *n, type_t *expected) {
2324
    if (expected->cls == TYPE_OPT) {
2325
        expected = expected->info.opt.elem;
2326
    }
2327
2328
    node_t *value = n->val.array_repeat_lit.value;
2329
    node_t *count = n->val.array_repeat_lit.count;
2330
2331
    /* Type check the value expression */
2332
    type_t *expected_typ = expected->info.ary.elem;
2333
    type_t *value_typ    = resolve_node(t, value, expected_typ);
2334
2335
    if (!value_typ)
2336
        return NULL;
2337
2338
    /* Type check the count expression */
2339
    if (!resolve_node(t, count, t->types.type_u32))
2340
        return NULL;
2341
2342
    /* Ensure the count is a compile-time constant */
2343
    usize length = 0;
2344
2345
    if (!resolve_const_usize(t, count, &length))
2346
        return NULL;
2347
2348
    /* For array contexts, use expected type */
2349
    if (expected->cls == TYPE_ARRAY) {
2350
        n->type = expected;
2351
    } else {
2352
        /* For slice contexts, create a new array type */
2353
        n->type = alloc_array_type(t, expected_typ, length);
2354
    }
2355
    return n->type;
2356
}
2357
2358
/* Check expression types. */
2359
static type_t *resolve_node(resolve_t *t, node_t *n, type_t *expected) {
2360
    /* Short-circuit if we've already traversed this node. */
2361
    if (n->type && n->cls != NODE_RECORD && n->cls != NODE_UNION)
2362
        return n->type;
2363
2364
    switch (n->cls) {
2365
    case NODE_ARRAY_LIT: {
2366
        if (expected->cls == TYPE_OPT) {
2367
            expected = expected->info.opt.elem;
2368
        }
2369
2370
        usize length = n->val.array_lit.elems.len;
2371
        if (length == 0) {
2372
            /* Create an empty array type with the expected element type. */
2373
            type_t *elem_type = expected->info.slc.elem;
2374
            n->type           = alloc_array_type(t, elem_type, 0);
2375
            return n->type;
2376
        }
2377
        /* Get the expected element type */
2378
        type_t *expected_typ = expected->cls == TYPE_SLICE
2379
                                   ? expected->info.slc.elem
2380
                                   : expected->info.ary.elem;
2381
2382
        /* Check all elements */
2383
        node_t **elems =
2384
            nodespan_ptrs(&t->module->parser, n->val.array_lit.elems);
2385
        for (usize i = 0; i < length; i++) {
2386
            if (!resolve_node(t, elems[i], expected_typ))
2387
                return NULL;
2388
        }
2389
        if (expected->cls == TYPE_ARRAY) {
2390
            n->type = expected;
2391
        } else {
2392
            /* For slice contexts, create a new array type */
2393
            n->type = alloc_array_type(t, expected_typ, length);
2394
        }
2395
        return n->type;
2396
    }
2397
2398
    case NODE_ARRAY_REPEAT_LIT:
2399
        return resolve_array_repeat(t, n, expected);
2400
2401
    case NODE_ARRAY_INDEX: {
2402
        type_t *array_typ = resolve_node(t, n->val.access.lval, NULL);
2403
        if (!array_typ)
2404
            return NULL;
2405
2406
        if (array_typ->cls == TYPE_PTR)
2407
            array_typ = deref_type(array_typ);
2408
2409
        node_t *idx_node = n->val.access.rval;
2410
2411
        if (idx_node->cls == NODE_RANGE) {
2412
            if (array_typ->cls == TYPE_SLICE) {
2413
                n->type = array_typ;
2414
                if (array_typ->info.slc.base)
2415
                    array_typ = array_typ->info.slc.base;
2416
            }
2417
            if (idx_node->val.range.start) {
2418
                if (!resolve_node(
2419
                        t, idx_node->val.range.start, t->types.type_u32
2420
                    ))
2421
                    return NULL;
2422
            }
2423
            if (idx_node->val.range.end) {
2424
                if (!resolve_node(
2425
                        t, idx_node->val.range.end, t->types.type_u32
2426
                    ))
2427
                    return NULL;
2428
            }
2429
            return (n->type = n->type ? n->type : array_typ->slice);
2430
        } else {
2431
            type_t *elem_typ = array_typ->cls == TYPE_SLICE
2432
                                   ? array_typ->info.slc.elem
2433
                                   : array_typ->info.ary.elem;
2434
2435
            if (!resolve_node(t, idx_node, t->types.type_u32))
2436
                return NULL;
2437
2438
            return (n->type = elem_typ);
2439
        }
2440
    }
2441
2442
    case NODE_UNION: {
2443
        union_decl_t *decl = &n->val.union_decl;
2444
        node_t **variants  = nodespan_ptrs(&t->module->parser, decl->variants);
2445
        if (!declare_enum(t, n)) {
2446
            return NULL;
2447
        }
2448
        type_t *typ = n->type;
2449
2450
        /* Add each variant to the union's symbol table. */
2451
        i32 iota = 0;
2452
        for (usize i = 0; i < decl->variants.len; i++) {
2453
            node_t *v = variants[i];
2454
2455
            if (!union_variant_add(t, typ, v, i, &iota))
2456
                return NULL;
2457
        }
2458
        update_enum_layout(typ);
2459
        n->sym->e.typ.info = typ;
2460
2461
        return (n->type = typ);
2462
    }
2463
2464
    case NODE_RECORD: {
2465
        record_decl_t *decl   = &n->val.record_decl;
2466
        node_t       **fields = nodespan_ptrs(&t->module->parser, decl->fields);
2467
        if (!declare_record(t, n)) {
2468
            return NULL;
2469
        }
2470
        type_t *strct_typ = n->type;
2471
2472
        /* Add each field to the record. */
2473
        for (usize i = 0; i < decl->fields.len; i++) {
2474
            node_t     *f          = fields[i];
2475
            var_decl_t *field      = &f->val.var;
2476
            type_t     *field_type = resolve_type(t, field->type);
2477
2478
            if (!field_type)
2479
                return NULL;
2480
2481
            if (!record_field_add(t, strct_typ, f, field->ident, field_type)) {
2482
                return NULL;
2483
            }
2484
        }
2485
        n->sym->e.typ.info = strct_typ;
2486
2487
        return strct_typ;
2488
    }
2489
2490
    case NODE_RECORD_TYPE:
2491
        return resolve_type(t, n);
2492
2493
    case NODE_RECORD_FIELD:
2494
        /* Record fields are handled when processing the parent record. */
2495
        return n->type;
2496
2497
    case NODE_RECORD_LIT_FIELD:
2498
        return n->type;
2499
2500
    case NODE_RECORD_LIT: {
2501
        type_t   *record_type = NULL;
2502
        type_t   *result_type = NULL;
2503
        symbol_t *variant_sym = NULL;
2504
2505
        if (!resolve_record_literal_types(
2506
                t,
2507
                n->val.record_lit.type,
2508
                expected,
2509
                &record_type,
2510
                &result_type,
2511
                &variant_sym
2512
            ))
2513
            return NULL;
2514
2515
        if (!resolve_record_literal_fields(t, n, record_type))
2516
            return NULL;
2517
2518
        if (variant_sym)
2519
            n->sym = variant_sym;
2520
2521
        return (n->type = result_type);
2522
    }
2523
2524
    case NODE_NUMBER:
2525
        return resolve_number(t, n, expected);
2526
2527
    case NODE_CHAR:
2528
        return (n->type = t->types.type_u8);
2529
2530
    case NODE_STRING:
2531
        return (n->type = t->types.type_str);
2532
2533
    case NODE_BOOL:
2534
        return (n->type = t->types.type_bool);
2535
2536
    case NODE_UNDEF:
2537
        return (n->type = expected);
2538
2539
    case NODE_NIL:
2540
        if (expected) {
2541
            if (expected->cls == TYPE_OPT)
2542
                return (n->type = expected);
2543
            return (n->type = alloc_opt_type(t, expected));
2544
        }
2545
        return NULL;
2546
2547
    case NODE_SUPER:
2548
        return NULL;
2549
2550
    case NODE_IDENT:
2551
    case NODE_SCOPE: {
2552
        bool pattern_ctx = (t->ctx == TC_CTX_PATTERN && n->cls == NODE_IDENT);
2553
        symbol_t *sym    = resolve_name(t, n, SYM_ANY);
2554
2555
        if (!sym) {
2556
            if (pattern_ctx) {
2557
                type_t *bind_type = expected ? expected : t->types.type_void;
2558
                n->type           = bind_type;
2559
                n->sym            = NULL;
2560
                return bind_type;
2561
            }
2562
            return NULL;
2563
        }
2564
        type_t *scoped_type = n->type;
2565
2566
        switch (sym->kind) {
2567
        case SYM_VARIABLE:
2568
        case SYM_VARIANT:
2569
        case SYM_CONSTANT: {
2570
            if (!sym->node)
2571
                return NULL;
2572
            if (sym->node->cls == NODE_UNION_VARIANT) {
2573
                if (!scoped_type || scoped_type->cls != TYPE_UNION)
2574
                    return NULL;
2575
                type_t *variant_type = sym->node->type;
2576
                if (variant_type->cls == TYPE_VOID)
2577
                    return (n->type = scoped_type);
2578
                return NULL;
2579
            }
2580
            return (n->type = sym->node->type);
2581
        }
2582
        case SYM_FUNCTION:
2583
            if (!sym->node)
2584
                return NULL;
2585
            sym->e.fn.used = true;
2586
            n->type        = sym->node->type;
2587
            return n->type;
2588
        case SYM_TYPE:
2589
            if (!sym->node)
2590
                return NULL;
2591
            n->type = sym->node->type;
2592
            return n->type;
2593
        default:
2594
            return NULL;
2595
        }
2596
    }
2597
2598
    case NODE_REF: {
2599
        node_t *target     = n->val.ref.target;
2600
        type_t *target_typ = resolve_node(t, target, expected);
2601
2602
        if (!target_typ)
2603
            return NULL;
2604
2605
        bool    mut_ref = n->val.ref.mut;
2606
        type_t *exp     = expected;
2607
2608
        while (exp && exp->cls == TYPE_OPT) {
2609
            exp = exp->info.opt.elem;
2610
        }
2611
        switch (target->cls) {
2612
        case NODE_IDENT: {
2613
            return (n->type = alloc_ptr_type(t, target_typ, mut_ref));
2614
        }
2615
        case NODE_ARRAY_INDEX: {
2616
            node_t *idx = target->val.access.rval;
2617
            if (idx->cls == NODE_RANGE) {
2618
                /* Array slice reference (e.g., &ary[0..3]) */
2619
2620
                if (target_typ->info.slc.mut == mut_ref) {
2621
                    return (n->type = target_typ);
2622
                }
2623
                type_t *slice_type = alloc_slice_type(
2624
                    t,
2625
                    target_typ->info.slc.elem,
2626
                    target_typ->info.slc.base,
2627
                    mut_ref
2628
                );
2629
                return (n->type = slice_type);
2630
            } else {
2631
                /* Array element reference (e.g., &ary[3]) */
2632
                return (n->type = alloc_ptr_type(t, target_typ, mut_ref));
2633
            }
2634
        }
2635
        case NODE_ARRAY_LIT:
2636
        case NODE_ARRAY_REPEAT_LIT:
2637
            /* Slice literal. */
2638
            if (target_typ->cls == TYPE_ARRAY) {
2639
                type_t *slice_type = alloc_slice_type(
2640
                    t, target_typ->info.ary.elem, target_typ, mut_ref
2641
                );
2642
                return (n->type = slice_type);
2643
            } else if (target_typ->cls == TYPE_SLICE) {
2644
                type_t *slice_type = alloc_slice_type(
2645
                    t,
2646
                    target_typ->info.slc.elem,
2647
                    target_typ->info.slc.base,
2648
                    mut_ref
2649
                );
2650
                return (n->type = slice_type);
2651
            } else {
2652
                bail("unexpected slice literal type");
2653
            }
2654
        case NODE_ACCESS:
2655
            /* Field access. */
2656
            return (n->type = alloc_ptr_type(t, target_typ, mut_ref));
2657
        default:
2658
            bail("can't take reference of %s", node_names[target->cls]);
2659
        }
2660
    }
2661
2662
    case NODE_UNOP: {
2663
        switch (n->val.unop.op) {
2664
        case OP_NOT: {
2665
            type_t *typ = resolve_node(t, n->val.unop.expr, expected);
2666
            if (!typ)
2667
                return NULL;
2668
            return (n->type = typ);
2669
        }
2670
        case OP_NEG: {
2671
            type_t *typ = resolve_node(t, n->val.unop.expr, expected);
2672
            if (!typ)
2673
                return NULL;
2674
            return (n->type = typ);
2675
        }
2676
        case OP_DEREF: {
2677
            type_t *target_typ = resolve_node(t, n->val.unop.expr, NULL);
2678
            if (!target_typ)
2679
                return NULL;
2680
2681
            return (n->type = deref_type(target_typ));
2682
        }
2683
        case OP_BNOT: {
2684
            type_t *typ = resolve_node(t, n->val.unop.expr, expected);
2685
            if (!typ)
2686
                return NULL;
2687
            return (n->type = typ);
2688
        }
2689
        default:
2690
            abort();
2691
        }
2692
    }
2693
2694
    case NODE_BINOP: {
2695
        node_t *lhs         = n->val.binop.left;
2696
        node_t *rhs         = n->val.binop.right;
2697
        bool    left_is_nil = lhs && lhs->cls == NODE_NIL;
2698
2699
        /* Check operands without forcing specific expected types */
2700
        type_t *left  = NULL;
2701
        type_t *right = NULL;
2702
2703
        if (left_is_nil && rhs && rhs->cls != NODE_NIL) {
2704
            right = resolve_node(t, rhs, NULL);
2705
            left  = resolve_node(t, lhs, right);
2706
        } else {
2707
            left  = resolve_node(t, lhs, NULL);
2708
            right = resolve_node(t, rhs, left);
2709
        }
2710
        type_t *unified = NULL;
2711
2712
        if (!left && !right)
2713
            return NULL;
2714
2715
        /* Check for pointer arithmetic before type unification */
2716
        if (n->val.binop.op == OP_ADD || n->val.binop.op == OP_SUB) {
2717
            if (left && right) {
2718
                /* Allow pointer + integer or integer + pointer */
2719
                if (left->cls == TYPE_PTR && type_is_int(right->cls)) {
2720
                    return (n->type = left);
2721
                }
2722
                if (n->val.binop.op == OP_ADD && right->cls == TYPE_PTR &&
2723
                    type_is_int(left->cls)) {
2724
                    return (n->type = right);
2725
                }
2726
            }
2727
        }
2728
2729
        bool coerce = n->val.binop.op == OP_EQ || n->val.binop.op == OP_NE;
2730
        if (coerce && left && right) {
2731
            if (left->cls == TYPE_OPT && right->cls != TYPE_OPT) {
2732
                /* Flip arguments because coercion only applies to the rval */
2733
                unified =
2734
                    type_unify(t, right, left, n, coerce, "binary operation");
2735
            } else {
2736
                unified =
2737
                    type_unify(t, left, right, n, coerce, "binary operation");
2738
            }
2739
        } else {
2740
            unified = type_unify(t, left, right, n, coerce, "binary operation");
2741
        }
2742
        if (!unified)
2743
            return NULL;
2744
2745
        /* Set operand types to unified type if they were previously NULL */
2746
        if (!left)
2747
            n->val.binop.left->type = unified;
2748
        if (!right)
2749
            n->val.binop.right->type = unified;
2750
2751
        /* Check numeric operations. */
2752
        if (n->val.binop.op <= OP_MOD) {
2753
            if (expected) {
2754
                /* If we have an expected numeric type different from unified,
2755
                 * coerce to it. This will affect the instructions used by the
2756
                 * code generator. Note that we don't try to unify the two types
2757
                 * as this will promote the smaller type to the larger one. */
2758
                if (expected != unified)
2759
                    return (n->type = expected);
2760
            }
2761
            return (n->type = unified);
2762
        }
2763
2764
        /* Check comparison operations. */
2765
        switch (n->val.binop.op) {
2766
        case OP_EQ:
2767
        case OP_NE:
2768
        case OP_GT:
2769
        case OP_LT:
2770
        case OP_LE:
2771
        case OP_GE:
2772
            /* Update operand types to unified type for comparison */
2773
            n->val.binop.left->type  = unified;
2774
            n->val.binop.right->type = unified;
2775
            return (n->type = t->types.type_bool);
2776
        case OP_AND:
2777
        case OP_OR:
2778
            return (n->type = unified);
2779
        case OP_BAND:
2780
        case OP_BOR:
2781
        case OP_XOR:
2782
        case OP_SHL:
2783
        case OP_SHR:
2784
            return (n->type = unified);
2785
        case OP_ADD:
2786
        case OP_SUB:
2787
        case OP_MUL:
2788
        case OP_DIV:
2789
        case OP_MOD:
2790
            /* These are handled above in the numeric operations section */
2791
            abort();
2792
        }
2793
        return NULL;
2794
    }
2795
2796
    case NODE_ACCESS: {
2797
        node_t *expr  = n->val.access.lval;
2798
        node_t *field = n->val.access.rval;
2799
2800
        type_t *decl_type = resolve_node(t, expr, NULL);
2801
        if (!decl_type)
2802
            return NULL;
2803
2804
        while (decl_type->cls == TYPE_PTR)
2805
            decl_type = deref_type(decl_type);
2806
2807
        if (decl_type->cls == TYPE_RECORD) {
2808
            symbol_t *field_sym = record_field_lookup(decl_type, field);
2809
            if (!field_sym)
2810
                return NULL;
2811
2812
            n->sym = field_sym;
2813
            return (n->type = field_sym->e.field.typ);
2814
        } else if (decl_type->cls == TYPE_ARRAY) {
2815
            if (ident_eq(field, LEN_FIELD, LEN_FIELD_LEN)) {
2816
                n->cls                 = NODE_NUMBER;
2817
                n->type                = t->types.type_u32;
2818
                n->val.number.value.u  = decl_type->info.ary.length;
2819
                n->val.number.text     = NULL;
2820
                n->val.number.text_len = 0;
2821
                return n->type;
2822
            }
2823
            return NULL;
2824
        } else if (decl_type->cls == TYPE_SLICE) {
2825
            if (ident_eq(field, LEN_FIELD, LEN_FIELD_LEN))
2826
                return (n->type = t->types.type_u32);
2827
            if (ident_eq(field, PTR_FIELD, PTR_FIELD_LEN))
2828
                return (n->type = decl_type->info.slc.elem->ptr);
2829
            return NULL;
2830
        }
2831
        return NULL;
2832
    }
2833
2834
    case NODE_USE:
2835
        return resolve_use(t, n);
2836
2837
    case NODE_CALL: {
2838
        node_t   *callee = n->val.call.callee;
2839
        symbol_t *sym    = resolve_name(t, callee, SYM_ANY);
2840
2841
        if (!sym)
2842
            return NULL;
2843
2844
        /* Function call */
2845
        if (sym->kind == SYM_FUNCTION) {
2846
            n->sym = sym;
2847
2848
            return resolve_call_fn(t, sym, n);
2849
        }
2850
        /* Tuple record constructor call */
2851
        if (sym->kind == SYM_TYPE) {
2852
            type_t *typ = sym->e.typ.info;
2853
2854
            if (typ && typ->cls == TYPE_RECORD && typ->info.srt.tuple) {
2855
                return resolve_tuple_record_constructor(t, n, typ);
2856
            }
2857
        }
2858
        /* Function pointer call */
2859
        if (sym->kind == SYM_VARIABLE) {
2860
            if (callee->cls == NODE_IDENT) {
2861
                if (sym->node->type && sym->node->type->cls == TYPE_FN) {
2862
                    n->sym = sym;
2863
                    return resolve_call_fn_ptr(t, sym, n);
2864
                }
2865
                return NULL;
2866
            }
2867
        } else if (sym->kind == SYM_VARIANT) {
2868
            if (callee->cls == NODE_SCOPE) {
2869
                type_t *scope = resolve_scope(t, callee);
2870
2871
                if (scope && type_is_union_with_payload(scope))
2872
                    return resolve_enum_constructor(t, n, scope, sym);
2873
            }
2874
        }
2875
        return NULL;
2876
    }
2877
    case NODE_BUILTIN:
2878
        return resolve_builtin(t, n, expected);
2879
    case NODE_CALL_ARG:
2880
        return (n->type = resolve_node(t, n->val.call_arg.expr, expected));
2881
2882
    case NODE_THROW:
2883
        return resolve_throw(t, n);
2884
    case NODE_TRY:
2885
        return resolve_try_expr(t, n, expected);
2886
    case NODE_CATCH:
2887
        bail("cannot type check %s", node_names[n->cls]);
2888
2889
    case NODE_RETURN: {
2890
        type_t *fn_ret   = t->fn->node->type->info.fun.ret;
2891
        type_t *expected = fn_ret;
2892
2893
        if (fn_ret->cls == TYPE_RESULT)
2894
            expected = fn_ret->info.res.payload;
2895
2896
        if (expected == t->types.type_void) {
2897
            if (n->val.return_stmt.value)
2898
                return NULL;
2899
            return (n->type = fn_ret);
2900
        }
2901
        if (n->val.return_stmt.value) {
2902
            if (!resolve_node(t, n->val.return_stmt.value, expected))
2903
                return NULL;
2904
        }
2905
        return (n->type = fn_ret);
2906
    }
2907
2908
    case NODE_IF:
2909
        if (!resolve_node(t, n->val.if_stmt.cond, t->types.type_bool))
2910
            return NULL;
2911
2912
        type_t *result_typ  = expected ? expected : t->types.type_void;
2913
        type_t *lbranch_typ = resolve_node(t, n->val.if_stmt.lbranch, expected);
2914
        if (!lbranch_typ)
2915
            return NULL;
2916
2917
        if (n->val.if_stmt.rbranch) {
2918
            type_t *rbranch_typ =
2919
                resolve_node(t, n->val.if_stmt.rbranch, expected);
2920
            if (!rbranch_typ)
2921
                return NULL;
2922
2923
            if (!expected) {
2924
                type_t *unified =
2925
                    type_unify(t, lbranch_typ, rbranch_typ, n, false, NULL);
2926
                if (unified)
2927
                    result_typ = unified;
2928
            }
2929
        }
2930
        return (n->type = result_typ);
2931
2932
    case NODE_IF_LET: {
2933
        type_t *expr_type = resolve_node(t, n->val.if_let_stmt.expr, NULL);
2934
        if (!expr_type)
2935
            return NULL;
2936
        /* Create scope for the bound variable */
2937
        n->val.if_let_stmt.scope     = symtab_scope(t->scope, NULL);
2938
        n->val.if_let_stmt.var->type = expr_type->info.opt.elem;
2939
        t->scope                     = n->val.if_let_stmt.scope;
2940
2941
        /* Add the bound variable to the scope */
2942
        if (!symbol_add(t, n->val.if_let_stmt.var, n->val.if_let_stmt.var))
2943
            return NULL;
2944
2945
        /* Only set symbol data if not a placeholder */
2946
        if (n->val.if_let_stmt.var->cls != NODE_PLACEHOLDER) {
2947
            n->val.if_let_stmt.var->sym->e.var.typ = expr_type->info.opt.elem;
2948
            n->val.if_let_stmt.var->sym->e.var.align =
2949
                expr_type->info.opt.elem->align;
2950
            n->val.if_let_stmt.var->sym->scope = t->scope;
2951
        }
2952
2953
        if (n->val.if_let_stmt.guard) {
2954
            if (!resolve_node(t, n->val.if_let_stmt.guard, t->types.type_bool))
2955
                return NULL;
2956
        }
2957
2958
        if (!resolve_block(t, n->val.if_let_stmt.lbranch))
2959
            return NULL;
2960
2961
        t->scope = t->scope->parent;
2962
2963
        if (n->val.if_let_stmt.rbranch) {
2964
            if (!resolve_block(t, n->val.if_let_stmt.rbranch))
2965
                return NULL;
2966
        }
2967
        return (n->type = t->types.type_void);
2968
    }
2969
2970
    case NODE_MATCH: {
2971
        /* Check the match operand */
2972
        type_t *match_typ = resolve_node(t, n->val.match_stmt.expr, NULL);
2973
        if (!match_typ)
2974
            return NULL;
2975
2976
        /* Check each case to ensure patterns match the
2977
         * match operand type. */
2978
        node_t **cases =
2979
            nodespan_ptrs(&t->module->parser, n->val.match_stmt.cases);
2980
        bool all_diverge = n->val.match_stmt.cases.len > 0;
2981
2982
        for (usize i = 0; i < n->val.match_stmt.cases.len; i++) {
2983
            node_t *c = cases[i];
2984
2985
            type_t *case_typ = resolve_match_case(t, c, match_typ);
2986
            if (!case_typ)
2987
                return NULL;
2988
2989
            /* Check if this case diverges. */
2990
            if (!node_diverges(c->val.match_case.body))
2991
                all_diverge = false;
2992
        }
2993
        /* Match diverges if all cases diverge. */
2994
        if (all_diverge)
2995
            return (n->type = t->types.type_never);
2996
2997
        return (n->type = t->types.type_void);
2998
    }
2999
    case NODE_MATCH_CASE:
3000
        /* Handled in `NODE_MATCH` */
3001
    case NODE_BLOCK:
3002
        return (n->type = resolve_block(t, n));
3003
    case NODE_FN:
3004
        /* Handled at the module level */
3005
    case NODE_LOOP:
3006
        return (n->type = resolve_block(t, n->val.loop_stmt.body));
3007
    case NODE_BREAK:
3008
        return (n->type = t->types.type_never);
3009
    case NODE_VAR:
3010
        return resolve_var(t, n);
3011
    case NODE_CONST:
3012
        return resolve_const(t, n);
3013
    case NODE_STATIC:
3014
        return resolve_static(t, n);
3015
    case NODE_PARAM:
3016
        abort();
3017
    case NODE_ASSIGN: {
3018
        type_t *ltype = resolve_node(t, n->val.assign.lval, NULL);
3019
        if (!ltype)
3020
            return NULL;
3021
3022
        if (!resolve_node(t, n->val.assign.rval, ltype))
3023
            return NULL;
3024
3025
        return (n->type = ltype);
3026
    }
3027
3028
    case NODE_ATTRIBUTE:
3029
        return (n->type = t->types.type_void);
3030
3031
    case NODE_EXPR_STMT: {
3032
        /* Check the expression but don't use its result value. */
3033
        type_t *typ = resolve_node(t, n->val.expr_stmt, NULL);
3034
        if (!typ)
3035
            return NULL;
3036
3037
        /* Expression statements don't produce values. */
3038
        return (n->type = t->types.type_void);
3039
    }
3040
3041
    case NODE_MOD:
3042
        return resolve_mod_decl(t, n);
3043
3044
    case NODE_RANGE: {
3045
        /* Check range start expression if provided */
3046
        if (n->val.range.start) {
3047
            if (!resolve_node(t, n->val.range.start, t->types.type_u32))
3048
                return NULL;
3049
        }
3050
        /* Check range end expression if provided */
3051
        if (n->val.range.end) {
3052
            if (!resolve_node(t, n->val.range.end, t->types.type_u32))
3053
                return NULL;
3054
        }
3055
        /* Range nodes don't have a specific type, they're contextual */
3056
        return (n->type = t->types.type_void);
3057
    }
3058
3059
    case NODE_AS: {
3060
        if (!resolve_node(t, n->val.as_expr.expr, NULL))
3061
            return NULL;
3062
3063
        type_t *target_type = resolve_type(t, n->val.as_expr.type);
3064
        if (!target_type)
3065
            return NULL;
3066
3067
        return (n->type = target_type);
3068
    }
3069
    case NODE_PANIC:
3070
        return (n->type = t->types.type_never);
3071
3072
    case NODE_WHILE:
3073
    case NODE_WHILE_LET:
3074
    case NODE_IF_CASE:
3075
    case NODE_GUARD_CASE:
3076
    case NODE_GUARD_LET:
3077
    case NODE_FOR:
3078
3079
    case NODE_PLACEHOLDER:
3080
        /* Placeholders don't produce a value, so return NULL type */
3081
        return (n->type = NULL);
3082
3083
    case NODE_TYPE:
3084
    case NODE_UNION_VARIANT:
3085
    case NODE_PTR:
3086
    case NODE_MOD_BODY:
3087
    case NODE_ALIGN:
3088
        bail("unsupported node type %s", node_names[n->cls]);
3089
    }
3090
    return NULL;
3091
}
3092
3093
static node_t *binding_ident(node_t *n) {
3094
    switch (n->cls) {
3095
    case NODE_VAR:
3096
        return n->val.var.ident;
3097
    case NODE_CONST:
3098
        return n->val.constant.ident;
3099
    case NODE_STATIC:
3100
        return n->val.static_decl.ident;
3101
    default:
3102
        bail("unexpected binding node %s", node_names[n->cls]);
3103
    }
3104
}
3105
3106
static type_t *resolve_binding(
3107
    resolve_t *t, node_t *n, node_t *val, node_t *typ
3108
) {
3109
    type_t *declared = NULL;
3110
    if (typ) {
3111
        /* Resolve the declared type before checking the value */
3112
        if (!(declared = resolve_type(t, typ)))
3113
            return NULL;
3114
    }
3115
    /* Check the value with the declared type as expected type */
3116
    type_t *inferred = resolve_node(t, val, declared);
3117
    if (!inferred)
3118
        return NULL;
3119
3120
    type_t *final_type = inferred;
3121
3122
    if (declared) {
3123
        final_type =
3124
            type_unify(t, inferred, declared, val, true, "variable binding");
3125
3126
        if (!final_type)
3127
            return NULL;
3128
    }
3129
3130
    node_t *ident = binding_ident(n);
3131
3132
    /* symbol_add handles placeholders internally */
3133
    if (!symbol_add(t, ident, n))
3134
        return NULL;
3135
3136
    /* Only set symbol data if not a placeholder */
3137
    if (ident->cls != NODE_PLACEHOLDER) {
3138
        n->sym->scope       = t->scope;
3139
        n->sym->e.var.typ   = final_type;
3140
        n->sym->e.var.align = final_type->align;
3141
    }
3142
3143
    return (n->type = final_type);
3144
}
3145
3146
/* Check if a `const` declaration is valid. */
3147
static type_t *resolve_const(resolve_t *t, node_t *n) {
3148
    return resolve_binding(t, n, n->val.constant.value, n->val.constant.type);
3149
}
3150
3151
static type_t *resolve_static(resolve_t *t, node_t *n) {
3152
    return resolve_binding(
3153
        t, n, n->val.static_decl.value, n->val.static_decl.type
3154
    );
3155
}
3156
3157
/* Check if a `let` or `mut` declaration is valid. */
3158
static type_t *resolve_var(resolve_t *t, node_t *n) {
3159
    node_t *type  = n->val.var.type;
3160
    node_t *value = n->val.var.value;
3161
3162
    if (!value)
3163
        return NULL;
3164
3165
    type_t *var_type = resolve_binding(t, n, value, type);
3166
3167
    if (!var_type)
3168
        return NULL;
3169
3170
    if (n->val.var.align) {
3171
        node_t *align = n->val.var.align->val.align;
3172
3173
        if (!resolve_node(t, align, t->types.type_u32))
3174
            return NULL;
3175
3176
        usize c = 0;
3177
3178
        if (!resolve_const_usize(t, align, &c))
3179
            return NULL;
3180
3181
        n->sym->e.var.align = (i32)c;
3182
    }
3183
    return var_type;
3184
}
3185
3186
static bool node_diverges(node_t *n) {
3187
    if (!n)
3188
        return false;
3189
3190
    switch (n->cls) {
3191
    case NODE_RETURN:
3192
    case NODE_THROW:
3193
    case NODE_PANIC:
3194
        return true;
3195
    case NODE_BLOCK:
3196
        return n->type && n->type->cls == TYPE_NEVER;
3197
    case NODE_IF: {
3198
        node_t *then_branch = n->val.if_stmt.lbranch;
3199
        node_t *else_branch = n->val.if_stmt.rbranch;
3200
3201
        if (!then_branch || !else_branch)
3202
            return false;
3203
3204
        return node_diverges(then_branch) && node_diverges(else_branch);
3205
    }
3206
    case NODE_IF_LET:
3207
    case NODE_IF_CASE: {
3208
        node_t *then_branch = NULL;
3209
        node_t *else_branch = NULL;
3210
3211
        if (n->cls == NODE_IF_LET) {
3212
            then_branch = n->val.if_let_stmt.lbranch;
3213
            else_branch = n->val.if_let_stmt.rbranch;
3214
        } else {
3215
            then_branch = n->val.if_case_stmt.lbranch;
3216
            else_branch = n->val.if_case_stmt.rbranch;
3217
        }
3218
        if (!then_branch || !else_branch)
3219
            return false;
3220
3221
        return node_diverges(then_branch) && node_diverges(else_branch);
3222
    }
3223
    case NODE_EXPR_STMT: {
3224
        node_t *expr = n->val.expr_stmt;
3225
3226
        if (!expr)
3227
            return false;
3228
        if (expr->type && expr->type->cls == TYPE_NEVER)
3229
            return true;
3230
3231
        if (expr->cls == NODE_CALL && expr->sym &&
3232
            expr->sym->kind == SYM_FUNCTION) {
3233
            const char *qualified = expr->sym->qualified;
3234
3235
            if (qualified &&
3236
                strcmp(qualified, "core::intrinsics::ebreak") == 0) {
3237
                return true;
3238
            }
3239
        }
3240
        return false;
3241
    }
3242
    case NODE_MATCH:
3243
        /* Match diverges if its type is TYPE_NEVER (all cases diverge). */
3244
        return n->type && n->type->cls == TYPE_NEVER;
3245
    default:
3246
        break;
3247
    }
3248
    return false;
3249
}
3250
3251
/* Check a code block. */
3252
static type_t *resolve_block(resolve_t *t, node_t *n) {
3253
    /* Create a new scope for this block. */
3254
    scope_t *parent    = t->scope;
3255
    n->val.block.scope = symtab_scope(parent, NULL);
3256
    t->scope           = n->val.block.scope;
3257
3258
    /* Check each statement in the block. */
3259
    node_t **stmts = nodespan_ptrs(&t->module->parser, n->val.block.stmts);
3260
    for (usize i = 0; i < n->val.block.stmts.len; i++) {
3261
        if (!resolve_node(t, stmts[i], NULL))
3262
            return NULL;
3263
    }
3264
    /* Return to parent scope. */
3265
    t->scope = parent;
3266
3267
    type_t *block_type = t->types.type_void;
3268
3269
    if (n->val.block.stmts.len > 0) {
3270
        node_t *last = stmts[n->val.block.stmts.len - 1];
3271
3272
        if (node_diverges(last))
3273
            block_type = t->types.type_never;
3274
    }
3275
    return (n->type = block_type);
3276
}
3277
3278
/* Type check a complete AST, starting from the root module. */
3279
bool resolve_run(resolve_t *t, module_t *root) {
3280
    if (!resolve_mod_def(t, root))
3281
        return false;
3282
3283
    for (usize i = 0; i < t->mm->nmodules; i++) {
3284
        module_t *mod = &t->mm->modules[i];
3285
3286
        if (!mod->checked) {
3287
            if (!resolve_mod_def(t, mod)) {
3288
                return false;
3289
            }
3290
        }
3291
    }
3292
    return true;
3293
}
3294
3295
/* Type check a module. */
3296
static bool resolve_mod_def(resolve_t *t, module_t *module) {
3297
    /* First check all function signatures and type declarations */
3298
    if (!resolve_decls(t, module)) {
3299
        return false;
3300
    }
3301
    if (module->state == MODULE_STATE_VISITING)
3302
        return false;
3303
    if (module->state == MODULE_STATE_VISITED && module->checked) {
3304
        return true;
3305
    }
3306
3307
    module_t *pmodule = t->module;
3308
    scope_t  *pscope  = t->scope;
3309
3310
    module->state = MODULE_STATE_VISITING;
3311
    t->module     = module;
3312
    t->scope      = module->scope;
3313
3314
    /* Type check function bodies */
3315
    node_t **mod_stmts =
3316
        nodespan_ptrs(&module->parser, module->ast->val.block.stmts);
3317
    for (usize i = 0; i < module->ast->val.block.stmts.len; i++) {
3318
        node_t *stmt = mod_stmts[i];
3319
3320
        if (stmt->cls == NODE_FN) {
3321
            if (!resolve_fn_def(t, stmt)) {
3322
                return false;
3323
            }
3324
            if (stmt->val.fn_decl.attribs &&
3325
                stmt->val.fn_decl.attribs->val.attrib & ATTRIB_DEFAULT) {
3326
                if (module->default_fn == NULL) {
3327
                    module->default_fn = stmt->sym;
3328
                }
3329
            }
3330
        }
3331
    }
3332
    if (!module->default_fn) {
3333
        for (usize i = 0; i < module->ast->val.block.stmts.len; i++) {
3334
            node_t *stmt = mod_stmts[i];
3335
            if (stmt->cls == NODE_FN && stmt->val.fn_decl.attribs &&
3336
                stmt->val.fn_decl.attribs->val.attrib & ATTRIB_DEFAULT &&
3337
                stmt->sym) {
3338
                module->default_fn = stmt->sym;
3339
                break;
3340
            }
3341
        }
3342
    }
3343
    module->checked   = true;
3344
    module->state     = MODULE_STATE_VISITED;
3345
    module->ast->type = t->types.type_void;
3346
3347
    t->module = pmodule;
3348
    t->scope  = pscope;
3349
3350
    return true;
3351
}
3352
3353
/* Check function and type declarations */
3354
static bool resolve_decls(resolve_t *t, module_t *module) {
3355
    if (module->state == MODULE_STATE_VISITING)
3356
        return false;
3357
    if (module->state == MODULE_STATE_VISITED && module->declared) {
3358
        return true;
3359
    }
3360
3361
    module_t *parent = t->module;
3362
3363
    module->state = MODULE_STATE_VISITING;
3364
    module->scope = symtab_scope(t->scope, module);
3365
    t->module     = module;
3366
    t->scope      = module->scope;
3367
3368
    node_t   *module_stmts[MAX_BLOCK_STATEMENTS] = { 0 };
3369
    module_t *module_refs[MAX_BLOCK_STATEMENTS]  = { 0 };
3370
    usize     nmodules                           = 0;
3371
3372
    /* Predeclare child modules so their symbols are available early. */
3373
    node_t **decl_stmts =
3374
        nodespan_ptrs(&module->parser, module->ast->val.block.stmts);
3375
    for (usize i = 0; i < module->ast->val.block.stmts.len; i++) {
3376
        node_t *stmt = decl_stmts[i];
3377
3378
        if (stmt->cls != NODE_MOD)
3379
            continue;
3380
3381
        node_t *name = stmt->val.mod_decl.ident;
3382
3383
        char rel[MAX_PATH_LEN] = { 0 };
3384
        strncpy(rel, name->val.ident.name, name->val.ident.length);
3385
3386
        module_t *submod =
3387
            module_manager_find_relative(t->mm, module->path, rel);
3388
        if (!submod) {
3389
            if (stmt->val.mod_decl.attribs &&
3390
                (stmt->val.mod_decl.attribs->val.attrib & ATTRIB_TEST))
3391
                continue;
3392
            return false;
3393
        }
3394
        symbol_t *sym = symtab_scope_lookup(
3395
            module->scope,
3396
            name->val.ident.name,
3397
            name->val.ident.length,
3398
            SYM_MODULE
3399
        );
3400
        if (!sym) {
3401
            if (!symbol_add(t, name, stmt)) {
3402
                return false;
3403
            }
3404
            sym = stmt->sym;
3405
        } else {
3406
            stmt->sym = sym;
3407
        }
3408
        sym->e.mod      = submod;
3409
        sym->scope      = submod->scope;
3410
        submod->attribs = stmt->val.mod_decl.attribs
3411
                              ? stmt->val.mod_decl.attribs->val.attrib
3412
                              : ATTRIB_NONE;
3413
        module_path(submod->qualified, module->qualified);
3414
        module_qualify(submod->qualified, name);
3415
3416
        module_stmts[nmodules]  = stmt;
3417
        module_refs[nmodules++] = submod;
3418
    }
3419
3420
    /* Predeclare named types so mutually recursive definitions can resolve. */
3421
    for (usize i = 0; i < module->ast->val.block.stmts.len; i++) {
3422
        node_t *stmt = decl_stmts[i];
3423
3424
        if (stmt->cls == NODE_RECORD) {
3425
            if (!declare_record(t, stmt)) {
3426
                return false;
3427
            }
3428
        } else if (stmt->cls == NODE_UNION) {
3429
            if (!declare_enum(t, stmt)) {
3430
                return false;
3431
            }
3432
        }
3433
    }
3434
3435
    for (usize i = 0; i < module->ast->val.block.stmts.len; i++) {
3436
        node_t *stmt = decl_stmts[i];
3437
3438
        switch (stmt->cls) {
3439
        case NODE_USE:
3440
            if (!resolve_use(t, stmt)) {
3441
                return false;
3442
            }
3443
            break;
3444
        case NODE_FN:
3445
            if (!resolve_fn_decl(t, stmt)) {
3446
                return false;
3447
            }
3448
            break;
3449
        case NODE_RECORD:
3450
        case NODE_UNION:
3451
            if (!resolve_node(t, stmt, NULL)) {
3452
                return false;
3453
            }
3454
            break;
3455
        case NODE_MOD:
3456
            stmt->type = t->types.type_void;
3457
            break;
3458
        case NODE_CONST:
3459
            if (!resolve_const(t, stmt)) {
3460
                return false;
3461
            }
3462
            break;
3463
        case NODE_STATIC:
3464
            if (!resolve_static(t, stmt)) {
3465
                return false;
3466
            }
3467
            break;
3468
        default:
3469
            break;
3470
        }
3471
    }
3472
3473
    /* Check submodule declarations after parent types are sized,
3474
     * so that `super::` references can resolve to fully-typed symbols.
3475
     * Skip submodules that are already being visited to avoid false
3476
     * circular dependency errors when `use X::Y` directly imports a
3477
     * submodule and that submodule uses `super::`. */
3478
    for (usize i = 0; i < nmodules; i++) {
3479
        module_t *submod = module_refs[i];
3480
3481
        if (!submod->declared && submod->state != MODULE_STATE_VISITING) {
3482
            if (!resolve_decls(t, submod)) {
3483
                return false;
3484
            }
3485
        }
3486
        if (module_stmts[i] && module_stmts[i]->sym) {
3487
            module_stmts[i]->sym->scope = submod->scope;
3488
        }
3489
    }
3490
3491
    for (usize i = 0; i < nmodules; i++) {
3492
        module_t *submod = module_refs[i];
3493
3494
        if (!submod)
3495
            return false;
3496
        /* Skip submodules that are already being visited to avoid false
3497
         * circular dependency errors. They will be checked by their
3498
         * original caller. */
3499
        if (submod->state == MODULE_STATE_VISITING) {
3500
            continue;
3501
        }
3502
        if (!resolve_mod_def(t, submod)) {
3503
            return false;
3504
        }
3505
    }
3506
    finalize_type_layout(t);
3507
3508
    module->declared  = true;
3509
    module->state     = MODULE_STATE_VISITED;
3510
    module->ast->type = t->types.type_void;
3511
3512
    t->scope  = t->scope->parent;
3513
    t->module = parent;
3514
3515
    return true;
3516
}
3517
3518
/* Register a function signature without checking its body */
3519
static type_t *resolve_fn_decl(resolve_t *t, node_t *n) {
3520
    fn_decl_t *fn = &n->val.fn_decl;
3521
3522
    /* Check attributes. */
3523
    if (fn->attribs && !resolve_node(t, fn->attribs, NULL))
3524
        return NULL;
3525
3526
    attrib_t attrs = fn->attribs ? fn->attribs->val.attrib : ATTRIB_NONE;
3527
3528
    /* Add function to symbol table */
3529
    if (!symbol_add(t, fn->ident, n)) {
3530
        return NULL;
3531
    }
3532
    n->sym->e.fn.attribs = attrs;
3533
3534
    /* Set up the qualified name for the function */
3535
    module_path(n->sym->qualified, t->module->qualified);
3536
    module_qualify(n->sym->qualified, fn->ident);
3537
3538
    /* Initialize usage tracking - mark as used if it's a default function */
3539
    n->sym->e.fn.used = (attrs & ATTRIB_DEFAULT) || (attrs & ATTRIB_TEST);
3540
3541
    /* Initialize function type and scope */
3542
    type_t *ret_typ    = n->val.fn_decl.return_type
3543
                             ? resolve_type(t, n->val.fn_decl.return_type)
3544
                             : t->types.type_void;
3545
    n->sym->e.fn.scope = symtab_scope(t->scope, NULL);
3546
    n->type = alloc_fn_type(t, n, ret_typ, n->val.fn_decl.params.len);
3547
3548
    /* Enter function scope temporarily to register parameters */
3549
    scope_t *parent = t->scope;
3550
    t->scope        = n->sym->e.fn.scope;
3551
3552
    /* Add parameters to function scope */
3553
    for (usize i = 0; i < n->val.fn_decl.params.len; i++) {
3554
        node_t *param =
3555
            nodespan_ptrs(&t->module->parser, n->val.fn_decl.params)[i];
3556
3557
        /* Assign declared type to identifier node. */
3558
        node_t *type     = param->val.param.type;
3559
        type_t *declared = resolve_type(t, type);
3560
3561
        if (!declared) {
3562
            return NULL;
3563
        }
3564
        param->type = declared;
3565
3566
        /* Store parameter type in function type for function pointer
3567
         * compatibility */
3568
        n->type->info.fun.params[i] = declared;
3569
3570
        if (!symbol_add(t, param->val.param.ident, param)) {
3571
            return NULL;
3572
        }
3573
        param->sym->e.var.typ   = declared;
3574
        param->sym->e.var.align = declared->align;
3575
    }
3576
    t->scope = parent;
3577
3578
    if (!resolve_fn_throws(t, n->type, fn->throws, ret_typ))
3579
        return NULL;
3580
3581
    return n->type;
3582
}
3583
3584
/* Type check function body (assumes signature is already registered) */
3585
static type_t *resolve_fn_def(resolve_t *t, node_t *n) {
3586
    /* Set current function and enter function scope */
3587
    t->fn    = n->sym;
3588
    t->scope = n->sym->e.fn.scope;
3589
3590
    /* For extern functions, body will be NULL */
3591
    if (n->val.fn_decl.body && !resolve_block(t, n->val.fn_decl.body)) {
3592
        t->fn    = NULL;
3593
        t->scope = t->scope->parent;
3594
        return NULL;
3595
    }
3596
    t->fn    = NULL;
3597
    t->scope = t->scope->parent;
3598
3599
    return n->type;
3600
}