#ifndef RESOLVER_H #define RESOLVER_H #include "ast.h" #include "limits.h" #include "module.h" #include "parser.h" #include "riscv.h" #include "symtab.h" #include "types.h" /* Built-in slice/array fields */ #define LEN_FIELD "len" #define LEN_FIELD_LEN 3 #define PTR_FIELD "ptr" #define PTR_FIELD_LEN 3 typedef struct type_t { typeclass_t cls; const char *name; /* Type name */ u16 namelen; /* Type name length */ union { struct { union_decl_t *decl; /* AST node for the union. */ symbol_t **variants; u8 nvariants; struct type_t *base; /* Underlying scalar type for fieldless unions */ i32 variantsize; /* Largest payload size (bytes) */ bool has_payload; /* Whether any variant carries data */ } uni; struct { struct type_t *err; /* Error set */ struct type_t *payload; /* Success payload type */ } res; struct { symbol_t **fields; /* Fields of the record */ u8 nfields; /* Number of fields */ u32 packedsize; /* Size if packed */ bool anonymous; /* Anonymous record */ bool tuple; /* Tuple-style record */ } srt; struct { struct type_t *target; /* Target type. */ bool mut; /* Mutable pointer. */ } ptr; struct { struct type_t *ret; /* Return type */ struct type_t **params; /* Parameter types */ struct type_t **throws; u8 nparams; u8 nthrows; } fun; struct { struct type_t *elem; /* Type of array elements */ u32 length; /* Length for arrays (fixed size) */ } ary; struct { struct type_t *elem; /* Type of slice elements */ struct type_t *base; /* Base array type */ bool mut; /* Mutable slice pointer. */ } slc; struct { struct type_t *elem; /* Type of the optional value */ } opt; } info; struct type_t *ptr; /* Pointer type, eg. `*T` for `T`. */ struct type_t *ptr_mut; /* Mutable pointer type, eg. `*mut T`. */ struct type_t *slice; /* Slice type, eg. *[T] for [T]. */ struct type_t *slice_mut; /* Mutable slice type, eg. *mut [T]. */ i32 size; /* Calculated size in bytes. */ i32 align; /* Alignment requirements. */ } type_t; /* Global type context. */ typedef struct { /* Built-in types. * These point into the `objects` array. */ type_t *type_i8; type_t *type_u8; type_t *type_i16; type_t *type_u16; type_t *type_i32; type_t *type_u32; type_t *type_bool; type_t *type_char; type_t *type_str; /* For statements, which have no type. */ type_t *type_void; /* Opaque type that can only be used behind pointers. */ type_t *type_opaque; /* For expressions that never produce a value. */ type_t *type_never; /* Type storage across all modules. */ type_t objects[MAX_TYPES]; u16 nobjects; /* Pools for pointer arrays inside type_t (variants, fields, params, * throws). Each type_t stores a pointer into one of these pools. */ symbol_t *sympool[MAX_SYMPTR_POOL]; u16 nsympool; struct type_t *typepool[MAX_TYPEPTR_POOL]; u16 ntypepool; } types_t; typedef enum { TC_CTX_NORMAL = 0, TC_CTX_PATTERN = 1, TC_CTX_TRY = 2, } resolve_ctx_t; /* Type checker state. */ typedef struct { scope_t *global; types_t types; symbol_t *fn; /* Track the current function. */ scope_t *scope; /* Track the current scope. */ module_manager_t *mm; /* Reference to module manager for imports */ module_t *module; /* Currently being resolved module */ u32 flags; u16 recordid; /* Next anonymous record ID */ resolve_ctx_t ctx; /* Allow unbound identifiers in patterns */ } resolve_t; /* Allocate `n` symbol_t* slots from the type pool. */ symbol_t **types_alloc_sympool(types_t *t, u8 n); /* Allocate `n` type_t* slots from the type pool. */ type_t **types_alloc_typepool(types_t *t, u8 n); /* Dereference a type. */ type_t *deref_type(type_t *ref); /* Initialize type checker. */ void resolve_init(resolve_t *t, module_manager_t *mm); /* Typecheck a complete AST. */ bool resolve_run(resolve_t *t, module_t *root); /* Check if a type is numeric, eg. integer or float. */ bool type_is_numeric(typeclass_t t); /* Check if a type is compound, ie. is made of multiple sub-types. */ bool type_is_compound(type_t *t); /* Check if a type is an address, eg. a pointer or slice. */ bool type_is_address(typeclass_t t); /* Check if a type is an integer */ bool type_is_int(typeclass_t t); /* Check if a type is an unsigned integer */ bool type_is_unsigned(typeclass_t t); /* Check if a type is primitive, ie. not compound. */ bool type_is_primitive(type_t *t); /* Check if a type is passed by reference automatically. */ bool type_is_passed_by_ref(type_t *t); /* Check if a type is a tagged value */ bool type_is_tagged_value(type_t *ty); /* Check if a type is a union with a payload value */ bool type_is_union_with_payload(type_t *ty); /* Check if a type is packed, ie. it has no padding */ bool type_is_packed(type_t *t); /* Check if type `a` can be coerced to type `b`. This handles cases like * *mut [T] -> *[T] where the types are structurally compatible. */ bool type_coercible(type_t *a, type_t *b); #endif