From 06f3884c30a6892983398445d8a690d830367171 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Tue, 15 Sep 2026 19:11:01 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E6=94=AF=E6=8C=81=E6=8C=87=E9=92=88?= =?UTF-8?q?=E8=BF=90=E7=AE=97=20=E6=8F=90=E4=BE=9B=E6=96=B0=E7=9A=84?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=A3=80=E6=9F=A5=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nob.c | 6 + stage0/spl_syscall.c | 4 + stage1/spl_ast.c | 10 +- stage1/spl_ast.h | 13 +- stage1/spl_ast2ir.c | 57 ++++- stage1/spl_attr.h | 1 + stage1/spl_lexer.c | 29 +-- stage1/spl_mpa.h | 14 ++ stage1/spl_sema.c | 483 ++++++++++++++++++++++++++----------------- stage1/spl_sema.h | 1 + stage1/spl_type.c | 255 ++++++++++++++++------- stage1/spl_type.h | 20 +- 12 files changed, 572 insertions(+), 321 deletions(-) create mode 100644 stage1/spl_mpa.h diff --git a/nob.c b/nob.c index 2f99bfb..b40f76a 100644 --- a/nob.c +++ b/nob.c @@ -376,6 +376,12 @@ int main(int argc, char **argv) { strcmp(mode_name, "sema") == 0 || strcmp(mode_name, "ir") == 0 || strcmp(mode_name, "vm") == 0) { tfn = test_once_with_dump; + } else if (strcmp(mode_name, "run") == 0) { + // HACK + Nob_Cmd cmd = {0}; + nob_cmd_append(&cmd, BUILD_FOLDER "spl_cli"); + nob_cmd_append(&cmd, BUILD_FOLDER "test.sir"); + return nob_cmd_run(&cmd) ? 0 : 1; } else { da_append(&files, mode_name); } diff --git a/stage0/spl_syscall.c b/stage0/spl_syscall.c index feac9dd..e804f18 100644 --- a/stage0/spl_syscall.c +++ b/stage0/spl_syscall.c @@ -167,6 +167,9 @@ SYSCALL_2(vm_strcmp, const char *, const char *, strcmp(a1, a2)) /* vm_memcpy - copy memory, returns dst */ SYSCALL_3(vm_memcpy, void *, const void *, size_t, (memcpy(a1, a2, a3), (uintptr_t)a1)) +/* vm_memcmp - compare two memory */ +SYSCALL_3(vm_memcmp, void *, const void *, size_t, (memcmp(a1, a2, a3), (uintptr_t)a1)) + static spl_vm_val_t vm_printf(int nargs, spl_vm_val_t *args) { if (nargs <= 0) return 0; @@ -387,6 +390,7 @@ void spl_syscall_register(spl_prog_t *prog) { {"vm_strlen", 0, vm_strlen}, {"vm_strcmp", 0, vm_strcmp}, {"vm_memcpy", 0, vm_memcpy}, + {"vm_memcmp", 0, vm_memcmp}, {"vm_printf", 0, vm_printf}, /* VM operations (comptime) */ {"vm_new", 0, vm_new}, diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index ca03b11..6c2f591 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -50,6 +50,8 @@ const char *spl_unary_op_name(spl_unary_op_t op) { return "bitnot"; case SPL_UNARY_OP_ADDRESS: return "addr"; + case SPL_UNARY_OP_DEREF: + return "deref"; default: return "?"; } @@ -840,7 +842,7 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { } /* 内建类型和普通路径 */ - if (bt->type == TOK_IDENT) { + if (bt->type == TOK_IDENT || bt->type == KW_BOOL) { const char *name = bt->lexeme; usize len = bt->len; /* 内建类型关键字 */ @@ -1353,7 +1355,7 @@ static spl_ast_node_ref_t parse_postfix(parser_t *p) { expr = ref; } else if (next->type == TOK_MUL) { advance(p); - spl_ast_node_ref_t ref = mk_unary(p, t, SPL_UNARY_OP_ADDRESS, expr); + spl_ast_node_ref_t ref = mk_unary(p, t, SPL_UNARY_OP_DEREF, expr); expr = ref; } else { SPL_FATAL(next, "expected identifier or '*' after '.'"); @@ -1416,13 +1418,13 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) { case TOK_INT_LITERAL: { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_INT_LIT, t); - node_at(p->ast, ref)->int_lit.val = parse_int_literal(t); + node_at(p->ast, ref)->int_lit.bits = parse_int_literal(t); // FIXME return ref; } case TOK_FLOAT_LITERAL: { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FLOAT_LIT, t); - node_at(p->ast, ref)->float_lit.val = parse_float_literal(t); + node_at(p->ast, ref)->float_lit.bits = parse_float_literal(t); // FIXME return ref; } case TOK_CHAR_LITERAL: { diff --git a/stage1/spl_ast.h b/stage1/spl_ast.h index b4f072c..67b8dfd 100644 --- a/stage1/spl_ast.h +++ b/stage1/spl_ast.h @@ -2,12 +2,12 @@ #define __SPL_AST_H__ #include "../stage0/include/utils.h" +#include "spl_attr.h" #include "spl_dbg.h" #include "spl_lexer.h" +#include "spl_mpa.h" #include "spl_tok.h" -#include "spl_attr.h" - /* clang-format off */ #define SPL_AST_KIND_TABLE \ X(SPL_AST_NONE, V0, none) \ @@ -139,6 +139,7 @@ typedef enum { SPL_UNARY_OP_NOT, SPL_UNARY_OP_BIT_NOT, SPL_UNARY_OP_ADDRESS, + SPL_UNARY_OP_DEREF, } spl_unary_op_t; const char *spl_binary_op_name(spl_binary_op_t op); @@ -291,12 +292,8 @@ struct spl_ast_node { } label; /* ---- 表达式子类型 ---- */ - struct { - isize val; - } int_lit; - struct { - double val; - } float_lit; + spl_mpa_int_t int_lit; + spl_mpa_float_t float_lit; struct { char val; } char_lit; diff --git a/stage1/spl_ast2ir.c b/stage1/spl_ast2ir.c index ce028d3..0ea25cf 100644 --- a/stage1/spl_ast2ir.c +++ b/stage1/spl_ast2ir.c @@ -239,6 +239,12 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { return 0; return slot; } + case SPL_AST_EXPR_UNARY: { + if (n->unary.op != SPL_UNARY_OP_DEREF) + return 0; + /* *p 作为左值,地址就是指针 p 的值 */ + return emit_expr(a, n->unary.operand); + } case SPL_AST_EXPR_FIELD: { spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->field.obj); if (!obj) @@ -298,7 +304,7 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { spl_ast_node_t *idx_node = spl_ast_node(a->sema->ast, n->index.index); if (!idx_node || idx_node->kind != SPL_AST_EXPR_INT_LIT) return 0; - usize i = (usize)idx_node->int_lit.val; + usize i = (usize)idx_node->int_lit.bits; spl_ir_node_ref_t base = emit_lvalue(a, n->index.obj); if (!base) return 0; @@ -415,10 +421,19 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) return 0; switch (n->kind) { - case SPL_AST_EXPR_INT_LIT: - return spl_ir_builder_type_const_int(a->ir, node_ir(a, n), (usize)n->int_lit.val); + case SPL_AST_EXPR_INT_LIT: { + /* 节点经 coerce 后 resolved 可能是具体 int 或 float。 + * 值始终存在 int_lit.bits(补码);按 resolved 决定如何构造 IR 常量。 */ + spl_type_id_t it = node_ir(a, n); + spl_type_node_t *itn = spl_type_node(a->sema->type, it); + if (itn && itn->kind == SPL_TYPE_FLOAT) { + double d = (double)(int64_t)n->int_lit.bits; + return spl_ir_builder_type_const_float(a->ir, it, d); + } + return spl_ir_builder_type_const_int(a->ir, it, (usize)n->int_lit.bits); + } case SPL_AST_EXPR_FLOAT_LIT: - return spl_ir_builder_type_const_float(a->ir, node_ir(a, n), n->float_lit.val); + return spl_ir_builder_type_const_float(a->ir, node_ir(a, n), n->float_lit.bits); case SPL_AST_EXPR_CHAR_LIT: return spl_ir_builder_type_const_char(a->ir, node_ir(a, n), n->char_lit.val); case SPL_AST_EXPR_STRING_LIT: { @@ -464,6 +479,12 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) case SPL_AST_EXPR_UNARY: { if (n->unary.op == SPL_UNARY_OP_ADDRESS) return emit_lvalue(a, n->unary.operand); + if (n->unary.op == SPL_UNARY_OP_DEREF) { + spl_ir_node_ref_t ptr = emit_lvalue(a, ref); + if (!ptr) + return 0; + return spl_ir_builder_mem_load(a->ir, node_ir(a, n), ptr); + } spl_ir_node_ref_t v = emit_expr(a, n->unary.operand); if (!v) return 0; @@ -584,17 +605,31 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) case SPL_OP_RSHIFT: return spl_ir_builder_arith_shr(a->ir, t, l, r); case SPL_OP_CMP_EQ: - return spl_ir_builder_cmp_eq(a->ir, t, l, r); case SPL_OP_CMP_NE: - return spl_ir_builder_cmp_ne(a->ir, t, l, r); case SPL_OP_CMP_LT: - return spl_ir_builder_cmp_lt(a->ir, t, l, r); case SPL_OP_CMP_LE: - return spl_ir_builder_cmp_le(a->ir, t, l, r); case SPL_OP_CMP_GT: - return spl_ir_builder_cmp_gt(a->ir, t, l, r); - case SPL_OP_CMP_GE: - return spl_ir_builder_cmp_ge(a->ir, t, l, r); + case SPL_OP_CMP_GE: { + /* 比较的操作数类型从左侧子节点读(sema 已 coerce 到共同类型) */ + spl_ast_node_t *cmln = spl_ast_node(a->sema->ast, n->binary.left); + spl_type_id_t op_tid = cmln ? node_ir(a, cmln) : 0; + switch (op) { + case SPL_OP_CMP_EQ: + return spl_ir_builder_cmp_eq(a->ir, op_tid, l, r); + case SPL_OP_CMP_NE: + return spl_ir_builder_cmp_ne(a->ir, op_tid, l, r); + case SPL_OP_CMP_LT: + return spl_ir_builder_cmp_lt(a->ir, op_tid, l, r); + case SPL_OP_CMP_LE: + return spl_ir_builder_cmp_le(a->ir, op_tid, l, r); + case SPL_OP_CMP_GT: + return spl_ir_builder_cmp_gt(a->ir, op_tid, l, r); + case SPL_OP_CMP_GE: + return spl_ir_builder_cmp_ge(a->ir, op_tid, l, r); + default: + return 0; + } + } default: return 0; } diff --git a/stage1/spl_attr.h b/stage1/spl_attr.h index b1036bb..f88479b 100644 --- a/stage1/spl_attr.h +++ b/stage1/spl_attr.h @@ -2,6 +2,7 @@ #define __SPL_ATTR_H__ #include "../stage0/include/utils.h" +#include "spl_mpa.h" typedef enum { SPL_ATTR_STAGE_SEMA, diff --git a/stage1/spl_lexer.c b/stage1/spl_lexer.c index 73b3033..88be674 100644 --- a/stage1/spl_lexer.c +++ b/stage1/spl_lexer.c @@ -333,19 +333,20 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) { continue; } - emit_int: { - spl_tok_t tok; - memset(&tok, 0, sizeof(tok)); - tok.type = TOK_INT_LITERAL; - tok.lexeme = num_start; - tok.len = (usize)((source + offset) - num_start); - tok.fname = fname; - tok.offset = num_start - source; - tok.line = line; - tok.col = col - tok.len; - vec_push(toks, tok); - continue; - } + emit_int: + { + spl_tok_t tok; + memset(&tok, 0, sizeof(tok)); + tok.type = TOK_INT_LITERAL; + tok.lexeme = num_start; + tok.len = (usize)((source + offset) - num_start); + tok.fname = fname; + tok.offset = num_start - source; + tok.line = line; + tok.col = col - tok.len; + vec_push(toks, tok); + continue; + } } /* Multi-character operators (longest match) */ @@ -411,7 +412,7 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) { /* Three-char operators first */ TRY_OP3('<', '-', '>', TOK_ARROW_BOTH, TOK_RIGHT_ARROW, TOK_LT) - TRY_OP3('<', '=', '>', TOK_FAT_ARROW_BOTH, TOK_RIGHT_FAT_ARROW, TOK_LT) + TRY_OP3('<', '=', '>', TOK_FAT_ARROW_BOTH, TOK_LE, TOK_LT) TRY_OP3('<', '<', '=', TOK_ASSIGN_L_SH, TOK_L_SH, TOK_LT) TRY_OP3('>', '>', '=', TOK_ASSIGN_R_SH, TOK_R_SH, TOK_GT) TRY_OP3('.', '.', '.', TOK_ELLIPSIS, TOK_RANGE, TOK_DOT) diff --git a/stage1/spl_mpa.h b/stage1/spl_mpa.h new file mode 100644 index 0000000..32c04ac --- /dev/null +++ b/stage1/spl_mpa.h @@ -0,0 +1,14 @@ +#ifndef __SPL_MPA_H__ +#define __SPL_MPA_H__ + +#include + +typedef struct { + uint64_t bits; +} spl_mpa_int_t; + +typedef struct { + double bits; +} spl_mpa_float_t; + +#endif /* __SPL_MPA_H__ */ diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index 4054e88..0aac0ab 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -117,7 +117,7 @@ static void sema_resolve_attrs(spl_sema_t *sema, spl_ast_node_ref_vec_t *raw, break; case SPL_AST_EXPR_INT_LIT: oa.kind = SPL_ATTR_ARG_INT; - oa.value.i = arg->int_lit.val; + oa.value.i = arg->int_lit.bits; break; default: SPL_ERROR(&a->dbg, "attribute arg #%zu has unsupported form", j); @@ -140,8 +140,8 @@ static void sema_resolve_attrs(spl_sema_t *sema, spl_ast_node_ref_vec_t *raw, } 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_coerce(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); @@ -177,6 +177,82 @@ static bool sema_is_literal(spl_ast_node_t *n) { } } +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; + if (tid == 0) { + snprintf(buf, cap, ""); + return; + } + spl_lang_type_node_t *n = spl_lang_type_node(sema->type, tid); + if (!n) { + snprintf(buf, cap, "", tid); + return; + } + spl_type_node_t *ir = spl_type_node(sema->type, n->ir_type_id); + switch (n->kind) { + case SPL_LANG_TYPE_INT: + if (ir && ir->int_type.bits == 0) + snprintf(buf, cap, "comptime_int(#%zu)", tid); + else if (ir) + snprintf(buf, cap, "%s%zu(#%zu)", ir->int_type.is_signed ? "i" : "u", ir->int_type.bits, + tid); + else + snprintf(buf, cap, "int?(#%zu)", tid); + break; + case SPL_LANG_TYPE_FLOAT: + if (ir && ir->float_type.bits == 0) + snprintf(buf, cap, "comptime_float(#%zu)", tid); + else if (ir) + snprintf(buf, cap, "f%zu(#%zu)", ir->float_type.bits, tid); + else + snprintf(buf, cap, "float?(#%zu)", tid); + break; + case SPL_LANG_TYPE_BOOL: + snprintf(buf, cap, "bool(#%zu)", tid); + break; + case SPL_LANG_TYPE_UNIT: + snprintf(buf, cap, "unit(#%zu)", tid); + break; + case SPL_LANG_TYPE_NEVER: + snprintf(buf, cap, "never(#%zu)", tid); + break; + case SPL_LANG_TYPE_ANY: + snprintf(buf, cap, "any(#%zu)", tid); + break; + case SPL_LANG_TYPE_INFER: + snprintf(buf, cap, "infer(#%zu)", tid); + break; + case SPL_LANG_TYPE_ERROR: + snprintf(buf, cap, "error(#%zu)", tid); + break; + case SPL_LANG_TYPE_PTR: + snprintf(buf, cap, "ptr(#%zu)", tid); + break; + case SPL_LANG_TYPE_ARRAY: + snprintf(buf, cap, "array(#%zu)", tid); + break; + case SPL_LANG_TYPE_SLICE: + snprintf(buf, cap, "slice(#%zu)", tid); + break; + case SPL_LANG_TYPE_TUPLE: + snprintf(buf, cap, "tuple(#%zu)", tid); + break; + case SPL_LANG_TYPE_RANGE: + snprintf(buf, cap, "range(#%zu)", tid); + break; + case SPL_LANG_TYPE_FN: + snprintf(buf, cap, "fn(#%zu)", tid); + break; + case SPL_LANG_TYPE_VARARGS: + snprintf(buf, cap, "varargs(#%zu)", tid); + break; + default: + snprintf(buf, cap, "langkind=%d ir=%zu(#%zu)", (int)n->kind, n->ir_type_id, tid); + break; + } +} + 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; @@ -505,7 +581,7 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, } case SPL_INTRIN_ASSERT: { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); - sema_check(sema, vec_at(*args, 0), bt); + sema_coerce(sema, vec_at(*args, 0), bt); if (nargs == 2) sema_infer(sema, vec_at(*args, 1)); return spl_lang_make_unit(sema->type); @@ -532,51 +608,78 @@ static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *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) { +static spl_lang_type_id_t sema_coerce(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 ============ */ + spl_lang_type_id_t already = n->resolved_lang_tid; + if (already == expected) + return expected; + + /* 已定型 */ + if (already != 0) { + spl_lang_type_node_t *an = spl_lang_type_node(sema->type, already); + spl_type_node_t *air = an ? spl_type_node(sema->type, an->ir_type_id) : NULL; + /* comptime 与 infer 都属于"可重定型":清空 resolved 后按 expected 重新推导 */ + bool a_rebindable = + (an && an->kind == SPL_LANG_TYPE_INFER) || + (an && an->kind == SPL_LANG_TYPE_INT && air && air->int_type.bits == 0) || + (an && an->kind == SPL_LANG_TYPE_FLOAT && air && air->float_type.bits == 0); + if (!a_rebindable) { + /* 具体类型:只接受子类型方向 */ + if (spl_lang_type_is_subtype(sema->type, already, expected)) { + n->expected_lang_tid = expected; + return expected; + } + char ebuf[128], gbuf[128]; + sema_type_to_str(sema, expected, ebuf, sizeof(ebuf)); + sema_type_to_str(sema, already, gbuf, sizeof(gbuf)); + SPL_ERROR(&n->dbg, "type mismatch: node kind=%d already typed as %s, expected %s", + (int)n->kind, gbuf, ebuf); + sema->error_count++; + return 0; + } + /* 清空 resolved,走未定型路径,让递归按 expected 下推子节点 */ + n->resolved_lang_tid = 0; + } + + /* 未定型的构造性节点 */ 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)) + /* & 与 .* 的结果类型由操作数决定,不能靠 expected 反向定型 */ + if (n->unary.op == SPL_UNARY_OP_ADDRESS || n->unary.op == SPL_UNARY_OP_DEREF) + return sema_infer(sema, ref); + if (!sema_coerce(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)) + if (!sema_coerce(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)) + if (!sema_coerce(sema, n->binary.left, bt)) return 0; - if (!sema_check(sema, n->binary.right, bt)) + if (!sema_coerce(sema, n->binary.right, bt)) return 0; n->resolved_lang_tid = bt; - n->expected_lang_tid = 0; return bt; } @@ -586,48 +689,55 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, 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); + spl_lang_type_id_t common = (lt == rt) ? lt : spl_lang_type_join(sema->type, lt, rt); if (!common) { - SPL_ERROR(&n->dbg, "comparison operands type mismatch"); + char lbuf[128], rbuf[128]; + sema_type_to_str(sema, lt, lbuf, sizeof(lbuf)); + sema_type_to_str(sema, rt, rbuf, sizeof(rbuf)); + SPL_ERROR(&n->dbg, "comparison operands type mismatch: lhs=%s rhs=%s", lbuf, rbuf); 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); + sema_coerce(sema, n->binary.left, common); + sema_coerce(sema, n->binary.right, common); + spl_lang_type_id_t b = spl_lang_make_bool(sema->type); + n->resolved_lang_tid = b; + return b; } - /* ptr +/- int:右侧 check 到整数,节点类型仍为指针 */ + /* ptr +/- int:expected 是 ptr 且左侧推断为 ptr。 + * 右侧保留原整型;仅 comptime_int(bits==0)收紧到 isize。 */ if (op == SPL_OP_ADD || op == SPL_OP_SUB) { - spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); - if (!lt) - return 0; - spl_lang_type_node_t *lln = spl_lang_type_node(sema->type, lt); - if (lln && lln->kind == SPL_LANG_TYPE_PTR) { - spl_lang_type_id_t it = spl_lang_make_int(sema->type, sizeof(void *) * 8, 1); - if (!sema_check(sema, n->binary.right, it)) - return 0; - n->resolved_lang_tid = lt; - n->expected_lang_tid = expected; - return expected; + spl_lang_type_node_t *en = spl_lang_type_node(sema->type, expected); + if (en && en->kind == SPL_LANG_TYPE_PTR) { + spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); + spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt); + if (ln && ln->kind == SPL_LANG_TYPE_PTR) { + spl_lang_type_id_t rt = sema_infer(sema, n->binary.right); + spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt); + if (!rn || rn->kind != SPL_LANG_TYPE_INT) { + SPL_ERROR(&n->dbg, "pointer offset must be integer"); + sema->error_count++; + return 0; + } + spl_type_node_t *rn_ir = spl_type_node(sema->type, rn->ir_type_id); + if (rn_ir && rn_ir->int_type.bits == 0) { + spl_lang_type_id_t it = + spl_lang_make_int(sema->type, sizeof(void *) * 8, 1); + if (!sema_coerce(sema, n->binary.right, it)) + return 0; + } + n->resolved_lang_tid = expected; + return expected; + } } } - /* 算术 / 位 / 移位:两侧 check 到 expected */ - if (!sema_check(sema, n->binary.left, expected)) + if (!sema_coerce(sema, n->binary.left, expected)) return 0; - if (!sema_check(sema, n->binary.right, expected)) + if (!sema_coerce(sema, n->binary.right, expected)) return 0; n->resolved_lang_tid = expected; - n->expected_lang_tid = 0; return expected; } @@ -636,13 +746,12 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, 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)) + if (!sema_coerce(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:退回通用逻辑 */ + break; } case SPL_AST_EXPR_TUPLE: { @@ -657,11 +766,10 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, } for (usize i = 0; i < nelems; ++i) { spl_lang_type_id_t et = vec_at(en->extra.elems, i); - if (!sema_check(sema, vec_at(n->tuple.elems, i), et)) + if (!sema_coerce(sema, vec_at(n->tuple.elems, i), et)) return 0; } n->resolved_lang_tid = expected; - n->expected_lang_tid = 0; return expected; } break; @@ -673,6 +781,7 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, en->kind != SPL_LANG_TYPE_ENUM)) break; + /* 有名字时,名字必须与 expected 指向同一类型 */ if (n->aggregate_literal.name) { spl_symbol_t sym; if (!spl_scope_find(sema->scope, n->aggregate_literal.name, &sym)) { @@ -691,8 +800,11 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, 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) + if (!irn) { + SPL_ERROR(&n->dbg, "aggregate type unresolved"); + sema->error_count++; return 0; + } if (en->kind == SPL_LANG_TYPE_ENUM) { if (vec_size(n->aggregate_literal.fields) != 1) { @@ -712,25 +824,16 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, 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; + usize field_tid_ir = vec_at(irn->agg_type.variants, idx).type_id; + spl_lang_type_id_t ft = sema_lang_from_ir(sema, field_tid_ir); + if (ft && item->struct_init_item.expr) { + if (!sema_coerce(sema, item->struct_init_item.expr, ft)) + 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)); - 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) @@ -741,39 +844,25 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, 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; usize field_tid_ir = vec_at(irn->agg_type.variants, idx).type_id; spl_lang_type_id_t ft = sema_lang_from_ir(sema, field_tid_ir); - 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; + if (ft && item->struct_init_item.expr) { + if (!sema_coerce(sema, item->struct_init_item.expr, ft)) + return 0; } - sema_check(sema, item->struct_init_item.expr, ft); } - 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); + sema_coerce(sema, n->if_expr.cond, bt); if (n->if_expr.then_block) - sema_check(sema, n->if_expr.then_block, expected); + sema_coerce(sema, n->if_expr.then_block, expected); if (n->if_expr.else_branch) - sema_check(sema, n->if_expr.else_branch, expected); + sema_coerce(sema, n->if_expr.else_branch, expected); n->resolved_lang_tid = expected; - n->expected_lang_tid = 0; return expected; } @@ -781,16 +870,14 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, 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); + spl_lang_type_id_t t = sema_coerce(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; } @@ -798,45 +885,49 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, 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; - } + /* 兜底:infer 后按子类型 / comptime 判定 */ + spl_lang_type_id_t from = sema_infer(sema, ref); + if (!from) + return 0; + if (from == expected) + return expected; - /* ============ 类 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"); + spl_lang_type_node_t *from_n = spl_lang_type_node(sema->type, from); + spl_lang_type_node_t *to_n = spl_lang_type_node(sema->type, expected); + spl_type_node_t *from_ir = from_n ? spl_type_node(sema->type, from_n->ir_type_id) : NULL; + spl_type_node_t *to_ir = to_n ? spl_type_node(sema->type, to_n->ir_type_id) : NULL; + + bool from_comptime_int = + from_n && from_n->kind == SPL_LANG_TYPE_INT && from_ir && from_ir->int_type.bits == 0; + bool from_comptime_float = + from_n && from_n->kind == SPL_LANG_TYPE_FLOAT && from_ir && from_ir->float_type.bits == 0; + if (from_comptime_int && to_n && to_n->kind == SPL_LANG_TYPE_INT) { + uint32_t bits = to_ir ? (uint32_t)to_ir->int_type.bits : 0; + if (n->kind == SPL_AST_EXPR_INT_LIT && bits != 0 && + !spl_lang_mpa_int_fits(sema->type, expected, n->int_lit)) { + SPL_ERROR(&n->dbg, "comptime value does not fit target type"); sema->error_count++; return 0; } - n->expected_lang_tid = expected; /* 只记,不改 natural */ + n->resolved_lang_tid = expected; return expected; } + if (from_comptime_float && to_n && to_n->kind == SPL_LANG_TYPE_FLOAT) { + n->resolved_lang_tid = expected; + return expected; + } + + if (spl_lang_type_is_subtype(sema->type, from, expected)) { + n->expected_lang_tid = expected; + return expected; + } + + char ebuf[128], gbuf[128]; + sema_type_to_str(sema, expected, ebuf, sizeof(ebuf)); + sema_type_to_str(sema, from, gbuf, sizeof(gbuf)); + SPL_ERROR(&n->dbg, "type mismatch: expect %s, got %s (node kind=%d)", ebuf, gbuf, (int)n->kind); + sema->error_count++; + return 0; } static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { @@ -854,12 +945,12 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { /* ---------- 字面量 ---------- */ case SPL_AST_EXPR_INT_LIT: { - spl_lang_type_id_t t = spl_lang_make_int(sema->type, 0, 1); /* comptime_int */ + spl_lang_type_id_t t = spl_lang_make_int(sema->type, 0, 1); 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 */ + spl_lang_type_id_t t = spl_lang_make_float(sema->type, 0); n->resolved_lang_tid = t; return t; } @@ -939,7 +1030,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { 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); + sema_coerce(sema, n->unary.operand, bt); n->resolved_lang_tid = bt; return bt; } @@ -948,6 +1039,16 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { n->resolved_lang_tid = p; return p; } + case SPL_UNARY_OP_DEREF: { + if (tn->kind != SPL_LANG_TYPE_PTR) { + SPL_ERROR(&n->dbg, "deref requires pointer operand"); + sema->error_count++; + return 0; + } + spl_lang_type_id_t elem = tn->extra.elem; + n->resolved_lang_tid = elem; + return elem; + } default: UNREACHABLE(); } @@ -962,7 +1063,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); if (!lt) return 0; - sema_check(sema, n->binary.right, lt); + sema_coerce(sema, n->binary.right, lt); n->resolved_lang_tid = lt; return lt; } @@ -970,8 +1071,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { /* 逻辑 */ 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); + sema_coerce(sema, n->binary.left, bt); + sema_coerce(sema, n->binary.right, bt); n->resolved_lang_tid = bt; return bt; } @@ -983,22 +1084,22 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { 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); + spl_lang_type_id_t common = (lt == rt) ? lt : spl_lang_type_join(sema->type, lt, rt); if (!common) { - SPL_ERROR(&n->dbg, "comparison operands type mismatch"); + char lbuf[128], rbuf[128]; + sema_type_to_str(sema, lt, lbuf, sizeof(lbuf)); + sema_type_to_str(sema, rt, rbuf, sizeof(rbuf)); + SPL_ERROR(&n->dbg, "comparison operands type mismatch: lhs=%s rhs=%s", lbuf, rbuf); sema->error_count++; return 0; } - sema_check(sema, n->binary.left, common); - sema_check(sema, n->binary.right, common); + sema_coerce(sema, n->binary.left, common); + sema_coerce(sema, n->binary.right, common); - n->resolved_lang_tid = common; - return spl_lang_make_bool(sema->type); + spl_lang_type_id_t b = spl_lang_make_bool(sema->type); + n->resolved_lang_tid = b; + return b; } /* Range */ @@ -1027,52 +1128,41 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { 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); + 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); - /* 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; + /* ptr +/- int 特判:右侧保留自己的整型; + * 仅当右操作数是 comptime_int(bits==0)时收紧到 isize, + * 避免 comptime 类型泄漏到 IR。 */ + if (ln && ln->kind == SPL_LANG_TYPE_PTR && rn && rn->kind == SPL_LANG_TYPE_INT && + (op == SPL_OP_ADD || op == SPL_OP_SUB)) { + spl_type_node_t *rn_ir = spl_type_node(sema->type, rn->ir_type_id); + if (rn_ir && rn_ir->int_type.bits == 0) { + spl_lang_type_id_t it = spl_lang_make_int(sema->type, sizeof(void *) * 8, 1); + sema_coerce(sema, n->binary.right, it); } + n->resolved_lang_tid = lt; + return lt; } - /* ptr +/- int 特判 */ + + spl_lang_type_id_t common = (lt == rt) ? lt : spl_lang_type_join(sema->type, lt, rt); if (!common) { - spl_lang_type_node_t *pln = spl_lang_type_node(sema->type, lt); - spl_lang_type_node_t *prn = spl_lang_type_node(sema->type, rt); - if (pln && pln->kind == SPL_LANG_TYPE_PTR && prn && prn->kind == SPL_LANG_TYPE_INT && - (op == SPL_OP_ADD || op == SPL_OP_SUB)) { - n->resolved_lang_tid = lt; - n->expected_lang_tid = 0; - return lt; - } + char lbuf[128], rbuf[128]; + sema_type_to_str(sema, lt, lbuf, sizeof(lbuf)); + sema_type_to_str(sema, rt, rbuf, sizeof(rbuf)); + SPL_ERROR(&n->dbg, "operand types cannot be joined: lhs=%s rhs=%s", lbuf, rbuf); + sema->error_count++; + return 0; } - sema_check(sema, n->binary.left, common); - sema_check(sema, n->binary.right, common); + + sema_coerce(sema, n->binary.left, common); + sema_coerce(sema, n->binary.right, common); + n->resolved_lang_tid = common; return common; } @@ -1123,13 +1213,13 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { for (usize i = 0; i < nargs && i < fixed; ++i) { spl_lang_type_id_t pt = vec_at(spl_lang_type_node(sema->type, callee_tid)->extra.fn.params, i); - sema_check(sema, vec_at(n->call.args, i), pt); + sema_coerce(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); + sema_coerce(sema, vec_at(n->call.args, i), vt); } spl_lang_type_id_t ret = fn->extra.fn.ret; @@ -1213,7 +1303,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { sema->error_count++; return 0; } - isize i = idx_node->int_lit.val; + isize i = (isize)idx_node->int_lit.bits; if (i < 0 || (usize)i >= vec_size(obj->extra.elems)) { SPL_ERROR(&n->dbg, "tuple index out of range"); sema->error_count++; @@ -1257,17 +1347,31 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { /* ---------- 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) + if (!dst) return 0; + spl_lang_type_id_t src = sema_infer(sema, n->cast.expr); + if (!src) + return 0; + + /* 仅当 src 是 comptime 时收紧到 dst;具体类型间的 as 直接放行(截断/扩展由 ast2ir 生成) */ spl_lang_type_node_t *sn = spl_lang_type_node(sema->type, src); + spl_type_node_t *sir = sn ? spl_type_node(sema->type, sn->ir_type_id) : NULL; + bool src_comptime = + (sn && sn->kind == SPL_LANG_TYPE_INT && sir && sir->int_type.bits == 0) || + (sn && sn->kind == SPL_LANG_TYPE_FLOAT && sir && sir->float_type.bits == 0); + if (src_comptime) { + if (!sema_coerce(sema, n->cast.expr, dst)) + return 0; + } + 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; } @@ -1296,10 +1400,11 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_lang_type_id_t et = sema_infer(sema, vec_at(n->array_literal.elems, i)); if (!et) return 0; - if (elem_t == 0) + if (elem_t == 0) { elem_t = et; - else { - spl_lang_type_id_t c = spl_lang_type_balance(sema->type, elem_t, et); + } else { + spl_lang_type_id_t c = + (elem_t == et) ? elem_t : spl_lang_type_join(sema->type, elem_t, et); if (c) elem_t = c; } @@ -1365,7 +1470,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { usize field_tid_ir = vec_at(irn->agg_type.variants, idx).type_id; spl_lang_type_id_t ft = sema_lang_from_ir(sema, field_tid_ir); if (ft && item->struct_init_item.expr) - sema_check(sema, item->struct_init_item.expr, ft); + sema_coerce(sema, item->struct_init_item.expr, ft); } } n->resolved_lang_tid = agg; @@ -1399,7 +1504,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { /* ---------- 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); + sema_coerce(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; @@ -1407,7 +1512,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { 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); + result = (then_t == else_t) ? then_t : spl_lang_type_join(sema->type, then_t, else_t); else result = then_t ? then_t : else_t; n->resolved_lang_tid = result; @@ -1433,7 +1538,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { vec_push(sema->label_stack, lbl); spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); - sema_check(sema, n->while_expr.cond, bt); + sema_coerce(sema, n->while_expr.cond, bt); if (n->while_expr.body) sema_infer(sema, n->while_expr.body); if (n->while_expr.else_branch) @@ -1722,7 +1827,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } if (decl_tid) { - sema_check(sema, n->var_const_decl.init_expr, 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)) { @@ -1753,7 +1858,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { 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); + sema_coerce(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) { diff --git a/stage1/spl_sema.h b/stage1/spl_sema.h index aa048ca..da0d4db 100644 --- a/stage1/spl_sema.h +++ b/stage1/spl_sema.h @@ -2,6 +2,7 @@ #define __SPL_SEMA_H__ #include "spl_ast.h" +#include "spl_mpa.h" #include "spl_type.h" #include "spl_attr.h" diff --git a/stage1/spl_type.c b/stage1/spl_type.c index c62da71..8015aa3 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -380,122 +380,219 @@ bool spl_lang_type_is_subtype(const spl_type_t *type, spl_lang_type_id_t sub, if (!nsub || !nsuper) return false; - // 语言级特殊类型 if (nsub->kind == SPL_LANG_TYPE_NEVER) return true; if (nsuper->kind == SPL_LANG_TYPE_ANY) return true; - if (nsub->kind == SPL_LANG_TYPE_INFER || nsuper->kind == SPL_LANG_TYPE_INFER) { - // 推断类型暂不处理子类型关系 + + if (nsub->kind == SPL_LANG_TYPE_INT && nsuper->kind == SPL_LANG_TYPE_INT) { + spl_type_node_t *ir_sub = spl_type_node(type, nsub->ir_type_id); + spl_type_node_t *ir_super = spl_type_node(type, nsuper->ir_type_id); + if (!ir_sub || !ir_super) + return false; + uint32_t sb = (uint32_t)ir_sub->int_type.bits; + uint32_t pb = (uint32_t)ir_super->int_type.bits; + /* comptime_int (bits==0) 是整数格的 top */ + if (pb == 0) + return true; /* 任何具体整数 <: comptime_int */ + if (sb == 0) + return false; /* comptime_int 不能隐式收窄到具体整数 */ + bool ss = ir_sub->int_type.is_signed != 0; + bool ps = ir_super->int_type.is_signed != 0; + if (ss == ps) + return sb <= pb; + if (!ss && ps) + return sb < pb; return false; } + + if (nsub->kind == SPL_LANG_TYPE_FLOAT && nsuper->kind == SPL_LANG_TYPE_FLOAT) { + spl_type_node_t *ir_sub = spl_type_node(type, nsub->ir_type_id); + spl_type_node_t *ir_super = spl_type_node(type, nsuper->ir_type_id); + if (!ir_sub || !ir_super) + return false; + uint32_t sb = (uint32_t)ir_sub->float_type.bits; + uint32_t pb = (uint32_t)ir_super->float_type.bits; + if (pb == 0) + return true; + if (sb == 0) + return false; + return sb <= pb; + } + if (nsub->kind == SPL_LANG_TYPE_PTR && nsuper->kind == SPL_LANG_TYPE_PTR) { spl_lang_type_node_t *sub_elem = spl_lang_type_node(type, nsub->extra.elem); spl_lang_type_node_t *super_elem = spl_lang_type_node(type, nsuper->extra.elem); if (sub_elem && sub_elem->kind == SPL_LANG_TYPE_NEVER) - return true; /* *never <: *T */ + return true; if (super_elem && super_elem->kind == SPL_LANG_TYPE_ANY) - return true; /* *T <: *any */ + return true; if (nsub->extra.elem == nsuper->extra.elem) - return true; /* *T <: *T */ + return true; return false; } - // 对于简单类型,委托给底层类型判断 - // 如果语言级 kind 相同且底层类型可子类型,则成立 - if (nsub->kind == nsuper->kind) { + if (nsub->kind == nsuper->kind) return spl_type_is_subtype(type, nsub->ir_type_id, nsuper->ir_type_id); - } - // 特殊情况:slice 可以看作 array 的超集?暂不处理 return false; } -spl_lang_type_id_t spl_lang_type_coerce_to(spl_type_t *type, spl_lang_type_id_t to, - spl_lang_type_id_t from) { - if (to == 0 || from == 0) - return 0; - if (to == from) - return to; +static uint32_t spl_type_std_int_bits_up(uint32_t bits) { + if (bits <= 8) + return 8; + if (bits <= 16) + return 16; + if (bits <= 32) + return 32; + if (bits <= 64) + return 64; + return 0; +} - spl_lang_type_node_t *to_node = spl_lang_type_node(type, to); - if (!to_node) +spl_lang_type_id_t spl_lang_type_join(const spl_type_t *type, spl_lang_type_id_t a, + spl_lang_type_id_t b) { + if (a == 0 || b == 0) + return 0; + if (a == b) + return a; + + spl_lang_type_node_t *na = spl_lang_type_node(type, a); + spl_lang_type_node_t *nb = spl_lang_type_node(type, b); + if (!na || !nb) return 0; - if (to_node->kind == SPL_LANG_TYPE_INFER) - return from; + if (na->kind == SPL_LANG_TYPE_NEVER) + return b; + if (nb->kind == SPL_LANG_TYPE_NEVER) + return a; + if (na->kind == SPL_LANG_TYPE_ANY || nb->kind == SPL_LANG_TYPE_ANY) + return spl_lang_make_any((spl_type_t *)type); - spl_lang_type_node_t *from_node = spl_lang_type_node(type, from); - if (!from_node) + /* comptime 参与:返回另一侧的具体类型(comptime 是宽度未定,优先取具体) */ + bool a_int = na->kind == SPL_LANG_TYPE_INT; + bool b_int = nb->kind == SPL_LANG_TYPE_INT; + bool a_flt = na->kind == SPL_LANG_TYPE_FLOAT; + bool b_flt = nb->kind == SPL_LANG_TYPE_FLOAT; + if (a_int && b_int) { + spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); + spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); + if (ira && irb) { + bool a_ct = ira->int_type.bits == 0; + bool b_ct = irb->int_type.bits == 0; + if (a_ct && b_ct) + return a; /* 都是 comptime_int */ + if (a_ct) + return b; + if (b_ct) + return a; + } + } + if (a_flt && b_flt) { + spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); + spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); + if (ira && irb) { + bool a_ct = ira->float_type.bits == 0; + bool b_ct = irb->float_type.bits == 0; + if (a_ct && b_ct) + return a; + if (a_ct) + return b; + if (b_ct) + return a; + } + } + + /* int / float 混合:仅 comptime 混 comptime 视为 comptime_float */ + if (a_int && b_flt) { + spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); + spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); + if (ira && irb && ira->int_type.bits == 0 && irb->float_type.bits == 0) + return spl_lang_make_float((spl_type_t *)type, 0); + return 0; + } + if (a_flt && b_int) { + spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); + spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); + if (ira && irb && ira->float_type.bits == 0 && irb->int_type.bits == 0) + return spl_lang_make_float((spl_type_t *)type, 0); + return 0; + } + + /* 现在走子类型关系(两侧均为具体类型) */ + if (spl_lang_type_is_subtype(type, a, b)) + return b; + if (spl_lang_type_is_subtype(type, b, a)) + return a; + + if (na->kind != nb->kind) return 0; - if (from_node->kind == SPL_LANG_TYPE_INT && to_node->kind == SPL_LANG_TYPE_INT) { - spl_type_id_t from_ir = spl_lang_type_get_ir_type(type, from); - spl_type_node_t *from_ir_node = spl_type_node(type, from_ir); - if (from_ir_node && from_ir_node->int_type.bits == 0) - return to; + if (a_int) { + spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); + spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); + if (!ira || !irb) + return 0; + uint32_t ba = (uint32_t)ira->int_type.bits; + uint32_t bb = (uint32_t)irb->int_type.bits; + bool sa = ira->int_type.is_signed != 0; + bool sb = irb->int_type.is_signed != 0; + if (sa == sb) { + uint32_t bits = ba > bb ? ba : bb; + return spl_lang_make_int((spl_type_t *)type, bits, sa); + } + uint32_t s_bits = sa ? ba : bb; + uint32_t u_bits = sa ? bb : ba; + uint32_t need = s_bits > (u_bits + 1) ? s_bits : (u_bits + 1); + uint32_t std_bits = spl_type_std_int_bits_up(need); + if (std_bits == 0) + return 0; + return spl_lang_make_int((spl_type_t *)type, std_bits, 1); } - if (from_node->kind == SPL_LANG_TYPE_FLOAT && to_node->kind == SPL_LANG_TYPE_FLOAT) { - spl_type_id_t from_ir = spl_lang_type_get_ir_type(type, from); - spl_type_node_t *from_ir_node = spl_type_node(type, from_ir); - if (from_ir_node && from_ir_node->float_type.bits == 0) - return to; + if (a_flt) { + spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); + spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); + if (!ira || !irb) + return 0; + uint32_t ba = (uint32_t)ira->float_type.bits; + uint32_t bb = (uint32_t)irb->float_type.bits; + uint32_t bits = ba > bb ? ba : bb; + return spl_lang_make_float((spl_type_t *)type, bits); } - if (to_node->kind == SPL_LANG_TYPE_ARRAY && from_node->kind == SPL_LANG_TYPE_ARRAY) { - spl_lang_type_id_t to_elem = to_node->extra.elem; - spl_lang_type_id_t from_elem = from_node->extra.elem; - if (spl_lang_type_coerce_to(type, to_elem, from_elem) != 0) - return to; - } - - if (spl_lang_type_is_subtype(type, from, to)) - return to; - return 0; } -spl_lang_type_id_t spl_lang_type_balance(spl_type_t *type, spl_lang_type_id_t t1, - spl_lang_type_id_t t2) { - if (t1 == 0 || t2 == 0) - return 0; - if (t1 == t2) - return t1; +bool spl_lang_mpa_int_fits(const spl_type_t *type, spl_lang_type_id_t target, spl_mpa_int_t v) { + spl_lang_type_node_t *nt = spl_lang_type_node(type, target); + if (!nt || nt->kind != SPL_LANG_TYPE_INT) + return false; + spl_type_node_t *ir = spl_type_node(type, nt->ir_type_id); + if (!ir) + return false; + uint32_t bits = (uint32_t)ir->int_type.bits; + if (bits == 0) + return true; + bool target_signed = ir->int_type.is_signed != 0; - spl_lang_type_node_t *n1 = spl_lang_type_node(type, t1); - spl_lang_type_node_t *n2 = spl_lang_type_node(type, t2); - if (!n1 || !n2) - return 0; + int64_t val = (int64_t)v.bits; - if (n1->kind == SPL_LANG_TYPE_ANY || n2->kind == SPL_LANG_TYPE_ANY) - return spl_lang_make_any(type); - if (n1->kind == SPL_LANG_TYPE_NEVER) - return t2; - if (n2->kind == SPL_LANG_TYPE_NEVER) - return t1; - - if (spl_lang_type_is_subtype(type, t1, t2)) - return t2; - if (spl_lang_type_is_subtype(type, t2, t1)) - return t1; - - if (n1->kind == SPL_LANG_TYPE_INT && n2->kind == SPL_LANG_TYPE_INT) - return 0; - - if (n1->kind == SPL_LANG_TYPE_FLOAT && n2->kind == SPL_LANG_TYPE_FLOAT) { - spl_type_id_t ir1 = spl_lang_type_get_ir_type(type, t1); - spl_type_id_t ir2 = spl_lang_type_get_ir_type(type, t2); - spl_type_node_t *irn1 = spl_type_node(type, ir1); - spl_type_node_t *irn2 = spl_type_node(type, ir2); - if (irn1 && irn2) { - usize bits = irn1->float_type.bits > irn2->float_type.bits ? irn1->float_type.bits - : irn2->float_type.bits; - return spl_lang_make_float(type, bits); - } + if (target_signed) { + if (bits >= 64) + return true; + int64_t lo = -((int64_t)1 << (bits - 1)); + int64_t hi = ((int64_t)1 << (bits - 1)) - 1; + return val >= lo && val <= hi; } - return 0; + if (val < 0) + return false; + uint64_t uval = (uint64_t)val; + if (bits >= 64) + return true; + uint64_t hi = ((uint64_t)1 << bits) - 1; + return uval <= hi; } spl_def_id_t spl_def_alloc(spl_type_t *type, spl_def_node_kind_t kind, const char *name, diff --git a/stage1/spl_type.h b/stage1/spl_type.h index 6306bfc..e22b122 100644 --- a/stage1/spl_type.h +++ b/stage1/spl_type.h @@ -3,6 +3,7 @@ #include "../stage0/include/utils.h" #include "spl_dbg.h" +#include "spl_mpa.h" typedef usize spl_type_id_t; /* 0 is error */ typedef VEC(spl_type_id_t) spl_type_id_vec_t; @@ -181,23 +182,10 @@ bool spl_lang_type_is_subtype(const spl_type_t *type, spl_lang_type_id_t sub, bool spl_type_is_subtype(const spl_type_t *type, spl_type_id_t sub, spl_type_id_t super); spl_lang_type_id_t spl_lang_node_push(spl_type_t *type, spl_lang_type_node_t *node); -/* 计算 from 是否可以隐式转换到 to。 - * - to 是 INFER 时视为"接受任意 from",返回 from。 - * - 成功返回"转换后的类型"(正常是 to,INFER 时是 from)。 - * - 失败返回 0。 - * 纯函数:不修改任何 AST,不产生副作用。 */ -spl_lang_type_id_t spl_lang_type_coerce_to(spl_type_t *type, spl_lang_type_id_t to, - spl_lang_type_id_t from); +spl_lang_type_id_t spl_lang_type_join(const spl_type_t *type, spl_lang_type_id_t a, + spl_lang_type_id_t b); -/* 合并两个类型(用于 if 分支、算术运算的对称平衡)。 - * - NEVER 与任意 T 平衡得到 T。 - * - ANY 与任意 T 平衡得到 ANY。 - * - 子类型与父类型平衡得到父类型。 - * - 两个浮点取位宽较大者。 - * - 两个整数不自动提升,除非一方是另一方的子类型。 - * 无法合并返回 0。纯函数。 */ -spl_lang_type_id_t spl_lang_type_balance(spl_type_t *type, spl_lang_type_id_t t1, - spl_lang_type_id_t t2); +bool spl_lang_mpa_int_fits(const spl_type_t *type, spl_lang_type_id_t target, spl_mpa_int_t v); spl_def_id_t spl_def_alloc(spl_type_t *type, spl_def_node_kind_t kind, const char *name, spl_dbg_node_t dbg, usize ast_node_ref);