#include "spl_sema.h" #include "spl_intrin.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 spl_ast_node_ref_vec_t *node_attr_list(spl_ast_node_t *n) { switch (n->kind) { case SPL_AST_FN_DECL: return &n->fn_decl.tag_list; case SPL_AST_VAR_DECL: case SPL_AST_CONST_DECL: return &n->var_const_decl.attr_list; case SPL_AST_TYPE_DECL: return &n->type_decl.attr_list; case SPL_AST_PARAM_DECL: return &n->param_decl.attr_list; case SPL_AST_MEMBER_DECL: return &n->member_decl.attr_list; case SPL_AST_TOP_LEVEL_BLOCK: return &n->top_level_block.tag_list; default: return NULL; } } static void sema_resolve_attrs(spl_sema_t *sema, spl_ast_node_ref_vec_t *raw, spl_attr_id_vec_t *out) { for (usize i = 0; i < vec_size(*raw); ++i) { spl_ast_node_ref_t aref = vec_at(*raw, i); spl_ast_node_t *a = spl_ast_node(sema->ast, aref); if (!a || (a->kind != SPL_AST_TAG_ITEM && a->kind != SPL_AST_EXTERNAL_TAG_ITEM)) continue; spl_attr_info_t *info = spl_attr_lookup(sema->attr, NULL, a->tag_item.name); if (!info) { SPL_ERROR(&a->dbg, "unknown attribute `%s`", a->tag_item.name); sema->error_count++; continue; } usize nargs = vec_size(a->tag_item.args); if ((int)nargs < info->min_args || (info->max_args >= 0 && (int)nargs > info->max_args)) { SPL_ERROR(&a->dbg, "attribute `%s` expects %d..%d args, got %zu", info->name, info->min_args, info->max_args, nargs); sema->error_count++; continue; } spl_attr_arg_vec_t args; vec_init(args); int bad = 0; for (usize j = 0; j < nargs; ++j) { spl_ast_node_t *arg = spl_ast_node(sema->ast, vec_at(a->tag_item.args, j)); spl_attr_arg_t oa = {0}; if (!arg) { bad = 1; break; } switch (arg->kind) { case SPL_AST_EXPR_IDENT: oa.kind = SPL_ATTR_ARG_STR; oa.value.s = arg->ident.name; break; case SPL_AST_EXPR_STRING_LIT: oa.kind = SPL_ATTR_ARG_STR; oa.value.s = arg->string_lit.data; break; case SPL_AST_EXPR_INT_LIT: oa.kind = SPL_ATTR_ARG_INT; oa.value.i = arg->int_lit.val; break; default: SPL_ERROR(&a->dbg, "attribute arg #%zu has unsupported form", j); sema->error_count++; bad = 1; break; } if (bad) break; vec_push(args, oa); } if (bad) { vec_free(args); continue; } spl_attr_id_t id = spl_attr_alloc(sema->attr, info, args); vec_push(*out, id); } } static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref); static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref); static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_lang_type_id_t expected); static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in, spl_ast_node_ref_vec_t *args); static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in); static bool sema_is_infer(spl_sema_t *sema, spl_lang_type_id_t tid) { spl_lang_type_node_t *n = spl_lang_type_node(sema->type, tid); return n && n->kind == SPL_LANG_TYPE_INFER; } static spl_lang_type_id_t sema_lang_from_ir(spl_sema_t *sema, spl_type_id_t ir) { 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 == ir) return i; } return 0; } static bool sema_is_literal(spl_ast_node_t *n) { switch (n->kind) { case SPL_AST_EXPR_INT_LIT: case SPL_AST_EXPR_FLOAT_LIT: case SPL_AST_EXPR_CHAR_LIT: case SPL_AST_EXPR_STRING_LIT: case SPL_AST_EXPR_BOOL_LIT: case SPL_AST_EXPR_NULL_LIT: case SPL_AST_EXPR_UNDEFINED_LIT: return true; default: 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_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: { /* root_scope 只在第一次创建,后续 module 复用 */ if (sema->scope->root_scope == 0) { spl_scope_id_t root = spl_scope_alloc(sema->scope); sema->scope->root_scope = root; } /* 进入 root_scope,再为当前 module 开一个子 scope */ sema->scope->current_scope = sema->scope->root_scope; spl_scope_id_t mod_scope = spl_scope_alloc(sema->scope); sema->scope->current_scope = mod_scope; 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_insert(sema->scope, mod_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)); } /* 故意不恢复 current_scope 保持 mod_scope 交给随后的 sema_parse 使用。 恢复由 spl_sema_run_module 统一负责 */ 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_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in, spl_ast_node_ref_vec_t *args) { const spl_intrin_info_t *info = spl_intrin_info(in); usize nargs = vec_size(*args); if ((int)nargs < info->min_args || (info->max_args >= 0 && (int)nargs > info->max_args)) { SPL_ERROR(&n->dbg, "`%s` expects %d..%d args, got %zu", info->name, info->min_args, info->max_args, nargs); sema->error_count++; return 0; } switch (in) { case SPL_INTRIN_SIZEOF: case SPL_INTRIN_ALIGNOF: { sema_infer(sema, vec_at(*args, 0)); /* 求类型表达式的值 */ return spl_lang_make_int(sema->type, sizeof(void *) * 8, 0); } case SPL_INTRIN_ASSERT: { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); sema_check(sema, vec_at(*args, 0), bt); if (nargs == 2) sema_infer(sema, vec_at(*args, 1)); return spl_lang_make_unit(sema->type); } default: UNREACHABLE(); } return 0; } static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in) { const spl_intrin_info_t *info = spl_intrin_info(in); switch (info->result) { case SPL_INTRIN_RESULT_USIZE: return spl_lang_make_int(sema->type, sizeof(void *) * 8, 0); case SPL_INTRIN_RESULT_BOOL: return spl_lang_make_bool(sema->type); case SPL_INTRIN_RESULT_UNIT: return spl_lang_make_unit(sema->type); default: UNREACHABLE(); } (void)n; return 0; } static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_lang_type_id_t expected) { if (!ref || !expected) return 0; spl_ast_node_t *n = spl_ast_node(sema->ast, ref); if (!n) return 0; /* ============ 类 1:构造性节点 —— 就地定型为 expected ============ */ switch (n->kind) { case SPL_AST_EXPR_UNARY: { if (n->unary.op == SPL_UNARY_OP_ADDRESS) return sema_infer(sema, ref); /* &x 没有"被 check 到某类型"的语义 */ if (!sema_check(sema, n->unary.operand, expected)) return 0; n->resolved_lang_tid = expected; n->expected_lang_tid = 0; return expected; } case SPL_AST_EXPR_BINARY: { spl_binary_op_t op = n->binary.op; /* 赋值 / 复合赋值:右侧 check 到左侧类型 */ if (op == SPL_OP_ASSIGN || (op >= SPL_OP_ASSIGN_ADD && op <= SPL_OP_ASSIGN_RSHIFT)) { spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); if (!lt) return 0; if (!sema_check(sema, n->binary.right, lt)) return 0; n->resolved_lang_tid = lt; n->expected_lang_tid = 0; return lt; } /* 逻辑运算:两侧 check 到 bool */ if (op == SPL_OP_BOOL_OR || op == SPL_OP_BOOL_AND) { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); if (!sema_check(sema, n->binary.left, bt)) return 0; if (!sema_check(sema, n->binary.right, bt)) return 0; n->resolved_lang_tid = bt; n->expected_lang_tid = 0; return bt; } if (op == SPL_OP_CMP_EQ || op == SPL_OP_CMP_NE || op == SPL_OP_CMP_LT || op == SPL_OP_CMP_LE || op == SPL_OP_CMP_GT || op == SPL_OP_CMP_GE) { /* 比较:结果 bool,节点存操作数类型;不依赖 expected */ spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); spl_lang_type_id_t rt = sema_infer(sema, n->binary.right); if (!lt || !rt) return 0; spl_lang_type_id_t common = 0; if (lt == rt) common = lt; else common = spl_lang_type_balance(sema->type, lt, rt); if (!common) { SPL_ERROR(&n->dbg, "comparison operands type mismatch"); sema->error_count++; return 0; } sema_check(sema, n->binary.left, common); sema_check(sema, n->binary.right, common); n->resolved_lang_tid = common; return spl_lang_make_bool(sema->type); } /* 算术 / 位 / 移位:两侧 check 到 expected */ if (!sema_check(sema, n->binary.left, expected)) return 0; if (!sema_check(sema, n->binary.right, expected)) return 0; n->resolved_lang_tid = expected; n->expected_lang_tid = 0; return expected; } case SPL_AST_EXPR_ARRAY_LIT: { spl_lang_type_node_t *en = spl_lang_type_node(sema->type, expected); if (en && en->kind == SPL_LANG_TYPE_ARRAY) { spl_lang_type_id_t et = en->extra.elem; for (usize i = 0; i < vec_size(n->array_literal.elems); ++i) if (!sema_check(sema, vec_at(n->array_literal.elems, i), et)) return 0; n->resolved_lang_tid = expected; n->expected_lang_tid = 0; return expected; } break; /* 非数组 expected:退回通用逻辑 */ } case SPL_AST_EXPR_AGGREGATE_LIT: { spl_lang_type_node_t *en = spl_lang_type_node(sema->type, expected); if (!en || (en->kind != SPL_LANG_TYPE_STRUCT && en->kind != SPL_LANG_TYPE_UNION)) break; if (n->aggregate_literal.name) { spl_symbol_t sym; if (!spl_scope_find(sema->scope, n->aggregate_literal.name, &sym)) { SPL_ERROR(&n->dbg, "unknown type `%s`", n->aggregate_literal.name); sema->error_count++; return 0; } spl_def_node_t *def = spl_def_node(sema->type, sym.node); if (!def || def->lang_id != expected) { SPL_ERROR(&n->dbg, "aggregate `%s` does not match expected type", n->aggregate_literal.name); sema->error_count++; return 0; } } spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, expected); spl_type_node_t *irn = spl_type_node(sema->type, agg_ir); if (!irn) return 0; usize nfields = vec_size(irn->agg_type.variants); bool *seen = calloc(nfields ? nfields : 1, sizeof(bool)); 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; usize idx = 0; if (!spl_type_agg_member_idx(sema->type, agg_ir, item->struct_init_item.name, &idx)) { SPL_ERROR(&item->dbg, "no field `%s`", item->struct_init_item.name); sema->error_count++; continue; } if (seen[idx]) { SPL_ERROR(&item->dbg, "duplicate field `%s`", item->struct_init_item.name); sema->error_count++; continue; } seen[idx] = true; spl_type_member_t *m = &vec_at(irn->agg_type.variants, idx); spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id); if (!ft) continue; if (!item->struct_init_item.expr) { SPL_ERROR(&item->dbg, "field `%s` requires initializer", item->struct_init_item.name); sema->error_count++; continue; } sema_check(sema, item->struct_init_item.expr, ft); } for (usize i = 0; i < nfields; ++i) { if (!seen[i]) { SPL_ERROR(&n->dbg, "missing field `%s`", vec_at(irn->agg_type.variants, i).name); sema->error_count++; } } free(seen); n->resolved_lang_tid = expected; n->expected_lang_tid = 0; return expected; } case SPL_AST_EXPR_IF: { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); sema_check(sema, n->if_expr.cond, bt); if (n->if_expr.then_block) sema_check(sema, n->if_expr.then_block, expected); if (n->if_expr.else_branch) sema_check(sema, n->if_expr.else_branch, expected); n->resolved_lang_tid = expected; n->expected_lang_tid = 0; return expected; } case SPL_AST_EXPR_BLOCK: { for (usize i = 0; i < vec_size(n->block.stmts); ++i) sema_infer(sema, vec_at(n->block.stmts, i)); if (n->block.tail_expr) { spl_lang_type_id_t t = sema_check(sema, n->block.tail_expr, expected); if (!t) return 0; n->resolved_lang_tid = t; n->expected_lang_tid = 0; return t; } spl_lang_type_id_t u = spl_lang_make_unit(sema->type); n->resolved_lang_tid = u; n->expected_lang_tid = 0; return u; } default: break; } /* ============ 类 2:字面量 —— 就地定型 ============ */ if (sema_is_literal(n)) { spl_lang_type_id_t from = n->resolved_lang_tid; if (!from) { from = sema_infer(sema, ref); if (!from) return 0; } if (from == expected) return expected; spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, expected, from); if (!r) { SPL_ERROR(&n->dbg, "literal cannot coerce to expected type"); sema->error_count++; return 0; } n->resolved_lang_tid = r; n->expected_lang_tid = 0; return r; } /* ============ 类 3:引用性节点 —— 只记 expected ============ */ { spl_lang_type_id_t from = sema_infer(sema, ref); if (!from) return 0; if (from == expected) { n->expected_lang_tid = 0; return expected; } spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, expected, from); if (!r) { SPL_ERROR(&n->dbg, "type mismatch: cannot coerce to expected type"); sema->error_count++; return 0; } n->expected_lang_tid = expected; /* 只记,不改 natural */ return expected; } } static spl_lang_type_id_t sema_infer(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; spl_ast_node_ref_vec_t *raw = node_attr_list(n); if (raw && vec_size(*raw) > 0) sema_resolve_attrs(sema, raw, &n->attrs); switch (n->kind) { /* ---------- 字面量 ---------- */ case SPL_AST_EXPR_INT_LIT: { spl_lang_type_id_t t = spl_lang_make_int(sema->type, 0, 1); /* comptime_int */ n->resolved_lang_tid = t; return t; } case SPL_AST_EXPR_FLOAT_LIT: { spl_lang_type_id_t t = spl_lang_make_float(sema->type, 0); /* comptime_float */ n->resolved_lang_tid = t; return t; } case SPL_AST_EXPR_CHAR_LIT: { spl_lang_type_id_t t = spl_lang_make_int(sema->type, 8, 0); n->resolved_lang_tid = t; return t; } 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 s = spl_lang_make_slice(sema->type, u8); n->resolved_lang_tid = s; return s; } case SPL_AST_EXPR_BOOL_LIT: { spl_lang_type_id_t t = spl_lang_make_bool(sema->type); n->resolved_lang_tid = t; return t; } case SPL_AST_EXPR_NULL_LIT: { spl_lang_type_id_t nv = spl_lang_make_never(sema->type); spl_lang_type_id_t p = spl_lang_make_ptr(sema->type, nv); n->resolved_lang_tid = p; return p; } case SPL_AST_EXPR_UNDEFINED_LIT: { spl_lang_type_id_t t = spl_lang_make_never(sema->type); n->resolved_lang_tid = t; return t; } /* ---------- IDENT:同时写 def_id 和 lang_tid 副本 ---------- */ 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; } n->resolved_lang_tid = def->lang_id; return def->lang_id; } /* ---------- UNARY ---------- */ case SPL_AST_EXPR_UNARY: { spl_lang_type_id_t op = sema_infer(sema, n->unary.operand); if (op == 0) return 0; spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, op); 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_lang_tid = op; return op; 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_lang_tid = op; return op; case SPL_UNARY_OP_NOT: { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); sema_check(sema, n->unary.operand, bt); n->resolved_lang_tid = bt; return bt; } case SPL_UNARY_OP_ADDRESS: { spl_lang_type_id_t p = spl_lang_make_ptr(sema->type, op); n->resolved_lang_tid = p; return p; } default: UNREACHABLE(); } } /* ---------- BINARY ---------- */ case SPL_AST_EXPR_BINARY: { spl_binary_op_t op = n->binary.op; /* 赋值 / 复合赋值 */ if (op == SPL_OP_ASSIGN || (op >= SPL_OP_ASSIGN_ADD && op <= SPL_OP_ASSIGN_RSHIFT)) { spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); if (!lt) return 0; sema_check(sema, n->binary.right, lt); n->resolved_lang_tid = lt; return lt; } /* 逻辑 */ if (op == SPL_OP_BOOL_OR || op == SPL_OP_BOOL_AND) { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); sema_check(sema, n->binary.left, bt); sema_check(sema, n->binary.right, bt); n->resolved_lang_tid = bt; return bt; } if (op == SPL_OP_CMP_EQ || op == SPL_OP_CMP_NE || op == SPL_OP_CMP_LT || op == SPL_OP_CMP_LE || op == SPL_OP_CMP_GT || op == SPL_OP_CMP_GE) { spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); spl_lang_type_id_t rt = sema_infer(sema, n->binary.right); if (!lt || !rt) return 0; spl_lang_type_id_t common = 0; if (lt == rt) common = lt; else common = spl_lang_type_balance(sema->type, lt, rt); if (!common) { SPL_ERROR(&n->dbg, "comparison operands type mismatch"); sema->error_count++; return 0; } sema_check(sema, n->binary.left, common); sema_check(sema, n->binary.right, common); n->resolved_lang_tid = common; return spl_lang_make_bool(sema->type); } /* Range */ if (op == SPL_OP_RANGE) { sema_infer(sema, n->binary.left); sema_infer(sema, n->binary.right); spl_lang_type_id_t i64 = spl_lang_make_int(sema->type, 64, 1); spl_lang_type_id_t r = spl_lang_make_range(sema->type, i64); n->resolved_lang_tid = r; return r; } /* 移位:结果 = 左类型 */ if (op == SPL_OP_LSHIFT || op == SPL_OP_RSHIFT) { spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); if (!lt) return 0; spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt); if (!ln || ln->kind != SPL_LANG_TYPE_INT) { SPL_ERROR(&n->dbg, "shift requires integer operands"); sema->error_count++; return 0; } sema_infer(sema, n->binary.right); n->resolved_lang_tid = lt; return lt; } /* 算术 / 位运算 */ spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); spl_lang_type_id_t rt = sema_infer(sema, n->binary.right); if (!lt || !rt) return 0; spl_lang_type_id_t common = 0; if (lt == rt) common = lt; else common = spl_lang_type_balance(sema->type, lt, rt); /* balance 失败:comptime + 具体时取具体 */ if (!common) { 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_type_node_t *lir = spl_type_node(sema->type, ln->ir_type_id); spl_type_node_t *rir = spl_type_node(sema->type, rn->ir_type_id); if (lir && lir->int_type.bits == 0) common = rt; else if (rir && rir->int_type.bits == 0) common = lt; } else if (ln && ln->kind == SPL_LANG_TYPE_FLOAT && rn && rn->kind == SPL_LANG_TYPE_FLOAT) { spl_type_node_t *lir = spl_type_node(sema->type, ln->ir_type_id); spl_type_node_t *rir = spl_type_node(sema->type, rn->ir_type_id); if (lir && lir->float_type.bits == 0) common = rt; else if (rir && rir->float_type.bits == 0) common = lt; } } if (!common) { SPL_ERROR(&n->dbg, "arithmetic operands type mismatch"); sema->error_count++; return 0; } sema_check(sema, n->binary.left, common); sema_check(sema, n->binary.right, common); n->resolved_lang_tid = common; return common; } /* ---------- CALL ---------- */ case SPL_AST_EXPR_CALL: { spl_ast_node_t *callee = spl_ast_node(sema->ast, n->call.callee); if (callee && callee->kind == SPL_AST_EXPR_IDENT) { spl_intrin_t in = spl_intrin_lookup_call(callee->ident.name); if (in != SPL_INTRIN_NONE) { spl_lang_type_id_t t = sema_intrin_call(sema, n, in, &n->call.args); n->resolved_lang_tid = t; return t; } } spl_lang_type_id_t callee_tid = sema_infer(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; } bool has_varargs = false; usize fixed = vec_size(fn->extra.fn.params); if (fixed > 0) { spl_lang_type_id_t last = vec_at(fn->extra.fn.params, fixed - 1); spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, last); if (ln && ln->kind == SPL_LANG_TYPE_VARARGS) { has_varargs = true; fixed--; } } usize nargs = vec_size(n->call.args); if (has_varargs) { if (nargs < fixed) { SPL_ERROR(&n->dbg, "too few arguments (expected at least %zu)", fixed); sema->error_count++; } } else if (nargs != fixed) { SPL_ERROR(&n->dbg, "argument count mismatch (expected %zu, got %zu)", fixed, nargs); sema->error_count++; } /* 固定参数:check 到形参类型 */ for (usize i = 0; i < nargs && i < fixed; ++i) { spl_lang_type_id_t pt = vec_at(fn->extra.fn.params, i); sema_check(sema, vec_at(n->call.args, i), pt); } /* varargs:默认提升到 isize */ if (has_varargs) { spl_lang_type_id_t vt = spl_lang_make_int(sema->type, sizeof(void *) * 8, 1); for (usize i = fixed; i < nargs; ++i) sema_check(sema, vec_at(n->call.args, i), vt); } spl_lang_type_id_t ret = fn->extra.fn.ret; n->resolved_lang_tid = ret; return ret; } /* ---------- FIELD ---------- */ case SPL_AST_EXPR_FIELD: { spl_lang_type_id_t obj_tid = sema_infer(sema, n->field.obj); spl_lang_type_node_t *obj = spl_lang_type_node(sema->type, obj_tid); if (!obj) return 0; spl_intrin_t in = spl_intrin_lookup_field(obj->kind, n->field.field); if (in != SPL_INTRIN_NONE) { spl_lang_type_id_t t = sema_intrin_field(sema, n, in); n->resolved_lang_tid = t; return t; } spl_lang_type_id_t agg_lang = obj_tid; if (obj->kind == SPL_LANG_TYPE_PTR) agg_lang = obj->extra.elem; spl_lang_type_node_t *agg = spl_lang_type_node(sema->type, agg_lang); if (!agg || (agg->kind != SPL_LANG_TYPE_STRUCT && agg->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 *m = spl_type_agg_member(sema->type, agg_ir, n->field.field); if (!m) { SPL_ERROR(&n->dbg, "no field `%s`", n->field.field); sema->error_count++; return 0; } spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id); if (!ft) { SPL_ERROR(&n->dbg, "cannot resolve field type"); sema->error_count++; return 0; } n->resolved_lang_tid = ft; return ft; } /* ---------- INDEX ---------- */ case SPL_AST_EXPR_INDEX: { spl_lang_type_id_t obj_tid = sema_infer(sema, n->index.obj); sema_infer(sema, n->index.index); spl_lang_type_node_t *obj = spl_lang_type_node(sema->type, obj_tid); if (!obj) return 0; spl_lang_type_id_t elem = 0; switch (obj->kind) { case SPL_LANG_TYPE_ARRAY: case SPL_LANG_TYPE_SLICE: case SPL_LANG_TYPE_RANGE: case SPL_LANG_TYPE_PTR: elem = obj->extra.elem; break; case SPL_LANG_TYPE_TUPLE: if (vec_size(obj->extra.elems) > 0) elem = vec_at(obj->extra.elems, 0); break; default: SPL_ERROR(&n->dbg, "index base must be array/slice/ptr/range/tuple"); sema->error_count++; return 0; } n->resolved_lang_tid = elem; return elem; } /* ---------- SLICE ---------- */ case SPL_AST_EXPR_SLICE: { spl_lang_type_id_t obj_tid = sema_infer(sema, n->slice.obj); if (n->slice.begin) sema_infer(sema, n->slice.begin); if (n->slice.end) sema_infer(sema, n->slice.end); spl_lang_type_node_t *obj = spl_lang_type_node(sema->type, obj_tid); if (!obj) return 0; spl_lang_type_id_t elem = 0; if (obj->kind == SPL_LANG_TYPE_ARRAY || obj->kind == SPL_LANG_TYPE_PTR || obj->kind == SPL_LANG_TYPE_SLICE) { elem = obj->extra.elem; } else { SPL_ERROR(&n->dbg, "slice base must be array/ptr/slice"); sema->error_count++; return 0; } spl_lang_type_id_t s = spl_lang_make_slice(sema->type, elem); n->resolved_lang_tid = s; return s; } /* ---------- CAST ---------- */ case SPL_AST_EXPR_CAST: { spl_lang_type_id_t src = sema_infer(sema, n->cast.expr); spl_lang_type_id_t dst = sema_infer(sema, n->cast.type); if (!src || !dst) return 0; spl_lang_type_node_t *sn = spl_lang_type_node(sema->type, src); if (sn && !(sn->kind == SPL_LANG_TYPE_INT || sn->kind == SPL_LANG_TYPE_FLOAT || sn->kind == SPL_LANG_TYPE_BOOL || sn->kind == SPL_LANG_TYPE_PTR)) { SPL_ERROR(&n->dbg, "invalid cast from non-primitive type"); sema->error_count++; return 0; } n->resolved_lang_tid = dst; return dst; } /* ---------- TUPLE ---------- */ case SPL_AST_EXPR_TUPLE: { spl_lang_type_id_vec_t es; vec_init(es); for (usize i = 0; i < vec_size(n->tuple.elems); ++i) vec_push(es, sema_infer(sema, vec_at(n->tuple.elems, i))); spl_lang_type_id_t t = spl_lang_make_tuple(sema->type, vec_unsafe_get_data(es), vec_size(es)); vec_free(es); n->resolved_lang_tid = t; return t; } /* ---------- ARRAY_LIT ---------- */ case SPL_AST_EXPR_ARRAY_LIT: { spl_lang_type_id_t elem_t = 0; if (n->array_literal.elem_type) elem_t = sema_infer(sema, n->array_literal.elem_type); usize nelems = vec_size(n->array_literal.elems); for (usize i = 0; i < nelems; ++i) { spl_lang_type_id_t et = sema_infer(sema, vec_at(n->array_literal.elems, i)); if (!et) return 0; if (elem_t == 0) elem_t = et; else { spl_lang_type_id_t c = spl_lang_type_balance(sema->type, elem_t, et); if (c) elem_t = c; } } if (elem_t == 0) elem_t = spl_lang_make_infer(sema->type); usize len = n->array_literal.is_underscore_len ? nelems : n->array_literal.has_len ? (usize)n->array_literal.len : nelems; spl_lang_type_id_t arr = spl_lang_make_array(sema->type, elem_t, len); n->resolved_lang_tid = arr; return arr; } /* ---------- AGGREGATE_LIT ---------- */ case SPL_AST_EXPR_AGGREGATE_LIT: { const char *type_name = n->aggregate_literal.name; if (!type_name) { spl_lang_type_id_t inf = spl_lang_make_infer(sema->type); n->resolved_lang_tid = inf; return inf; } 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 = def->lang_id; spl_lang_type_node_t *an = spl_lang_type_node(sema->type, agg); if (!an || (an->kind != SPL_LANG_TYPE_STRUCT && an->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); spl_type_node_t *irn = spl_type_node(sema->type, agg_ir); if (irn) { 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; usize idx = 0; if (!spl_type_agg_member_idx(sema->type, agg_ir, item->struct_init_item.name, &idx)) { SPL_ERROR(&item->dbg, "no field `%s`", item->struct_init_item.name); sema->error_count++; continue; } spl_type_member_t *m = &vec_at(irn->agg_type.variants, idx); spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id); if (ft && item->struct_init_item.expr) sema_check(sema, item->struct_init_item.expr, ft); } } n->resolved_lang_tid = agg; return agg; } /* ---------- COMPTIME_CALL ---------- */ case SPL_AST_EXPR_COMPTIME_CALL: { spl_intrin_t in = spl_intrin_lookup_call(n->comptime_call.name); if (in == SPL_INTRIN_NONE) { SPL_ERROR(&n->dbg, "unknown comptime call `@%s`", n->comptime_call.name); sema->error_count++; return 0; } spl_lang_type_id_t t = sema_intrin_call(sema, n, in, &n->comptime_call.args); n->resolved_lang_tid = t; return t; } /* ---------- BLOCK ---------- */ case SPL_AST_EXPR_BLOCK: { spl_lang_type_id_t last = 0; for (usize i = 0; i < vec_size(n->block.stmts); ++i) last = sema_infer(sema, vec_at(n->block.stmts, i)); if (n->block.tail_expr) last = sema_infer(sema, n->block.tail_expr); n->resolved_lang_tid = last; return last; } /* ---------- IF ---------- */ case SPL_AST_EXPR_IF: { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); sema_check(sema, n->if_expr.cond, bt); spl_lang_type_id_t then_t = n->if_expr.then_block ? sema_infer(sema, n->if_expr.then_block) : 0; spl_lang_type_id_t else_t = n->if_expr.else_branch ? sema_infer(sema, n->if_expr.else_branch) : 0; spl_lang_type_id_t result = 0; if (then_t && else_t) result = spl_lang_type_balance(sema->type, then_t, else_t); else result = then_t ? then_t : else_t; n->resolved_lang_tid = result; return result; } /* ---------- IFVAR / WHILE / LOOP / FOR / MATCH ---------- */ case SPL_AST_EXPR_IFVAR: { sema_infer(sema, n->ifvar_expr.var_decl); if (n->ifvar_expr.then_block) sema_infer(sema, n->ifvar_expr.then_block); if (n->ifvar_expr.else_branch) sema_infer(sema, n->ifvar_expr.else_branch); return 0; } case SPL_AST_EXPR_WHILE: { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); sema_check(sema, n->while_expr.cond, bt); if (n->while_expr.body) sema_infer(sema, n->while_expr.body); if (n->while_expr.else_branch) sema_infer(sema, n->while_expr.else_branch); return 0; } case SPL_AST_EXPR_LOOP: { if (n->loop_expr.body) sema_infer(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_infer(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; id_node->resolved_lang_tid = elem_tid; } } } } if (n->for_expr.body) sema_infer(sema, n->for_expr.body); if (n->for_expr.else_branch) sema_infer(sema, n->for_expr.else_branch); sema_pop_scope(sema); return 0; } case SPL_AST_EXPR_MATCH: { sema_infer(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_infer(sema, arm->match_arm.pattern); sema_infer(sema, arm->match_arm.body); } } return 0; } /* ---------- FN_TYPE ---------- */ case SPL_AST_EXPR_FN_TYPE: { spl_lang_type_id_vec_t ps; vec_init(ps); for (usize i = 0; i < vec_size(n->fn_type.params); ++i) vec_push(ps, sema_infer(sema, vec_at(n->fn_type.params, i))); spl_lang_type_id_t ret = sema_infer(sema, n->fn_type.ret_type); spl_lang_type_id_t fn = spl_lang_make_fn(sema->type, ret, vec_unsafe_get_data(ps), vec_size(ps)); vec_free(ps); n->resolved_lang_tid = fn; return fn; } /* ---------- 类型表达式 ---------- */ case SPL_AST_TYPE_PATH: { const char *name = n->type_path.name; spl_lang_type_id_t b = spl_type_lookup_builtin(sema->type, name); if (b) { n->resolved_lang_tid = b; return b; } 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_lang_tid = def->lang_id; return def->lang_id; } case SPL_AST_TYPE_POINTER: { spl_lang_type_id_t p = sema_infer(sema, n->type_pointer.pointee); spl_lang_type_id_t r = spl_lang_make_ptr(sema->type, p); n->resolved_lang_tid = r; return r; } case SPL_AST_TYPE_ARRAY: { spl_lang_type_id_t e = sema_infer(sema, n->type_array.elem_type); usize len = n->type_array.has_len ? (usize)n->type_array.len : 0; spl_lang_type_id_t r = spl_lang_make_array(sema->type, e, len); n->resolved_lang_tid = r; return r; } case SPL_AST_TYPE_SLICE: { spl_lang_type_id_t e = sema_infer(sema, n->type_slice.elem_type); spl_lang_type_id_t r = spl_lang_make_slice(sema->type, e); n->resolved_lang_tid = r; return r; } case SPL_AST_TYPE_FN: { spl_lang_type_id_vec_t ps; vec_init(ps); for (usize i = 0; i < vec_size(n->type_fn.params); ++i) vec_push(ps, sema_infer(sema, vec_at(n->type_fn.params, i))); spl_lang_type_id_t ret = sema_infer(sema, n->type_fn.ret_type); spl_lang_type_id_t r = spl_lang_make_fn(sema->type, ret, vec_unsafe_get_data(ps), vec_size(ps)); vec_free(ps); n->resolved_lang_tid = r; return r; } case SPL_AST_TYPE_PAREN: { usize c = vec_size(n->type_paren.types); if (c == 0) { spl_lang_type_id_t u = spl_lang_make_unit(sema->type); n->resolved_lang_tid = u; return u; } if (c == 1) { spl_lang_type_id_t t = sema_infer(sema, vec_at(n->type_paren.types, 0)); n->resolved_lang_tid = t; return t; } spl_lang_type_id_vec_t es; vec_init(es); for (usize i = 0; i < c; ++i) vec_push(es, sema_infer(sema, vec_at(n->type_paren.types, i))); spl_lang_type_id_t t = spl_lang_make_tuple(sema->type, vec_unsafe_get_data(es), vec_size(es)); vec_free(es); n->resolved_lang_tid = t; return t; } case SPL_AST_TYPE_AGGREGATE: case SPL_AST_TYPE_COMPTIME_CALL: return 0; /* ---------- 顶层声明 ---------- */ case SPL_AST_CONTAINER_MEMBERS: for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) sema_infer(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_infer(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_infer(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)); 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_infer(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_infer(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_infer(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_kind_t lk; switch (tk) { case SPL_TYPE_STRUCT: lk = SPL_LANG_TYPE_STRUCT; break; case SPL_TYPE_UNION: lk = SPL_LANG_TYPE_UNION; break; case SPL_TYPE_ENUM: lk = SPL_LANG_TYPE_ENUM; break; case SPL_TYPE_SHAPE: lk = SPL_LANG_TYPE_SHAPE; break; default: lk = SPL_LANG_TYPE_STRUCT; break; } spl_lang_type_node_t ln = {0}; ln.kind = lk; ln.ir_type_id = agg_ir; spl_lang_type_id_t agg_lang = spl_lang_node_push(sema->type, &ln); spl_def_resolve(sema->type, n->resolved_def_id, agg_lang); n->resolved_lang_tid = agg_lang; 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_infer(sema, vec_at(te->type_aggregate.members, i)); } } else { spl_lang_type_id_t tid = sema_infer(sema, n->type_decl.type_expr); spl_def_resolve(sema->type, n->resolved_def_id, tid); n->resolved_lang_tid = tid; } break; } /* ---------- VAR / CONST ---------- */ 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 = 0; if (n->var_const_decl.type) decl_tid = sema_infer(sema, n->var_const_decl.type); if (!n->var_const_decl.init_expr) { SPL_ERROR(&n->dbg, "variable `%s` must be initialized", name); sema->error_count++; return 0; } if (decl_tid) { sema_check(sema, n->var_const_decl.init_expr, decl_tid); } else { decl_tid = sema_infer(sema, n->var_const_decl.init_expr); if (!decl_tid || sema_is_infer(sema, decl_tid)) { SPL_ERROR(&n->dbg, "cannot infer type of `%s`", name); sema->error_count++; return 0; } } spl_def_resolve(sema->type, n->resolved_def_id, decl_tid); n->resolved_lang_tid = decl_tid; return decl_tid; } /* ---------- MEMBER / PARAM ---------- */ case SPL_AST_MEMBER_DECL: { if (n->member_decl.type_expr) return sema_infer(sema, n->member_decl.type_expr); return 0; } case SPL_AST_PARAM_DECL: { if (n->param_decl.type_expr) return sema_infer(sema, n->param_decl.type_expr); return 0; } /* ---------- 语句 ---------- */ case SPL_AST_STATEMENT_RET: { if (n->statement_ret.expr) { if (sema->current_fn_ret_tid) sema_check(sema, n->statement_ret.expr, sema->current_fn_ret_tid); else sema_infer(sema, n->statement_ret.expr); } else if (sema->current_fn_ret_tid) { spl_lang_type_id_t u = spl_lang_make_unit(sema->type); if (sema->current_fn_ret_tid != u) { SPL_ERROR(&n->dbg, "function must return a value"); 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_infer(sema, n->statement_defer.body); return 0; case SPL_AST_STATEMENT_COMPTIME: if (n->statement_comptime.body) sema_infer(sema, n->statement_comptime.body); return 0; case SPL_AST_STATEMENT_DECL: if (n->statement_decl.decl) sema_infer(sema, n->statement_decl.decl); return 0; case SPL_AST_STATEMENT_EXPR: if (n->statement_expr.expr) sema_infer(sema, n->statement_expr.expr); return 0; case SPL_AST_TOP_LEVEL_BLOCK: if (n->top_level_block.block) sema_infer(sema, n->top_level_block.block); 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, spl_attr_t *attr) { Assert(sema != NULL && ast != NULL && type != NULL && scope != NULL && attr != NULL); sema->ast = ast; sema->type = type; sema->scope = scope; sema->error_count = 0; sema->current_fn_ret_tid = 0; sema->attr = attr; sema->root = (spl_symbol_t){0}; sema->store_scope = 0; } void spl_sema_drop(spl_sema_t *sema) { (void)sema; } void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref) { if (!sema->ast || !module_ref) return; spl_ast_node_t *mod = spl_ast_node(sema->ast, module_ref); if (!mod || mod->kind != SPL_AST_CONTAINER_MEMBERS) return; spl_scope_id_t saved = sema->scope->current_scope; sema_collect(sema, module_ref); sema_infer(sema, module_ref); sema->scope->current_scope = saved; } 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; spl_sema_run_module(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"); } spl_attr_dump(sema->attr); }