feat: 泛型基础设施 — <T>解析 + 类型推断 (单态化 codegen 待补)

This commit is contained in:
2026-06-06 16:17:15 +08:00
parent fa734b8a23
commit 350eeef3c5
9 changed files with 100 additions and 37 deletions
+40 -19
View File
@@ -159,31 +159,39 @@ static void analyze_binary_expr(AstNode* node, Scope* scope, ErrorList* errors,
}
// 参数类型匹配检查(CALL_EXPR 和 METHOD_CALL 共用)
static void check_arg_type(AstNode* arg, TypeKind expected, const char* expected_sname,
size_t idx, AstNode* call_node, Scope* scope,
static bool check_arg_type(AstNode* arg, TypeKind expected, const char* expected_sname,
size_t idx, AstNode* call_node, Symbol* fn_sym,
ErrorList* errors, Arena* a) {
(void)scope; (void)a;
(void)a;
TypeKind actual = arg->type.kind;
if (actual == TYPE_ERROR) return;
if (expected == TYPE_STRUCT) {
if (actual == TYPE_ERROR) return false;
if (expected == TYPE_STRUCT && expected_sname) {
// 检查是否是泛型类型参数(匹配则接受任意类型)
if (fn_sym && fn_sym->type_params) {
for (size_t t = 0; t < fn_sym->type_param_count; t++) {
if (strcmp(expected_sname, fn_sym->type_params[t]) == 0)
return true; // 泛型参数,接受任意类型
}
}
const char* actual_name = arg->type.struct_name;
if (actual != TYPE_STRUCT || !actual_name || !expected_sname ||
if (actual != TYPE_STRUCT || !actual_name ||
strcmp(actual_name, expected_sname) != 0) {
error_add(errors, "<sema>", call_node->loc.line, call_node->loc.col,
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
idx + 1, expected_sname ? expected_sname : "struct",
actual_name ? actual_name : type_name(actual));
}
return;
return false;
}
if (actual == expected) return;
if (expected == TYPE_I64 && actual == TYPE_ENUM) return;
if (can_implicit_convert(actual, expected)) return;
if (actual == expected) return false;
if (expected == TYPE_I64 && actual == TYPE_ENUM) return false;
if (can_implicit_convert(actual, expected)) return false;
if (actual == TYPE_I64 && arg->kind == AST_LITERAL_EXPR
&& (expected == TYPE_I32 || expected == TYPE_U64 || expected == TYPE_CHAR)) return;
&& (expected == TYPE_I32 || expected == TYPE_U64 || expected == TYPE_CHAR)) return false;
error_add(errors, "<sema>", call_node->loc.line, call_node->loc.col,
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
idx + 1, type_name(expected), type_name(actual));
return false;
}
// 命名参数重排序(CALL_EXPR 和 METHOD_CALL 共用)
@@ -241,9 +249,20 @@ static void analyze_call_expr(AstNode* node, Scope* scope, ErrorList* errors, Ar
}
for (size_t i = 0; i < node->as.call.arg_count; i++) {
analyze_expr(node->as.call.args[i], scope, errors, a);
check_arg_type(node->as.call.args[i], sym->param_types[i],
bool is_generic_param = check_arg_type(node->as.call.args[i], sym->param_types[i],
sym->param_struct_names ? sym->param_struct_names[i] : NULL,
i, node, scope, errors, a);
i, node, sym, errors, a);
// 泛型: 若实参匹配类型参数,传播具体类型到返回值
if (is_generic_param && sym->return_type == TYPE_STRUCT
&& sym->return_struct_type_name && sym->type_params) {
for (size_t t = 0; t < sym->type_param_count; t++) {
if (strcmp(sym->return_struct_type_name, sym->type_params[t]) == 0) {
node->type.kind = node->as.call.args[i]->type.kind;
node->type.struct_name = node->as.call.args[i]->type.struct_name;
return;
}
}
}
}
node->type.kind = sym->return_type;
if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name)
@@ -422,7 +441,7 @@ static void analyze_method_call(AstNode* node, Scope* scope, ErrorList* errors,
analyze_expr(node->as.method_call.args[i], scope, errors, a);
check_arg_type(node->as.method_call.args[i], sym->param_types[i + 1],
sym->param_struct_names ? sym->param_struct_names[i + 1] : NULL,
i, node, scope, errors, a);
i, node, sym, errors, a);
}
node->type.kind = sym->return_type;
if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name)
@@ -572,7 +591,9 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
scope_insert_function(scope, a, fn->as.function.name,
ret_t, ret_sn,
pts, pnames, pstruct_names,
fn->as.function.param_count);
fn->as.function.param_count,
fn->as.function.type_params,
fn->as.function.type_param_count);
}
// 第三遍:分析每个函数体
for (size_t i = 0; i < node->as.program.fn_count; i++) {
@@ -884,13 +905,13 @@ void sema_analyze(AstNode* ast, ErrorList* errors, Arena* arena) {
// 注册内置函数
TypeKind params_i64[] = {TYPE_I64};
scope_insert_function(global_scope, arena, "print_i64", TYPE_VOID, NULL, params_i64, NULL, NULL, 1);
scope_insert_function(global_scope, arena, "print_i64", TYPE_VOID, NULL, params_i64, NULL, NULL, 1, NULL, 0);
TypeKind params_f64[] = {TYPE_F64};
scope_insert_function(global_scope, arena, "print_f64", TYPE_VOID, NULL, params_f64, NULL, NULL, 1);
scope_insert_function(global_scope, arena, "print_f64", TYPE_VOID, NULL, params_f64, NULL, NULL, 1, NULL, 0);
TypeKind params_bool[] = {TYPE_BOOL};
scope_insert_function(global_scope, arena, "print_bool", TYPE_VOID, NULL, params_bool, NULL, NULL, 1);
scope_insert_function(global_scope, arena, "print_bool", TYPE_VOID, NULL, params_bool, NULL, NULL, 1, NULL, 0);
TypeKind params_str[] = {TYPE_STR};
scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, NULL, params_str, NULL, NULL, 1);
scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, NULL, params_str, NULL, NULL, 1, NULL, 0);
analyze_node(ast, global_scope, errors, arena);
}