stage1 支持更多语法 修复更多问题 暂时stage1功能结束

This commit is contained in:
zzy committed 2026-09-17 13:37:59 +08:00
1 parent 54425a50c7
commit acfbbeee8b
11 files changed
+802 -183

No files matched your search

+398 -113
View File
@@ -97,11 +97,14 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n,
static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in);
static spl_lang_type_id_t sema_eval_decl(spl_sema_t *sema, spl_def_id_t def_id);
static spl_lang_type_id_t sema_infer_fn_signature(spl_sema_t *sema, spl_ast_node_t *n);
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 void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
spl_lang_type_id_t matched_tid);
static void sema_do_type_unpack(spl_sema_t *sema, spl_ast_node_t *decl, spl_ast_node_t *pat,
spl_ast_node_ref_t type_expr_ref);
static void sema_type_unpack_walk(spl_sema_t *sema, spl_ast_node_t *pat,
spl_lang_type_id_t src_lang);
static void sema_type_unpack_one(spl_sema_t *sema, spl_ast_node_t *pat, const char *name,
spl_lang_type_id_t src_lang);
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) {
@@ -112,6 +115,15 @@ static spl_lang_type_id_t sema_lang_from_ir(spl_sema_t *sema, spl_type_id_t ir)
return 0;
}
static spl_lang_type_kind_t sema_lang_kind(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_ERROR;
}
static bool sema_is_infer(spl_sema_t *sema, spl_lang_type_id_t tid) {
return sema_lang_kind(sema, tid) == SPL_LANG_TYPE_INFER;
}
static void sema_type_to_str(spl_sema_t *sema, spl_lang_type_id_t tid, char *buf, usize cap) {
if (!buf || cap == 0)
return;
@@ -311,19 +323,34 @@ static spl_lang_type_id_t sema_build_aggregate(spl_sema_t *sema, spl_ast_node_t
.ast_node_ref = mref};
vec_push(members, m);
} else if (mn->kind == SPL_AST_FN_DECL) {
spl_def_id_t fn_def =
spl_def_alloc(sema->type, SPL_DEF_FN, mn->fn_decl.name, mn->dbg, sema->ast, mref);
mn->resolved_def_id = fn_def;
spl_def_id_t fn_def = mn->resolved_def_id;
if (!fn_def) {
fn_def = spl_def_alloc(sema->type, SPL_DEF_FN, mn->fn_decl.name, mn->dbg, sema->ast,
mref);
mn->resolved_def_id = fn_def;
}
spl_def_node_t *fn_d = spl_def_node(sema->type, fn_def);
if (fn_d)
fn_d->owner_def = owner_def_id;
spl_lang_method_t meth = {.name = mn->fn_decl.name, .def_id = fn_def};
vec_push(methods, meth);
} else if (mn->kind == SPL_AST_TYPE_DECL) {
spl_def_id_t tdef = mn->resolved_def_id;
if (!tdef)
spl_ast_node_t *tpat = spl_ast_node(sema->ast, mn->type_decl.pattern);
if (!tpat || tpat->kind != SPL_AST_PATTERN_IDENT)
continue;
spl_lang_method_t meth = {.name = mn->type_decl.name, .def_id = tdef};
const char *tname = tpat->pattern_ident.name;
spl_def_id_t tdef = mn->resolved_def_id;
if (!tdef) {
spl_ast_node_kind_t tek =
mn->type_decl.type_expr ? spl_ast_node(sema->ast, mn->type_decl.type_expr)->kind
: 0;
spl_def_node_kind_t dk =
(tek == SPL_AST_TYPE_AGGREGATE) ? SPL_DEF_AGG : SPL_DEF_SCALAR;
tdef = spl_def_alloc(sema->type, dk, tname, mn->dbg, sema->ast, mref);
mn->resolved_def_id = tdef;
}
spl_lang_method_t meth = {.name = tname, .def_id = tdef};
vec_push(methods, meth);
}
}
@@ -402,15 +429,19 @@ static spl_lang_type_id_t sema_build_container_aggregate(spl_sema_t *sema, spl_a
spl_def_id_t tdef = d->resolved_def_id;
if (!tdef)
continue;
spl_lang_method_t meth = {.name = d->type_decl.name, .def_id = tdef};
spl_ast_node_t *tpat = spl_ast_node(sema->ast, d->type_decl.pattern);
if (!tpat || tpat->kind != SPL_AST_PATTERN_IDENT)
continue;
spl_lang_method_t meth = {.name = tpat->pattern_ident.name, .def_id = tdef};
vec_push(methods, meth);
} else if (d->kind == SPL_AST_VAR_DECL || d->kind == SPL_AST_CONST_DECL) {
spl_def_id_t vdef = d->resolved_def_id;
if (!vdef)
continue;
/* def_id 现在挂在 pattern 上,不在 VAR_DECL 节点上 */
spl_ast_node_t *pat = spl_ast_node(sema->ast, d->var_const_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT)
continue;
spl_def_id_t vdef = pat->resolved_def_id;
if (!vdef)
continue;
spl_lang_method_t meth = {.name = pat->pattern_ident.name, .def_id = vdef};
vec_push(methods, meth);
}
@@ -550,6 +581,9 @@ static spl_lang_type_id_t sema_eval_decl(spl_sema_t *sema, spl_def_id_t def_id)
if (n) {
switch (n->kind) {
case SPL_AST_TYPE_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->type_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT)
break;
if (n->type_decl.type_expr) {
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (te && te->kind == SPL_AST_TYPE_AGGREGATE)
@@ -628,21 +662,28 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) {
break;
}
case SPL_AST_TYPE_DECL: {
spl_symbol_t sym = {.name = n->type_decl.name, .kind = SPL_SYMBOL_KIND_TYPE};
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->type_decl.pattern);
if (!pat)
return;
if (pat->kind != SPL_AST_PATTERN_IDENT)
return; /* 解包由 sema_collect_types 处理 */
const char *name = pat->pattern_ident.name;
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (!te) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"type declaration `%s` missing type expression", n->type_decl.name);
"type declaration `%s` missing type expression", name);
return;
}
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_TYPE};
if (te->kind == SPL_AST_TYPE_AGGREGATE)
sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, sym.name, te->dbg, sema->ast, ref);
sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, name, te->dbg, sema->ast, ref);
else
sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, sema->ast, ref);
sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, name, te->dbg, sema->ast, ref);
n->resolved_def_id = sym.node;
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg,
"duplicate symbol `%s`", sym.name);
"duplicate symbol `%s`", name);
}
break;
}
@@ -659,18 +700,20 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) {
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, sema->ast, ref);
n->resolved_def_id = sym.node;
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg,
"duplicate symbol `%s`", name);
}
} else {
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"unsupported variable pattern (only simple identifier)");
"container-level var only supports simple identifier; "
"move destructuring into a function body");
break;
}
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, sema->ast, ref);
/* def_id 挂在 pattern 的 ident 上,不在 VAR_DECL 节点上 */
pat->resolved_def_id = sym.node;
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg,
"duplicate symbol `%s`", name);
}
break;
}
@@ -692,8 +735,17 @@ static void sema_collect_types(spl_sema_t *sema, spl_ast_node_ref_t ref) {
for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) {
spl_ast_node_ref_t dref = vec_at(n->container_members.declarations, i);
spl_ast_node_t *d = spl_ast_node(sema->ast, dref);
if (d && d->kind == SPL_AST_TYPE_DECL && d->resolved_def_id)
sema_eval_decl(sema, d->resolved_def_id);
if (!d || d->kind != SPL_AST_TYPE_DECL)
continue;
spl_ast_node_t *pat = spl_ast_node(sema->ast, d->type_decl.pattern);
if (!pat)
continue;
if (pat->kind == SPL_AST_PATTERN_IDENT) {
if (d->resolved_def_id)
sema_eval_decl(sema, d->resolved_def_id);
} else {
sema_do_type_unpack(sema, d, pat, d->type_decl.type_expr);
}
}
break;
case SPL_AST_TOP_LEVEL_BLOCK:
@@ -833,6 +885,23 @@ static spl_lang_type_id_t sema_block_body(spl_sema_t *sema, spl_ast_node_t *n,
return r;
}
static bool sema_pattern_is_literal(spl_ast_node_kind_t k) {
switch (k) {
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:
return true;
default:
return false;
}
}
/* 把 matched_tid 的绑定按 pattern 结构插进当前 scope。
调用前必须已经 push_scope。
约定:PATTERN_DOT 用 resolved_def_id = variant_idx + 1 保存变体位置。 */
static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
spl_lang_type_id_t matched_tid) {
if (!pat_ref)
@@ -841,9 +910,24 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
if (!pat)
return;
if (sema_pattern_is_literal(pat->kind)) {
spl_lang_type_id_t lt = sema_infer(sema, pat_ref);
if (lt && matched_tid)
sema_coerce(sema, pat_ref, matched_tid);
return;
}
switch (pat->kind) {
case SPL_AST_PATTERN_IDENT: {
const char *name = pat->pattern_ident.name;
if (!name || strcmp(name, "_") == 0)
return;
/* 容器级 var 已在 collect_names 阶段分配 def_id,这里只回填 lang。 */
if (pat->resolved_def_id) {
spl_def_resolve(sema->type, pat->resolved_def_id, matched_tid);
pat->resolved_lang_tid = matched_tid;
return;
}
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, pat->dbg, sema->ast, pat_ref);
spl_def_resolve(sema->type, sym.node, matched_tid);
@@ -859,11 +943,17 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
case SPL_AST_PATTERN_UNDERSCORE:
return;
case SPL_AST_PATTERN_LIST: {
for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i)
sema_bind_pattern(sema, vec_at(pat->pattern_list.patterns, i), matched_tid);
return;
}
case SPL_AST_PATTERN_TUPLE: {
spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, matched_tid);
if (!tn || tn->kind != SPL_LANG_TYPE_TUPLE) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"tuple pattern requires a tuple value");
"tuple pattern requires tuple value");
return;
}
usize natoms = vec_size(pat->pattern_tuple.patterns);
@@ -873,7 +963,6 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
"tuple pattern arity mismatch (expected %zu, got %zu)", nelems, natoms);
return;
}
/* 递归 bind 会 push lang_table,tn 会悬垂;先把元素类型拷到本地 */
spl_lang_type_id_vec_t elem_tids;
vec_init(elem_tids);
for (usize i = 0; i < nelems; ++i)
@@ -885,13 +974,245 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
return;
}
case SPL_AST_PATTERN_DOT:
case SPL_AST_PATTERN_AGGREGATE:
default:
spl_diag_error(sema->diag, SPL_DIAG_KIND_UNHANDLED_NODE, &pat->dbg,
"pattern kind %d not yet supported", (int)pat->kind);
case SPL_AST_PATTERN_DOT: {
spl_lang_type_node_t *mn = spl_lang_type_node(sema->type, matched_tid);
if (!mn || mn->kind != SPL_LANG_TYPE_ENUM) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"variant pattern requires enum value");
return;
}
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, matched_tid);
usize idx = 0;
if (!spl_type_agg_member_idx(&sema->type->ir, agg_ir, pat->pattern_dot.name, &idx)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &pat->dbg, "no variant `%s` in enum",
pat->pattern_dot.name);
return;
}
spl_type_node_t *irn = spl_type_node(&sema->type->ir, agg_ir);
if (!irn || idx >= vec_size(irn->agg_type.variants))
return;
spl_lang_type_id_t payload_lang =
sema_lang_from_ir(sema, vec_at(irn->agg_type.variants, idx).type_id);
pat->resolved_def_id = idx + 1;
pat->resolved_lang_tid = matched_tid;
if (pat->pattern_dot.sub_pattern && payload_lang)
sema_bind_pattern(sema, pat->pattern_dot.sub_pattern, payload_lang);
return;
}
case SPL_AST_PATTERN_AGGREGATE: {
spl_lang_type_node_t *an = spl_lang_type_node(sema->type, matched_tid);
if (!an || (an->kind != SPL_LANG_TYPE_STRUCT && an->kind != SPL_LANG_TYPE_UNION &&
an->kind != SPL_LANG_TYPE_ENUM)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"aggregate pattern requires struct or enum value");
return;
}
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, matched_tid);
usize nfields = vec_size(pat->pattern_aggregate.fields);
if (an->kind == SPL_LANG_TYPE_ENUM && nfields != 1) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"enum pattern must have exactly one variant");
return;
}
for (usize i = 0; i < nfields; ++i) {
spl_ast_node_t *f = spl_ast_node(sema->ast, vec_at(pat->pattern_aggregate.fields, i));
if (!f || f->kind != SPL_AST_PATTERN_FIELD)
continue;
usize idx = 0;
if (!spl_type_agg_member_idx(&sema->type->ir, agg_ir, f->pattern_field.name, &idx)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &f->dbg, "no field `%s`",
f->pattern_field.name);
continue;
}
spl_type_node_t *irn = spl_type_node(&sema->type->ir, agg_ir);
if (!irn || idx >= vec_size(irn->agg_type.variants))
continue;
spl_lang_type_id_t ft =
sema_lang_from_ir(sema, vec_at(irn->agg_type.variants, idx).type_id);
f->resolved_def_id = idx;
if (f->pattern_field.pattern && ft)
sema_bind_pattern(sema, f->pattern_field.pattern, ft);
}
pat->resolved_lang_tid = matched_tid;
return;
}
default:
spl_diag_error(sema->diag, SPL_DIAG_KIND_UNHANDLED_NODE, &pat->dbg,
"pattern kind %d not supported", (int)pat->kind);
return;
}
}
/* type 解包:把容器 struct 的 methods 里的名字引入当前 scope。
语法层由 pattern 承载,语义层在这里分派。
约束:
- 源类型必须是 LANG_TYPE_STRUCT 且 agg_type.variants 为空
(即 @import 返回的容器 struct,不是普通带字段的 struct)
- PATTERN_DOT 不允许有 sub_pattern(编译期没有 payload 概念)
- PATTERN_FIELD 不允许带 sub pattern(同上)
- 不做递归导出,显式即所得 */
static void sema_type_unpack_one(spl_sema_t *sema, spl_ast_node_t *pat, const char *name,
spl_lang_type_id_t src_lang) {
if (!name)
return;
spl_lang_type_node_t *src = spl_lang_type_node(sema->type, src_lang);
if (!src)
return;
for (usize i = 0; i < vec_size(src->methods); ++i) {
spl_lang_method_t *m = &vec_at(src->methods, i);
if (strcmp(m->name, name) != 0)
continue;
spl_def_node_t *d = spl_def_node(sema->type, m->def_id);
spl_symbol_kind_t k = SPL_SYMBOL_KIND_VAR;
if (d) {
switch (d->kind) {
case SPL_DEF_FN:
k = SPL_SYMBOL_KIND_FN;
break;
case SPL_DEF_AGG:
case SPL_DEF_SCALAR:
case SPL_DEF_DISTINCT:
case SPL_DEF_ALIAS:
case SPL_DEF_BUILTIN:
k = SPL_SYMBOL_KIND_TYPE;
break;
default:
k = SPL_SYMBOL_KIND_VAR;
break;
}
}
spl_symbol_t sym = {.name = name, .kind = k, .node = m->def_id};
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &pat->dbg,
"type unpack: duplicate symbol `%s`", name);
}
pat->resolved_def_id = m->def_id;
return;
}
spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &pat->dbg,
"type unpack: no symbol `%s` in source container", name);
}
static void sema_type_unpack_walk(spl_sema_t *sema, spl_ast_node_t *pat,
spl_lang_type_id_t src_lang) {
if (!pat)
return;
switch (pat->kind) {
case SPL_AST_PATTERN_UNDERSCORE:
return;
case SPL_AST_PATTERN_DOT:
if (pat->pattern_dot.sub_pattern) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"type unpack: payload pattern not allowed in compile-time unpack");
return;
}
sema_type_unpack_one(sema, pat, pat->pattern_dot.name, src_lang);
return;
case SPL_AST_PATTERN_AGGREGATE:
for (usize i = 0; i < vec_size(pat->pattern_aggregate.fields); ++i) {
spl_ast_node_t *f = spl_ast_node(sema->ast, vec_at(pat->pattern_aggregate.fields, i));
if (!f || f->kind != SPL_AST_PATTERN_FIELD)
continue;
if (f->pattern_field.pattern) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &f->dbg,
"type unpack: field pattern not allowed");
continue;
}
sema_type_unpack_one(sema, f, f->pattern_field.name, src_lang);
}
return;
case SPL_AST_PATTERN_LIST:
for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i) {
spl_ast_node_t *sub = spl_ast_node(sema->ast, vec_at(pat->pattern_list.patterns, i));
sema_type_unpack_walk(sema, sub, src_lang);
}
return;
case SPL_AST_PATTERN_IDENT:
/* collect_names 已分派,不应到这里 */
return;
default:
spl_diag_error(sema->diag, SPL_DIAG_KIND_UNHANDLED_NODE, &pat->dbg,
"type unpack: unsupported pattern kind %d", (int)pat->kind);
return;
}
}
static void sema_do_type_unpack(spl_sema_t *sema, spl_ast_node_t *decl, spl_ast_node_t *pat,
spl_ast_node_ref_t type_expr_ref) {
if (!type_expr_ref) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg,
"type unpack missing source type expression");
return;
}
spl_lang_type_id_t src_lang = sema_infer(sema, type_expr_ref);
if (!src_lang)
return;
spl_lang_type_node_t *src = spl_lang_type_node(sema->type, src_lang);
if (!src)
return;
if (src->kind != SPL_LANG_TYPE_STRUCT) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg,
"type unpack source must be a container struct");
return;
}
spl_type_id_t src_ir = spl_lang_type_get_ir_type(sema->type, src_lang);
spl_type_node_t *irn = spl_type_node(&sema->type->ir, src_ir);
if (!irn) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg,
"type unpack source IR unresolved");
return;
}
if (vec_size(irn->agg_type.variants) != 0) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg,
"type unpack source has fields; only container struct allowed");
return;
}
sema_type_unpack_walk(sema, pat, src_lang);
}
/* var / const / if-var 共用的初始化推导 + bind。
当前 scope 必须已经是 bind 目标 scope(调用者负责 push)。 */
static spl_lang_type_id_t sema_var_body(spl_sema_t *sema, spl_ast_node_t *n) {
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_diag_error(sema->diag, SPL_DIAG_KIND_VAR_UNINITIALIZED, &n->dbg,
"variable must be initialized");
return 0;
}
if (decl_tid) {
if (!sema_coerce(sema, n->var_const_decl.init_expr, decl_tid))
return 0;
} else {
decl_tid = sema_infer(sema, n->var_const_decl.init_expr);
if (!decl_tid || sema_is_infer(sema, decl_tid)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_CANNOT_INFER, &n->dbg,
"cannot infer variable type");
return 0;
}
}
sema_bind_pattern(sema, n->var_const_decl.pattern, decl_tid);
n->resolved_lang_tid = decl_tid;
return decl_tid;
}
static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref,
@@ -1842,9 +2163,15 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
case SPL_AST_EXPR_IFVAR: {
sema_infer(sema, n->ifvar_expr.var_decl);
if (!n->ifvar_expr.var_decl)
return 0;
spl_ast_node_t *vd = spl_ast_node(sema->ast, n->ifvar_expr.var_decl);
sema_push_scope(sema);
sema_var_body(sema, vd);
if (n->ifvar_expr.then_block)
sema_infer(sema, n->ifvar_expr.then_block);
sema_pop_scope(sema);
/* else 在 pattern scope 之外:绑定名在 else 不可见 */
if (n->ifvar_expr.else_branch)
sema_infer(sema, n->ifvar_expr.else_branch);
return 0;
@@ -1865,7 +2192,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (n->while_expr.else_branch)
sema_infer(sema, n->while_expr.else_branch);
vec_pop(sema->label_stack);
(void)vec_pop(sema->label_stack);
return 0;
}
case SPL_AST_EXPR_LOOP: {
@@ -1880,7 +2207,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (n->loop_expr.body)
sema_infer(sema, n->loop_expr.body);
vec_pop(sema->label_stack);
(void)vec_pop(sema->label_stack);
return 0;
}
case SPL_AST_EXPR_FOR: {
@@ -1891,7 +2218,6 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
lbl = ln->label.name;
}
vec_push(sema->label_stack, lbl);
sema_push_scope(sema);
usize nsrc = vec_size(n->for_expr.iter_exprs);
@@ -1900,49 +2226,47 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (pat && pat->kind == SPL_AST_PATTERN_LIST) {
usize natoms = vec_size(pat->pattern_list.patterns);
for (usize i = 0; i < nsrc; ++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 < natoms)
sema_bind_pattern(sema, vec_at(pat->pattern_list.patterns, i), elem_tid);
}
if (natoms > nsrc) {
if (natoms != nsrc) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"for: pattern has %zu atoms but only %zu sources", natoms, nsrc);
"for: %zu pattern atoms but %zu sources", natoms, nsrc);
}
for (usize i = 0; i < nsrc && i < natoms; ++i) {
spl_lang_type_id_t ct = sema_infer(sema, vec_at(n->for_expr.iter_exprs, i));
spl_lang_type_id_t et = sema_for_elem_type(sema, ct);
sema_bind_pattern(sema, vec_at(pat->pattern_list.patterns, i), et);
}
} else {
for (usize i = 0; i < nsrc; ++i) {
spl_lang_type_id_t container_tid =
sema_infer(sema, vec_at(n->for_expr.iter_exprs, i));
if (i == 0 && pat_ref) {
spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid);
sema_bind_pattern(sema, pat_ref, elem_tid);
}
}
if (nsrc > 1 && pat_ref) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
if (nsrc > 1) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"for: multiple sources require pattern list");
}
for (usize i = 0; i < nsrc; ++i) {
spl_lang_type_id_t ct = sema_infer(sema, vec_at(n->for_expr.iter_exprs, i));
if (i == 0)
sema_bind_pattern(sema, pat_ref, sema_for_elem_type(sema, ct));
}
}
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);
vec_pop(sema->label_stack);
sema_pop_scope(sema);
(void)vec_pop(sema->label_stack);
return 0;
}
case SPL_AST_EXPR_MATCH: {
sema_infer(sema, n->match_expr.matched_expr);
spl_lang_type_id_t matched = 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);
if (!arm || arm->kind != SPL_AST_MATCH_ARM)
continue;
sema_push_scope(sema);
sema_bind_pattern(sema, arm->match_arm.pattern, matched);
if (arm->match_arm.body)
sema_infer(sema, arm->match_arm.body);
}
sema_pop_scope(sema);
}
return 0;
}
@@ -2114,6 +2438,9 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
case SPL_AST_TYPE_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->type_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT)
return 0;
if (!n->type_decl.type_expr)
break;
spl_def_node_t *def =
@@ -2139,50 +2466,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
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_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"unsupported variable pattern");
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, sema->ast, ref);
n->resolved_def_id = sym.node;
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg,
"duplicate symbol `%s`", name);
}
}
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_diag_error(sema->diag, SPL_DIAG_KIND_VAR_UNINITIALIZED, &n->dbg,
"variable `%s` must be initialized", name);
return 0;
}
if (decl_tid) {
sema_coerce(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_diag_error(sema->diag, SPL_DIAG_KIND_CANNOT_INFER, &n->dbg,
"cannot infer type of `%s`", name);
return 0;
}
}
spl_def_resolve(sema->type, n->resolved_def_id, decl_tid);
n->resolved_lang_tid = decl_tid;
return decl_tid;
}
case SPL_AST_CONST_DECL:
return sema_var_body(sema, n);
case SPL_AST_MEMBER_DECL:
if (n->member_decl.type_expr)