feat: struct参数/返回值 + SourceLoc + 测试补全

- struct 可作函数参数和返回值 (fn make_point -> Point)
- SourceLoc 抽象: 所有 ast_make_* 参数 + AstNode 迁移完毕
- sema: +4 struct 类型检查测试 (字段类型/未定义/数量/嵌套)
- codegen: +2 struct IR 生成测试 (decl + field_access)
- 新增集成测试 14_struct_fn.l

测试: 104 单元 + 14 集成 = 全部通过
This commit is contained in:
2026-06-05 13:29:31 +08:00
parent 4046ab1875
commit da9a7065dd
12 changed files with 481 additions and 168 deletions
+74
View File
@@ -115,6 +115,76 @@ void test_str_concat_type_ok() {
arena_destroy(&a);
}
/* === struct 类型检查测试 === */
void test_struct_field_type_mismatch() {
Arena a = arena_create(1);
size_t tc; ErrorInfo lex_err = {0};
Token* toks = lex(&a,
"struct Point { x: i64, y: i64 } fn main() { let p: Point = Point { x: 10, y: true }; return; }",
"test", &tc, &lex_err);
ASSERT(toks != NULL);
ErrorInfo parse_err = {0};
AstNode* ast = parse(&a, toks, tc, "test", &parse_err);
ASSERT(ast != NULL);
ErrorList errors; error_init(&errors);
sema_analyze(ast, &errors, &a);
ASSERT(errors.count > 0); // y 字段类型不匹配: true 是 bool, 不是 i64
arena_destroy(&a);
}
void test_struct_undefined() {
Arena a = arena_create(1);
size_t tc; ErrorInfo lex_err = {0};
Token* toks = lex(&a,
"fn main() { let p: Unknown = Unknown { x: 1 }; return; }",
"test", &tc, &lex_err);
ASSERT(toks != NULL);
ErrorInfo parse_err = {0};
AstNode* ast = parse(&a, toks, tc, "test", &parse_err);
ASSERT(ast != NULL);
ErrorList errors; error_init(&errors);
sema_analyze(ast, &errors, &a);
ASSERT(errors.count > 0); // Unknown 未定义
arena_destroy(&a);
}
void test_struct_field_count_mismatch() {
Arena a = arena_create(1);
size_t tc; ErrorInfo lex_err = {0};
Token* toks = lex(&a,
"struct Point { x: i64, y: i64 } fn main() { let p: Point = Point { x: 10 }; return; }",
"test", &tc, &lex_err);
ASSERT(toks != NULL);
ErrorInfo parse_err = {0};
AstNode* ast = parse(&a, toks, tc, "test", &parse_err);
ASSERT(ast != NULL);
ErrorList errors; error_init(&errors);
sema_analyze(ast, &errors, &a);
ASSERT(errors.count > 0); // 缺少字段 'y'
arena_destroy(&a);
}
void test_struct_nested_type_ok() {
Arena a = arena_create(1);
size_t tc; ErrorInfo lex_err = {0};
Token* toks = lex(&a,
"struct Point { x: i64, y: i64 } struct Rect { tl: Point, br: Point } fn main() { let r: Rect = Rect { tl: Point { x: 0, y: 0 }, br: Point { x: 1, y: 1 } }; print_i64(r.tl.x); return; }",
"test", &tc, &lex_err);
ASSERT(toks != NULL);
ErrorInfo parse_err = {0};
AstNode* ast = parse(&a, toks, tc, "test", &parse_err);
ASSERT(ast != NULL);
ErrorList errors; error_init(&errors);
sema_analyze(ast, &errors, &a);
ASSERT(errors.count == 0); // 嵌套结构体类型检查应通过
arena_destroy(&a);
}
int main(void) {
TEST_RUN(test_type_error);
TEST_RUN(test_undefined_var);
@@ -123,5 +193,9 @@ int main(void) {
TEST_RUN(test_assign_immutable_error);
TEST_RUN(test_str_type_ok);
TEST_RUN(test_str_concat_type_ok);
TEST_RUN(test_struct_field_type_mismatch);
TEST_RUN(test_struct_undefined);
TEST_RUN(test_struct_field_count_mismatch);
TEST_RUN(test_struct_nested_type_ok);
return test_summary();
}