Files
spl/stage1/spl_sema.c
T

1290 lines
47 KiB
C

#include "spl_sema.h"
#include "spl_type.h"
void spl_scope_init(spl_scope_t *scope) {
vec_init(scope->scopes);
vec_push(scope->scopes, (spl_scope_node_t){0});
scope->current_scope = 0;
scope->root_scope = 0;
}
void spl_scope_drop(spl_scope_t *scope) {
for (usize i = 0; i < vec_size(scope->scopes); ++i) {
map_free(vec_at(scope->scopes, i).symbols);
}
vec_free(scope->scopes);
scope->current_scope = 0;
scope->root_scope = 0;
}
spl_scope_id_t spl_scope_alloc(spl_scope_t *scope) {
spl_scope_node_t n = {0};
n.parent = scope->current_scope;
map_init(n.symbols, MAP_HASH_STR, MAP_CMP_STR);
vec_push(scope->scopes, n);
return vec_size(scope->scopes) - 1;
}
bool spl_scope_insert(spl_scope_t *scope, spl_scope_id_t id, spl_symbol_t symbol) {
if (!id || id >= vec_size(scope->scopes)) {
LOG_FATAL("sema scope insert error");
return false;
}
spl_scope_node_t *node = &vec_at(scope->scopes, id);
spl_symbol_t old = {0};
if (map_get(node->symbols, symbol.name, &old)) {
SPL_ERROR(&(spl_dbg_node_t){0}, "duplicate symbol `%s`", symbol.name);
return false;
}
map_put(node->symbols, symbol.name, symbol);
return true;
}
bool spl_scope_find(spl_scope_t *scope, const char *name, spl_symbol_t *out) {
if (!scope || !name || !out)
return false;
for (spl_scope_id_t id = scope->current_scope; id != 0; id = vec_at(scope->scopes, id).parent) {
spl_scope_node_t *s = &vec_at(scope->scopes, id);
if (map_get(s->symbols, name, out)) {
return true;
}
}
return false;
}
static inline void sema_push_scope(spl_sema_t *sema) {
spl_scope_id_t new_scope = spl_scope_alloc(sema->scope);
sema->store_scope = sema->scope->current_scope;
sema->scope->current_scope = new_scope;
}
static inline void sema_pop_scope(spl_sema_t *sema) {
sema->scope->current_scope = sema->store_scope;
}
static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_lang_type_id_t to,
spl_lang_type_id_t from) {
if (to == 0 || from == 0)
return 0;
spl_lang_type_node_t *to_node = spl_lang_type_node(sema->type, to);
if (!to_node)
return 0;
if (to_node->kind == SPL_LANG_TYPE_INFER)
return from;
spl_lang_type_node_t *from_node = spl_lang_type_node(sema->type, from);
if (!from_node)
return 0;
if (from_node->kind == SPL_LANG_TYPE_INT) {
spl_type_id_t from_ir = spl_lang_type_get_ir_type(sema->type, from);
spl_type_node_t *from_ir_node = spl_type_node(sema->type, from_ir);
if (from_ir_node && from_ir_node->int_type.bits == 0 && to_node->kind == SPL_LANG_TYPE_INT)
return to;
}
if (from_node->kind == SPL_LANG_TYPE_FLOAT) {
spl_type_id_t from_ir = spl_lang_type_get_ir_type(sema->type, from);
spl_type_node_t *from_ir_node = spl_type_node(sema->type, from_ir);
if (from_ir_node && from_ir_node->float_type.bits == 0 &&
to_node->kind == SPL_LANG_TYPE_FLOAT)
return to;
}
if (to_node->kind == SPL_LANG_TYPE_ARRAY && from_node->kind == SPL_LANG_TYPE_ARRAY) {
spl_lang_type_id_t to_elem = to_node->extra.elem;
spl_lang_type_id_t from_elem = from_node->extra.elem;
if (sema_coerce(sema, to_elem, from_elem) != 0)
return to;
}
if (spl_lang_type_is_subtype(sema->type, from, to))
return to;
return 0;
}
static spl_lang_type_id_t sema_coerce_balance(spl_sema_t *sema, spl_lang_type_id_t t1,
spl_lang_type_id_t t2) {
if (t1 == 0 || t2 == 0)
return 0;
if (t1 == t2)
return t1;
spl_lang_type_node_t *n1 = spl_lang_type_node(sema->type, t1);
spl_lang_type_node_t *n2 = spl_lang_type_node(sema->type, t2);
if (!n1 || !n2)
return 0;
if (n1->kind == SPL_LANG_TYPE_ANY || n2->kind == SPL_LANG_TYPE_ANY)
return spl_lang_make_any(sema->type);
if (n1->kind == SPL_LANG_TYPE_NEVER)
return t2;
if (n2->kind == SPL_LANG_TYPE_NEVER)
return t1;
if (spl_lang_type_is_subtype(sema->type, t1, t2))
return t2;
if (spl_lang_type_is_subtype(sema->type, t2, t1))
return t1;
if (n1->kind == SPL_LANG_TYPE_INT && n2->kind == SPL_LANG_TYPE_INT) {
// 如果一个是另一个的子类型,直接返回父类型(已在前面通用检查中处理)
// 否则符号不同且无法安全提升,返回 0
return 0;
}
if (n1->kind == SPL_LANG_TYPE_FLOAT && n2->kind == SPL_LANG_TYPE_FLOAT) {
spl_type_id_t ir1 = spl_lang_type_get_ir_type(sema->type, t1);
spl_type_id_t ir2 = spl_lang_type_get_ir_type(sema->type, t2);
spl_type_node_t *irn1 = spl_type_node(sema->type, ir1);
spl_type_node_t *irn2 = spl_type_node(sema->type, ir2);
if (irn1 && irn2) {
usize bits = irn1->float_type.bits > irn2->float_type.bits ? irn1->float_type.bits
: irn2->float_type.bits;
return spl_lang_make_float(sema->type, bits);
}
}
return 0;
}
static bool sema_coerce_for_bool(spl_sema_t *sema, spl_lang_type_id_t from) {
spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type);
return sema_coerce(sema, bool_tid, from) == bool_tid;
}
static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_t lang_tid) {
spl_lang_type_node_t *n = spl_lang_type_node(sema->type, lang_tid);
if (!n)
return 0;
switch (n->kind) {
case SPL_LANG_TYPE_ARRAY:
case SPL_LANG_TYPE_SLICE:
case SPL_LANG_TYPE_RANGE:
case SPL_LANG_TYPE_PTR:
return n->extra.elem;
default:
return 0;
}
}
static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
if (!n)
return;
switch (n->kind) {
case SPL_AST_CONTAINER_MEMBERS: {
spl_symbol_t file_sym = {.name = "$file", .kind = SPL_SYMBOL_KIND_TYPE};
file_sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, "$file", n->dbg, ref);
n->resolved_def_id = file_sym.node;
spl_scope_id_t root_scope = spl_scope_alloc(sema->scope);
sema->scope->current_scope = root_scope;
sema->scope->root_scope = root_scope;
spl_scope_insert(sema->scope, root_scope, file_sym);
for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) {
sema_collect(sema, vec_at(n->container_members.declarations, i));
}
break;
}
case SPL_AST_TYPE_DECL: {
spl_symbol_t sym = {.name = n->type_decl.name, .kind = SPL_SYMBOL_KIND_TYPE};
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (!te) {
SPL_ERROR(&n->dbg, "type declaration `%s` missing type expression", n->type_decl.name);
sema->error_count++;
return;
}
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, sym.name, te->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
spl_scope_id_t old_scope = sema->scope->current_scope;
spl_scope_id_t inner_scope = spl_scope_alloc(sema->scope);
sema->scope->current_scope = inner_scope;
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
sema_collect(sema, vec_at(te->type_aggregate.members, i));
}
sema->scope->current_scope = old_scope;
} else {
sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
}
break;
}
case SPL_AST_FN_DECL: {
spl_symbol_t sym = {.name = n->fn_decl.name, .kind = SPL_SYMBOL_KIND_FN};
sym.node = spl_def_alloc(sema->type, SPL_DEF_FN, sym.name, n->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
break;
}
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern);
if (pat && pat->kind == SPL_AST_PATTERN_IDENT) {
const char *name = pat->pattern_ident.name;
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
} else {
SPL_ERROR(&n->dbg, "unsupported variable pattern (only simple identifier)");
sema->error_count++;
}
break;
}
case SPL_AST_TOP_LEVEL_BLOCK:
if (n->top_level_block.block) {
sema_collect(sema, n->top_level_block.block);
}
break;
default:
break;
}
}
static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (ref == 0)
return 0;
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
if (!n)
return 0;
switch (n->kind) {
case SPL_AST_CONTAINER_MEMBERS:
for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) {
sema_parse(sema, vec_at(n->container_members.declarations, i));
}
return 0;
case SPL_AST_FN_DECL: {
if (n->resolved_def_id == 0) {
Panic("fn `%s` not collected", n->fn_decl.name);
}
spl_lang_type_id_vec_t param_types;
vec_init(param_types);
for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) {
spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i));
if (pd && pd->kind == SPL_AST_PARAM_DECL && pd->param_decl.type_expr) {
vec_push(param_types, sema_parse(sema, pd->param_decl.type_expr));
} else {
vec_push(param_types, spl_lang_make_varargs(sema->type));
}
}
spl_lang_type_id_t ret_tid = sema_parse(sema, n->fn_decl.ret_type);
if (ret_tid == 0) {
ret_tid = spl_lang_make_unit(sema->type);
}
spl_lang_type_id_t fn_tid = spl_lang_make_fn(
sema->type, ret_tid, vec_unsafe_get_data(param_types), vec_size(param_types));
Assert(fn_tid != 0);
vec_free(param_types);
spl_def_resolve(sema->type, n->resolved_def_id, fn_tid);
if (n->fn_decl.body) {
sema_push_scope(sema);
for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) {
spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i));
if (pd && pd->kind == SPL_AST_PARAM_DECL) {
spl_symbol_t psym = {.name = pd->param_decl.name, .kind = SPL_SYMBOL_KIND_VAR};
psym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, psym.name, pd->dbg,
vec_at(n->fn_decl.params, i));
spl_lang_type_id_t p_tid = sema_parse(sema, pd->param_decl.type_expr);
spl_def_resolve(sema->type, psym.node, p_tid);
pd->resolved_def_id = psym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, psym);
}
}
spl_lang_type_id_t old_ret = sema->current_fn_ret_tid;
sema->current_fn_ret_tid = ret_tid;
sema_parse(sema, n->fn_decl.body);
sema->current_fn_ret_tid = old_ret;
sema_pop_scope(sema);
}
return fn_tid;
}
case SPL_AST_TYPE_DECL: {
if (!n->type_decl.type_expr)
break;
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (!te)
break;
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
spl_type_member_vec_t members;
vec_init(members);
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i));
if (mn && mn->kind == SPL_AST_MEMBER_DECL) {
spl_lang_type_id_t mtid = sema_parse(sema, mn->member_decl.type_expr);
spl_type_member_t m = {.name = mn->member_decl.name,
.type_id = spl_lang_type_get_ir_type(sema->type, mtid),
.ast_node_ref = vec_at(te->type_aggregate.members, i)};
vec_push(members, m);
}
}
spl_type_node_kind_t tk;
if (strcmp(te->type_aggregate.kind_name, "struct") == 0)
tk = SPL_TYPE_STRUCT;
else if (strcmp(te->type_aggregate.kind_name, "union") == 0)
tk = SPL_TYPE_UNION;
else if (strcmp(te->type_aggregate.kind_name, "enum") == 0)
tk = SPL_TYPE_ENUM;
else
tk = SPL_TYPE_STRUCT;
spl_type_layout_t layout = {.mode = SPL_TYPE_LAYOUT_AUTO};
spl_type_id_t agg_ir = spl_type_builder_agg(
sema->type, tk, &members, spl_type_builder_int(sema->type, 32, 1), layout);
vec_free(members);
// 创建语言级节点
spl_lang_type_node_t lang_node = {0};
switch (tk) {
case SPL_TYPE_STRUCT:
lang_node.kind = SPL_LANG_TYPE_STRUCT;
break;
case SPL_TYPE_UNION:
lang_node.kind = SPL_LANG_TYPE_UNION;
break;
case SPL_TYPE_ENUM:
lang_node.kind = SPL_LANG_TYPE_ENUM;
break;
case SPL_TYPE_SHAPE:
lang_node.kind = SPL_LANG_TYPE_SHAPE;
break;
default:
break;
}
lang_node.ir_type_id = agg_ir;
vec_push(sema->type->lang_table, lang_node);
spl_lang_type_id_t agg_lang = vec_size(sema->type->lang_table) - 1;
spl_def_resolve(sema->type, n->resolved_def_id, agg_lang);
n->resolved_type_id = agg_lang; // 存储 lang_id
// 处理聚合内部的函数声明
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i));
if (mn && mn->kind == SPL_AST_FN_DECL) {
sema_parse(sema, vec_at(te->type_aggregate.members, i));
}
}
} else {
spl_lang_type_id_t tid = sema_parse(sema, n->type_decl.type_expr);
spl_def_resolve(sema->type, n->resolved_def_id, tid);
n->resolved_type_id = tid; // 存储 lang_id
}
break;
}
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) {
SPL_ERROR(&n->dbg, "unsupported variable pattern");
sema->error_count++;
return 0;
}
const char *name = pat->pattern_ident.name;
if (n->resolved_def_id == 0) {
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
}
spl_lang_type_id_t decl_tid;
if (n->var_const_decl.type) {
decl_tid = sema_parse(sema, n->var_const_decl.type);
} else {
decl_tid = spl_lang_make_infer(sema->type);
}
if (n->var_const_decl.init_expr == 0) {
SPL_ERROR(&n->dbg, "variable `%s` must be initialized", name);
sema->error_count++;
return 0;
}
spl_lang_type_id_t init_tid = sema_parse(sema, n->var_const_decl.init_expr);
decl_tid = sema_coerce(sema, decl_tid, init_tid);
if (decl_tid == 0) {
SPL_ERROR(&n->dbg, "cannot infer type for variable `%s`", name);
sema->error_count++;
return 0;
}
spl_def_resolve(sema->type, n->resolved_def_id, decl_tid);
n->resolved_type_id = decl_tid; // 存储 lang_id
return decl_tid;
}
case SPL_AST_MEMBER_DECL: {
if (n->member_decl.type_expr) {
return sema_parse(sema, n->member_decl.type_expr);
}
return 0;
}
case SPL_AST_PARAM_DECL: {
if (n->param_decl.type_expr) {
return sema_parse(sema, n->param_decl.type_expr);
}
return 0;
}
case SPL_AST_EXPR_INT_LIT: {
spl_lang_type_id_t ct = spl_lang_make_int(sema->type, 0, 1);
n->resolved_type_id = ct;
return ct;
}
case SPL_AST_EXPR_FLOAT_LIT: {
spl_lang_type_id_t ct = spl_lang_make_float(sema->type, 0);
n->resolved_type_id = ct;
return ct;
}
case SPL_AST_EXPR_CHAR_LIT: {
spl_lang_type_id_t u8 = spl_lang_make_int(sema->type, 8, 0);
n->resolved_type_id = u8;
return u8;
}
case SPL_AST_EXPR_STRING_LIT: {
spl_lang_type_id_t u8 = spl_lang_make_int(sema->type, 8, 0);
spl_lang_type_id_t slice = spl_lang_make_slice(sema->type, u8);
n->resolved_type_id = slice;
return slice;
}
case SPL_AST_EXPR_BOOL_LIT: {
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
n->resolved_type_id = bt;
return bt;
}
case SPL_AST_EXPR_NULL_LIT: {
spl_lang_type_id_t never = spl_lang_make_never(sema->type);
spl_lang_type_id_t ptr = spl_lang_make_ptr(sema->type, never);
n->resolved_type_id = ptr;
return ptr;
}
case SPL_AST_EXPR_UNDEFINED_LIT: {
spl_lang_type_id_t t = spl_lang_make_never(sema->type);
n->resolved_type_id = t;
return t;
}
case SPL_AST_EXPR_IDENT: {
const char *name = n->ident.name;
spl_symbol_t sym;
if (!spl_scope_find(sema->scope, name, &sym)) {
SPL_ERROR(&n->dbg, "undefined identifier `%s`", name);
sema->error_count++;
return 0;
}
if (sym.node == 0) {
SPL_ERROR(&n->dbg, "identifier `%s` has no definition", name);
sema->error_count++;
return 0;
}
n->resolved_def_id = sym.node;
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
if (!def) {
SPL_ERROR(&n->dbg, "definition for `%s` not found", name);
sema->error_count++;
return 0;
}
return def->lang_id;
}
case SPL_AST_EXPR_UNARY: {
spl_lang_type_id_t operand_tid = sema_parse(sema, n->unary.operand);
if (operand_tid == 0)
return 0;
spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, operand_tid);
if (!tn)
return 0;
switch (n->unary.op) {
case SPL_UNARY_OP_MINUS:
if (tn->kind != SPL_LANG_TYPE_INT && tn->kind != SPL_LANG_TYPE_FLOAT) {
SPL_ERROR(&n->dbg, "unary minus requires numeric operand");
sema->error_count++;
return 0;
}
n->resolved_type_id = operand_tid;
return operand_tid;
case SPL_UNARY_OP_NOT:
if (tn->kind != SPL_LANG_TYPE_BOOL) {
SPL_ERROR(&n->dbg, "logical not requires bool operand");
sema->error_count++;
return 0;
}
{
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
n->resolved_type_id = bt;
return bt;
}
case SPL_UNARY_OP_BIT_NOT:
if (tn->kind != SPL_LANG_TYPE_INT) {
SPL_ERROR(&n->dbg, "bitwise not requires integer operand");
sema->error_count++;
return 0;
}
n->resolved_type_id = operand_tid;
return operand_tid;
case SPL_UNARY_OP_ADDRESS: {
spl_lang_type_id_t ptr_tid = spl_lang_make_ptr(sema->type, operand_tid);
n->resolved_type_id = ptr_tid;
return ptr_tid;
}
default:
UNREACHABLE();
}
break;
}
case SPL_AST_EXPR_BINARY: {
spl_lang_type_id_t lt = sema_parse(sema, n->binary.left);
spl_lang_type_id_t rt = sema_parse(sema, n->binary.right);
spl_binary_op_t op = n->binary.op;
switch (op) {
case SPL_OP_ASSIGN:
if (sema_coerce(sema, lt, rt) == 0) {
SPL_ERROR(&n->dbg, "assignment type mismatch");
sema->error_count++;
return 0;
}
n->resolved_type_id = lt;
return lt;
case SPL_OP_ASSIGN_ADD:
case SPL_OP_ASSIGN_SUB:
case SPL_OP_ASSIGN_MUL:
case SPL_OP_ASSIGN_DIV:
case SPL_OP_ASSIGN_MOD:
case SPL_OP_ASSIGN_AND:
case SPL_OP_ASSIGN_OR:
case SPL_OP_ASSIGN_XOR:
case SPL_OP_ASSIGN_LSHIFT:
case SPL_OP_ASSIGN_RSHIFT: {
spl_lang_type_id_t balanced = sema_coerce_balance(sema, lt, rt);
if (balanced == 0 || balanced != lt) {
SPL_ERROR(&n->dbg, "compound assignment type mismatch");
sema->error_count++;
return 0;
}
n->resolved_type_id = lt;
return lt;
}
case SPL_OP_BOOL_OR:
case SPL_OP_BOOL_AND: {
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt);
spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt);
if (!ln || ln->kind != SPL_LANG_TYPE_BOOL || !rn || rn->kind != SPL_LANG_TYPE_BOOL) {
SPL_ERROR(&n->dbg, "logical operands must be bool");
sema->error_count++;
return 0;
}
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
n->resolved_type_id = bt;
return bt;
}
case SPL_OP_BIT_OR:
case SPL_OP_BIT_XOR:
case SPL_OP_BIT_AND: {
spl_lang_type_id_t bal = sema_coerce_balance(sema, lt, rt);
spl_lang_type_node_t *bn = spl_lang_type_node(sema->type, bal);
if (!bn || bn->kind != SPL_LANG_TYPE_INT) {
SPL_ERROR(&n->dbg, "bitwise operands must be integers");
sema->error_count++;
return 0;
}
n->resolved_type_id = bal;
return bal;
}
case SPL_OP_CMP_EQ:
case SPL_OP_CMP_NE:
case SPL_OP_CMP_LE:
case SPL_OP_CMP_GE:
case SPL_OP_CMP_LT:
case SPL_OP_CMP_GT: {
// FIXME 不一定合理
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt);
spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt);
bool numeric =
(ln && (ln->kind == SPL_LANG_TYPE_INT || ln->kind == SPL_LANG_TYPE_FLOAT)) &&
(rn && (rn->kind == SPL_LANG_TYPE_INT || rn->kind == SPL_LANG_TYPE_FLOAT));
if (!numeric && sema_coerce_balance(sema, lt, rt) == 0) {
SPL_ERROR(&n->dbg, "comparison operands type mismatch");
sema->error_count++;
return 0;
}
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
n->resolved_type_id = bt;
return bt;
}
case SPL_OP_LSHIFT:
case SPL_OP_RSHIFT: {
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt);
spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt);
if (!ln || ln->kind != SPL_LANG_TYPE_INT || !rn || rn->kind != SPL_LANG_TYPE_INT) {
SPL_ERROR(&n->dbg, "shift operands must be integers");
sema->error_count++;
return 0;
}
n->resolved_type_id = lt;
return lt;
}
case SPL_OP_ADD:
case SPL_OP_SUB:
case SPL_OP_MUL:
case SPL_OP_DIV:
case SPL_OP_MOD: {
spl_lang_type_id_t bal = sema_coerce_balance(sema, lt, rt);
spl_lang_type_node_t *bn = spl_lang_type_node(sema->type, bal);
if (!bn || (bn->kind != SPL_LANG_TYPE_INT && bn->kind != SPL_LANG_TYPE_FLOAT)) {
SPL_ERROR(&n->dbg, "arithmetic operands type mismatch");
sema->error_count++;
return 0;
}
n->resolved_type_id = bal;
return bal;
}
case SPL_OP_RANGE: {
spl_lang_type_id_t i64 = spl_lang_make_int(sema->type, 64, 1);
spl_lang_type_id_t range = spl_lang_make_range(sema->type, i64);
n->resolved_type_id = range;
return range;
}
default:
break;
}
break;
}
case SPL_AST_EXPR_CALL: {
spl_lang_type_id_t callee_tid = sema_parse(sema, n->call.callee);
spl_lang_type_node_t *fn = spl_lang_type_node(sema->type, callee_tid);
if (!fn || fn->kind != SPL_LANG_TYPE_FN) {
SPL_ERROR(&n->dbg, "callee is not a function");
sema->error_count++;
return 0;
}
// 检查函数是否可变参数:最后一个参数是否为 VARARGS
bool has_varargs = false;
usize fixed_param_count = vec_size(fn->extra.fn.params);
if (fixed_param_count > 0) {
spl_lang_type_id_t last_param = vec_at(fn->extra.fn.params, fixed_param_count - 1);
spl_lang_type_node_t *last_node = spl_lang_type_node(sema->type, last_param);
if (last_node && last_node->kind == SPL_LANG_TYPE_VARARGS) {
has_varargs = true;
fixed_param_count--; // 排除 VARARGS 参数
}
}
if (has_varargs) {
// 可变参数函数:实参数量至少等于固定参数数量
if (vec_size(n->call.args) < fixed_param_count) {
SPL_ERROR(&n->dbg, "too few arguments (expected at least %zu)", fixed_param_count);
sema->error_count++;
} else {
// 检查固定参数部分
for (usize i = 0; i < fixed_param_count; ++i) {
spl_lang_type_id_t arg_tid = sema_parse(sema, vec_at(n->call.args, i));
spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i);
if (sema_coerce(sema, param_tid, arg_tid) == 0) {
SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1);
sema->error_count++;
}
}
// 额外参数不进行类型检查(或可扩展为元组类型检查)
}
} else {
// 非可变参数函数:实参数量必须严格匹配
if (vec_size(n->call.args) != vec_size(fn->extra.fn.params)) {
SPL_ERROR(&n->dbg, "argument count mismatch (expected %zu, got %zu)",
vec_size(fn->extra.fn.params), vec_size(n->call.args));
sema->error_count++;
} else {
for (usize i = 0; i < vec_size(n->call.args); ++i) {
spl_lang_type_id_t arg_tid = sema_parse(sema, vec_at(n->call.args, i));
spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i);
if (sema_coerce(sema, param_tid, arg_tid) == 0) {
SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1);
sema->error_count++;
}
}
}
}
spl_lang_type_id_t ret_tid = fn->extra.fn.ret;
n->resolved_type_id = ret_tid;
return ret_tid;
}
case SPL_AST_EXPR_FIELD: {
spl_lang_type_id_t obj_tid = sema_parse(sema, n->field.obj);
spl_lang_type_node_t *obj_node = spl_lang_type_node(sema->type, obj_tid);
if (!obj_node)
return 0;
// 内建字段:数组/切片的 len
if ((obj_node->kind == SPL_LANG_TYPE_ARRAY || obj_node->kind == SPL_LANG_TYPE_SLICE) &&
strcmp(n->field.field, "len") == 0) {
spl_lang_type_id_t usize_tid = spl_lang_make_int(sema->type, sizeof(void *) * 8, 0);
n->resolved_type_id = usize_tid;
return usize_tid;
}
// 自动解引用
spl_lang_type_id_t agg_lang = obj_tid;
if (obj_node->kind == SPL_LANG_TYPE_PTR) {
agg_lang = obj_node->extra.elem;
}
spl_lang_type_node_t *agg_node = spl_lang_type_node(sema->type, agg_lang);
if (!agg_node ||
(agg_node->kind != SPL_LANG_TYPE_STRUCT && agg_node->kind != SPL_LANG_TYPE_UNION)) {
SPL_ERROR(&n->dbg, "field access on non-aggregate type");
sema->error_count++;
return 0;
}
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang);
const spl_type_member_t *member = spl_type_agg_member(sema->type, agg_ir, n->field.field);
if (!member) {
SPL_ERROR(&n->dbg, "no field `%s`", n->field.field);
sema->error_count++;
return 0;
}
// 将底层字段类型映射回语言级类型
spl_lang_type_id_t field_lang = 0;
for (usize i = 1; i < vec_size(sema->type->lang_table); ++i) {
spl_lang_type_node_t *ln = &vec_at(sema->type->lang_table, i);
if (ln->ir_type_id == member->type_id) {
field_lang = i;
break;
}
}
if (!field_lang) {
SPL_ERROR(&n->dbg, "cannot resolve field type for `%s`", n->field.field);
sema->error_count++;
return 0;
}
n->resolved_type_id = field_lang;
return field_lang;
}
case SPL_AST_EXPR_INDEX: {
spl_lang_type_id_t obj_tid = sema_parse(sema, n->index.obj);
spl_lang_type_id_t idx_tid = sema_parse(sema, n->index.index);
spl_lang_type_node_t *obj_node = spl_lang_type_node(sema->type, obj_tid);
if (!obj_node)
return 0;
spl_lang_type_id_t elem_lang = 0;
switch (obj_node->kind) {
case SPL_LANG_TYPE_ARRAY:
case SPL_LANG_TYPE_SLICE:
case SPL_LANG_TYPE_RANGE:
case SPL_LANG_TYPE_PTR:
elem_lang = obj_node->extra.elem;
break;
case SPL_LANG_TYPE_TUPLE:
if (vec_size(obj_node->extra.elems) > 0)
elem_lang = vec_at(obj_node->extra.elems, 0);
else {
SPL_ERROR(&n->dbg, "empty tuple");
sema->error_count++;
return 0;
}
break;
default:
SPL_ERROR(&n->dbg, "index base must be array, pointer, slice, or tuple");
sema->error_count++;
return 0;
}
(void)idx_tid;
n->resolved_type_id = elem_lang;
return elem_lang;
}
case SPL_AST_EXPR_SLICE: {
spl_lang_type_id_t obj_tid = sema_parse(sema, n->slice.obj);
if (n->slice.begin)
sema_parse(sema, n->slice.begin);
if (n->slice.end)
sema_parse(sema, n->slice.end);
spl_lang_type_node_t *obj_node = spl_lang_type_node(sema->type, obj_tid);
if (!obj_node)
return 0;
spl_lang_type_id_t elem_lang = 0;
if (obj_node->kind == SPL_LANG_TYPE_ARRAY || obj_node->kind == SPL_LANG_TYPE_PTR ||
obj_node->kind == SPL_LANG_TYPE_SLICE) {
elem_lang = obj_node->extra.elem;
} else {
SPL_ERROR(&n->dbg, "slice base must be array, pointer, or slice");
sema->error_count++;
return 0;
}
spl_lang_type_id_t slice_tid = spl_lang_make_slice(sema->type, elem_lang);
n->resolved_type_id = slice_tid;
return slice_tid;
}
case SPL_AST_EXPR_CAST: {
spl_lang_type_id_t src_tid = sema_parse(sema, n->cast.expr);
spl_lang_type_id_t dst_tid = sema_parse(sema, n->cast.type);
spl_lang_type_node_t *src_node = spl_lang_type_node(sema->type, src_tid);
if (!src_node)
return 0;
if (src_node->kind != SPL_LANG_TYPE_INT && src_node->kind != SPL_LANG_TYPE_FLOAT &&
src_node->kind != SPL_LANG_TYPE_BOOL) {
SPL_ERROR(&n->dbg, "invalid cast from non-primitive type");
sema->error_count++;
return 0;
}
n->resolved_type_id = dst_tid;
return dst_tid;
}
case SPL_AST_EXPR_TUPLE: {
spl_lang_type_id_vec_t elems;
vec_init(elems);
for (usize i = 0; i < vec_size(n->tuple.elems); ++i) {
vec_push(elems, sema_parse(sema, vec_at(n->tuple.elems, i)));
}
spl_lang_type_id_t tuple =
spl_lang_make_tuple(sema->type, vec_unsafe_get_data(elems), vec_size(elems));
vec_free(elems);
n->resolved_type_id = tuple;
return tuple;
}
case SPL_AST_EXPR_ARRAY_LIT: {
spl_lang_type_id_t elem_tid = 0;
if (n->array_literal.elem_type) {
elem_tid = sema_parse(sema, n->array_literal.elem_type);
}
for (usize i = 0; i < vec_size(n->array_literal.elems); ++i) {
spl_lang_type_id_t et = sema_parse(sema, vec_at(n->array_literal.elems, i));
if (elem_tid == 0)
elem_tid = et;
else if (sema_coerce(sema, elem_tid, et) == 0) {
SPL_ERROR(&n->dbg, "array element type mismatch");
sema->error_count++;
}
}
usize len;
if (n->array_literal.is_underscore_len) {
len = vec_size(n->array_literal.elems);
} else {
len =
n->array_literal.has_len ? n->array_literal.len : vec_size(n->array_literal.elems);
}
spl_lang_type_id_t arr_tid = spl_lang_make_array(sema->type, elem_tid, len);
n->resolved_type_id = arr_tid;
return arr_tid;
}
case SPL_AST_EXPR_ANON_ARRAY_LIT: {
spl_lang_type_id_t elem_tid = 0;
for (usize i = 0; i < vec_size(n->anon_array_literal.elems); ++i) {
spl_lang_type_id_t et = sema_parse(sema, vec_at(n->anon_array_literal.elems, i));
if (elem_tid == 0)
elem_tid = et;
else if (sema_coerce(sema, elem_tid, et) == 0) {
SPL_ERROR(&n->dbg, "array element type mismatch");
sema->error_count++;
}
}
usize len = vec_size(n->anon_array_literal.elems);
spl_lang_type_id_t arr_tid = spl_lang_make_array(sema->type, elem_tid, len);
n->resolved_type_id = arr_tid;
return arr_tid;
}
case SPL_AST_EXPR_AGGREGATE_LIT: {
const char *type_name = n->aggregate_literal.name;
if (!type_name) {
SPL_ERROR(&n->dbg, "anonymous aggregate literal not supported yet");
sema->error_count++;
return 0;
}
spl_symbol_t sym;
if (!spl_scope_find(sema->scope, type_name, &sym)) {
SPL_ERROR(&n->dbg, "unknown type `%s`", type_name);
sema->error_count++;
return 0;
}
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
if (!def || !def->lang_id) {
SPL_ERROR(&n->dbg, "type `%s` not resolved", type_name);
sema->error_count++;
return 0;
}
spl_lang_type_id_t agg_lang = def->lang_id;
spl_lang_type_node_t *agg_node = spl_lang_type_node(sema->type, agg_lang);
if (!agg_node ||
(agg_node->kind != SPL_LANG_TYPE_STRUCT && agg_node->kind != SPL_LANG_TYPE_UNION)) {
SPL_ERROR(&n->dbg, "`%s` is not a struct/union", type_name);
sema->error_count++;
return 0;
}
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang);
for (usize i = 0; i < vec_size(n->aggregate_literal.fields); ++i) {
spl_ast_node_t *item = spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, i));
if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM)
continue;
const char *fname = item->struct_init_item.name;
spl_lang_type_id_t field_lang = 0;
if (item->struct_init_item.expr) {
field_lang = sema_parse(sema, item->struct_init_item.expr);
}
const spl_type_member_t *member = spl_type_agg_member(sema->type, agg_ir, fname);
if (!member) {
SPL_ERROR(&item->dbg, "no field `%s` in `%s`", fname, type_name);
sema->error_count++;
continue;
}
// 映射到底层类型对应的语言级类型
spl_lang_type_id_t expected_lang = 0;
for (usize j = 1; j < vec_size(sema->type->lang_table); ++j) {
spl_lang_type_node_t *ln = &vec_at(sema->type->lang_table, j);
if (ln->ir_type_id == member->type_id) {
expected_lang = j;
break;
}
}
if (!expected_lang) {
SPL_ERROR(&item->dbg, "cannot resolve field type for `%s`", fname);
sema->error_count++;
continue;
}
if (sema_coerce(sema, expected_lang, field_lang) == 0) {
SPL_ERROR(&item->dbg, "field `%s` type mismatch", fname);
sema->error_count++;
}
}
n->resolved_type_id = agg_lang;
return agg_lang;
}
case SPL_AST_EXPR_COMPTIME_CALL:
return 0;
case SPL_AST_EXPR_BLOCK: {
for (usize i = 0; i < vec_size(n->block.stmts); ++i) {
sema_parse(sema, vec_at(n->block.stmts, i));
}
if (n->block.tail_expr) {
return sema_parse(sema, n->block.tail_expr);
}
return 0;
}
case SPL_AST_EXPR_IF: {
spl_lang_type_id_t cond_tid = sema_parse(sema, n->if_expr.cond);
if (!sema_coerce_for_bool(sema, cond_tid)) {
SPL_ERROR(&n->dbg, "if condition must be bool");
sema->error_count++;
}
sema_parse(sema, n->if_expr.then_block);
if (n->if_expr.else_branch) {
sema_parse(sema, n->if_expr.else_branch);
}
return 0;
}
case SPL_AST_EXPR_IFVAR: {
sema_parse(sema, n->ifvar_expr.var_decl);
sema_parse(sema, n->ifvar_expr.then_block);
if (n->ifvar_expr.else_branch) {
sema_parse(sema, n->ifvar_expr.else_branch);
}
return 0;
}
case SPL_AST_EXPR_WHILE: {
spl_lang_type_id_t cond_tid = sema_parse(sema, n->while_expr.cond);
if (!sema_coerce_for_bool(sema, cond_tid)) {
SPL_ERROR(&n->dbg, "while condition must be bool");
sema->error_count++;
}
sema_parse(sema, n->while_expr.body);
if (n->while_expr.else_branch) {
sema_parse(sema, n->while_expr.else_branch);
}
return 0;
}
case SPL_AST_EXPR_LOOP: {
sema_parse(sema, n->loop_expr.body);
return 0;
}
case SPL_AST_EXPR_FOR: {
sema_push_scope(sema);
for (usize i = 0; i < vec_size(n->for_expr.iter_exprs); ++i) {
spl_lang_type_id_t container_tid = sema_parse(sema, vec_at(n->for_expr.iter_exprs, i));
spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid);
if (i < vec_size(n->for_expr.idents)) {
spl_ast_node_t *id_node = spl_ast_node(sema->ast, vec_at(n->for_expr.idents, i));
if (id_node && id_node->kind == SPL_AST_EXPR_IDENT) {
const char *var_name = id_node->ident.name;
if (strcmp(var_name, "_") != 0) {
spl_symbol_t sym = {.name = var_name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, var_name, id_node->dbg,
vec_at(n->for_expr.idents, i));
spl_def_resolve(sema->type, sym.node, elem_tid);
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
id_node->resolved_def_id = sym.node;
}
}
}
}
sema_parse(sema, n->for_expr.body);
if (n->for_expr.else_branch) {
sema_parse(sema, n->for_expr.else_branch);
}
sema_pop_scope(sema);
return 0;
}
case SPL_AST_EXPR_MATCH: {
sema_parse(sema, n->match_expr.matched_expr);
for (usize i = 0; i < vec_size(n->match_expr.arms); ++i) {
spl_ast_node_t *arm = spl_ast_node(sema->ast, vec_at(n->match_expr.arms, i));
if (arm && arm->kind == SPL_AST_MATCH_ARM) {
sema_parse(sema, arm->match_arm.pattern);
sema_parse(sema, arm->match_arm.body);
}
}
return 0;
}
case SPL_AST_EXPR_FN_TYPE: {
spl_lang_type_id_vec_t params;
vec_init(params);
for (usize i = 0; i < vec_size(n->fn_type.params); ++i) {
vec_push(params, sema_parse(sema, vec_at(n->fn_type.params, i)));
}
spl_lang_type_id_t ret_tid = sema_parse(sema, n->fn_type.ret_type);
spl_lang_type_id_t fn_tid =
spl_lang_make_fn(sema->type, ret_tid, vec_unsafe_get_data(params), vec_size(params));
vec_free(params);
n->resolved_type_id = fn_tid;
return fn_tid;
}
case SPL_AST_TYPE_PATH: {
const char *name = n->type_path.name;
spl_lang_type_id_t builtin = spl_type_lookup_builtin(sema->type, name);
if (builtin != 0) {
n->resolved_type_id = builtin;
return builtin;
}
spl_symbol_t sym;
if (!spl_scope_find(sema->scope, name, &sym)) {
SPL_ERROR(&n->dbg, "type `%s` not found", name);
sema->error_count++;
return 0;
}
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
if (!def || !def->lang_id)
return 0;
n->resolved_type_id = def->lang_id;
return def->lang_id;
}
case SPL_AST_TYPE_POINTER: {
spl_lang_type_id_t pointee_tid = sema_parse(sema, n->type_pointer.pointee);
spl_lang_type_id_t ptr_tid = spl_lang_make_ptr(sema->type, pointee_tid);
n->resolved_type_id = ptr_tid;
return ptr_tid;
}
case SPL_AST_TYPE_ARRAY: {
spl_lang_type_id_t elem_tid = sema_parse(sema, n->type_array.elem_type);
usize len = n->type_array.has_len ? (usize)n->type_array.len : 0;
spl_lang_type_id_t arr_tid = spl_lang_make_array(sema->type, elem_tid, len);
n->resolved_type_id = arr_tid;
return arr_tid;
}
case SPL_AST_TYPE_SLICE: {
spl_lang_type_id_t elem_tid = sema_parse(sema, n->type_slice.elem_type);
spl_lang_type_id_t slice_tid = spl_lang_make_slice(sema->type, elem_tid);
n->resolved_type_id = slice_tid;
return slice_tid;
}
case SPL_AST_TYPE_FN: {
spl_lang_type_id_vec_t params;
vec_init(params);
for (usize i = 0; i < vec_size(n->type_fn.params); ++i) {
vec_push(params, sema_parse(sema, vec_at(n->type_fn.params, i)));
}
spl_lang_type_id_t ret_tid = sema_parse(sema, n->type_fn.ret_type);
spl_lang_type_id_t fn_tid =
spl_lang_make_fn(sema->type, ret_tid, vec_unsafe_get_data(params), vec_size(params));
vec_free(params);
n->resolved_type_id = fn_tid;
return fn_tid;
}
case SPL_AST_TYPE_PAREN: {
usize count = vec_size(n->type_paren.types);
if (count == 0) {
spl_lang_type_id_t unit = spl_lang_make_unit(sema->type);
n->resolved_type_id = unit;
return unit;
}
if (count == 1) {
return sema_parse(sema, vec_at(n->type_paren.types, 0));
}
spl_lang_type_id_vec_t elems;
vec_init(elems);
for (usize i = 0; i < count; ++i) {
vec_push(elems, sema_parse(sema, vec_at(n->type_paren.types, i)));
}
spl_lang_type_id_t tuple =
spl_lang_make_tuple(sema->type, vec_unsafe_get_data(elems), vec_size(elems));
vec_free(elems);
n->resolved_type_id = tuple;
return tuple;
}
case SPL_AST_TYPE_AGGREGATE: {
return 0;
}
case SPL_AST_TYPE_COMPTIME_CALL:
return 0;
case SPL_AST_STATEMENT_RET: {
if (n->statement_ret.expr) {
spl_lang_type_id_t ret_tid = sema_parse(sema, n->statement_ret.expr);
if (sema->current_fn_ret_tid != 0 &&
sema_coerce(sema, sema->current_fn_ret_tid, ret_tid) == 0) {
SPL_ERROR(&n->dbg, "return type mismatch");
sema->error_count++;
}
}
return 0;
}
case SPL_AST_STATEMENT_BREAK:
case SPL_AST_STATEMENT_CONTINUE:
return 0;
case SPL_AST_STATEMENT_DEFER:
if (n->statement_defer.body) {
sema_parse(sema, n->statement_defer.body);
}
return 0;
case SPL_AST_STATEMENT_COMPTIME:
if (n->statement_comptime.body) {
sema_parse(sema, n->statement_comptime.body);
}
return 0;
case SPL_AST_STATEMENT_DECL:
if (n->statement_decl.decl) {
sema_parse(sema, n->statement_decl.decl);
}
return 0;
case SPL_AST_STATEMENT_EXPR:
if (n->statement_expr.expr) {
sema_parse(sema, n->statement_expr.expr);
}
return 0;
default:
return 0;
}
return 0;
}
void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope) {
sema->ast = ast;
sema->type = type;
sema->scope = scope;
sema->error_count = 0;
sema->current_fn_ret_tid = 0;
sema->root = (spl_symbol_t){0};
sema->store_scope = 0;
}
void spl_sema_drop(spl_sema_t *sema) { (void)sema; }
void spl_sema_run(spl_sema_t *sema) {
if (!sema->ast || !sema->ast->root)
return;
spl_ast_node_t *root = spl_ast_node(sema->ast, sema->ast->root);
if (!root || root->kind != SPL_AST_ROOT)
return;
sema_collect(sema, root->root.members);
sema_parse(sema, root->root.members);
}
void spl_sema_dump(spl_sema_t *sema) {
printf("Scopes:\n");
for (usize i = 1; i < vec_size(sema->scope->scopes); ++i) {
spl_scope_node_t *scope = &vec_at(sema->scope->scopes, i);
printf("scope[%zu] parent=%zu\n", i, scope->parent);
map_for(scope->symbols, j) {
spl_symbol_t *symbol = &unsafe_map_at(scope->symbols, j).val;
printf(" %s -> def`%s`#%zu\n", unsafe_map_at(scope->symbols, j).key, symbol->name,
symbol->node);
}
}
printf("LangTypeTable:\n");
for (usize i = 1; i < vec_size(sema->type->lang_table); ++i) {
printf(" lang_id#%zu ", i);
spl_lang_type_dump(sema->type, i);
printf("\n");
}
printf("TypeTable:\n");
for (usize i = 1; i < vec_size(sema->type->type_table); ++i) {
printf(" type_id#%zu ", i);
spl_type_pure_dump(sema->type, i);
printf("\n");
}
printf("DefTable:\n");
for (usize i = 1; i < vec_size(sema->type->def_table); ++i) {
printf(" def#%zu ", i);
spl_type_def_dump(sema->type, i);
printf("\n");
}
}