stage1 支持聚合类型方法

This commit is contained in:
zzy committed 2026-09-14 15:36:43 +08:00
1 parent 9bdb7f892e
commit 5073c2b3ea
10 files changed
+387 -148

No files matched your search

+170 -95
View File
@@ -200,6 +200,85 @@ static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_
}
}
static spl_lang_type_id_t sema_build_aggregate(spl_sema_t *sema, spl_ast_node_t *te) {
spl_type_member_vec_t members;
vec_init(members);
spl_lang_method_vec_t methods;
vec_init(methods);
spl_ast_node_ref_vec_t fn_nodes;
vec_init(fn_nodes);
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
spl_ast_node_ref_t mref = vec_at(te->type_aggregate.members, i);
spl_ast_node_t *mn = spl_ast_node(sema->ast, mref);
if (!mn)
continue;
if (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 = 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, mref);
mn->resolved_def_id = fn_def;
spl_lang_method_t meth = {.name = mn->fn_decl.name, .def_id = fn_def};
vec_push(methods, meth);
vec_push(fn_nodes, mref);
}
}
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;
ln.methods = methods;
spl_lang_type_id_t agg_lang = spl_lang_node_push(sema->type, &ln);
spl_lang_type_id_t saved_agg = sema->current_aggregate_lang;
sema->current_aggregate_lang = agg_lang;
for (usize i = 0; i < vec_size(fn_nodes); ++i)
sema_infer(sema, vec_at(fn_nodes, i));
sema->current_aggregate_lang = saved_agg;
vec_free(fn_nodes);
return agg_lang;
}
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)
@@ -240,25 +319,12 @@ static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
sema->error_count++;
return;
}
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
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 {
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);
}
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
break;
}
case SPL_AST_FN_DECL: {
@@ -438,7 +504,8 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref,
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))
if (!en || (en->kind != SPL_LANG_TYPE_STRUCT && en->kind != SPL_LANG_TYPE_UNION &&
en->kind != SPL_LANG_TYPE_ENUM))
break;
if (n->aggregate_literal.name) {
@@ -461,6 +528,41 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref,
spl_type_node_t *irn = spl_type_node(sema->type, agg_ir);
if (!irn)
return 0;
if (en->kind == SPL_LANG_TYPE_ENUM) {
if (vec_size(n->aggregate_literal.fields) != 1) {
SPL_ERROR(&n->dbg, "enum literal must have exactly one variant");
sema->error_count++;
return 0;
}
spl_ast_node_t *item = spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, 0));
if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM) {
SPL_ERROR(&n->dbg, "invalid enum literal");
sema->error_count++;
return 0;
}
usize idx = 0;
if (!spl_type_agg_member_idx(sema->type, agg_ir, item->struct_init_item.name, &idx)) {
SPL_ERROR(&item->dbg, "no variant `%s`", item->struct_init_item.name);
sema->error_count++;
return 0;
}
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)
return 0;
if (!item->struct_init_item.expr) {
SPL_ERROR(&item->dbg, "variant `%s` requires initializer",
item->struct_init_item.name);
sema->error_count++;
return 0;
}
sema_check(sema, item->struct_init_item.expr, ft);
n->resolved_lang_tid = expected;
n->expected_lang_tid = 0;
return expected;
}
usize nfields = vec_size(irn->agg_type.variants);
bool *seen = calloc(nfields ? nfields : 1, sizeof(bool));
@@ -492,12 +594,6 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref,
}
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;
@@ -892,26 +988,40 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
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)) {
if (!agg || (agg->kind != SPL_LANG_TYPE_STRUCT && agg->kind != SPL_LANG_TYPE_UNION &&
agg->kind != SPL_LANG_TYPE_ENUM)) {
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;
if (m) {
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;
}
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;
for (usize i = 0; i < vec_size(agg->methods); ++i) {
spl_lang_method_t *meth = &vec_at(agg->methods, i);
if (strcmp(meth->name, n->field.field) != 0)
continue;
spl_def_node_t *fd = spl_def_node(sema->type, meth->def_id);
if (!fd)
return 0;
n->resolved_def_id = meth->def_id;
n->resolved_lang_tid = fd->lang_id;
return fd->lang_id;
}
n->resolved_lang_tid = ft;
return ft;
SPL_ERROR(&n->dbg, "no field `%s`", n->field.field);
sema->error_count++;
return 0;
}
/* ---------- INDEX ---------- */
@@ -1047,8 +1157,14 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
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);
if (!an || (an->kind != SPL_LANG_TYPE_STRUCT && an->kind != SPL_LANG_TYPE_UNION &&
an->kind != SPL_LANG_TYPE_ENUM)) {
SPL_ERROR(&n->dbg, "`%s` is not a struct/union/enum", type_name);
sema->error_count++;
return 0;
}
if (an->kind == SPL_LANG_TYPE_ENUM && vec_size(n->aggregate_literal.fields) != 1) {
SPL_ERROR(&n->dbg, "enum literal must have exactly one variant");
sema->error_count++;
return 0;
}
@@ -1270,8 +1386,20 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
return t;
}
case SPL_AST_TYPE_AGGREGATE:
case SPL_AST_TYPE_COMPTIME_CALL:
return sema_build_aggregate(sema, n);
case SPL_AST_TYPE_COMPTIME_CALL: {
const char *name = n->type_comptime_call.name;
if (name && strcmp(name, "self") == 0) {
if (sema->current_aggregate_lang == 0) {
SPL_ERROR(&n->dbg, "`@self` outside of aggregate");
sema->error_count++;
return 0;
}
n->resolved_lang_tid = sema->current_aggregate_lang;
return sema->current_aggregate_lang;
}
return 0;
}
/* ---------- 顶层声明 ---------- */
case SPL_AST_CONTAINER_MEMBERS:
@@ -1329,65 +1457,10 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
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_lang_type_id_t agg_lang = sema_build_aggregate(sema, te);
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);
@@ -1522,6 +1595,8 @@ void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref) {
return;
spl_scope_id_t saved = sema->scope->current_scope;
sema_collect(sema, module_ref);
fprintf(stderr, "after collect: current=%zu root=%zu\n", sema->scope->current_scope,
sema->scope->root_scope);
sema_infer(sema, module_ref);
sema->scope->current_scope = saved;
}