From 09d05e3a34e367355ddda079dfc17b2a0cfa381c Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Tue, 15 Sep 2026 21:24:58 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E6=8C=87=E9=92=88=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E7=9A=84=E9=94=99=E8=AF=AF=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20as=E8=BF=90=E7=AE=97=E7=AC=A6=E4=BC=98=E5=85=88=E7=BA=A7?= =?UTF-8?q?=E7=9A=84=E4=BF=AE=E6=94=B9=20ir2vm=E7=9A=84bug=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gramma.pest | 5 +- nob.c | 2 +- stage0/spl_cli.c | 8 ++- stage0/spl_mcode.h | 4 +- stage0/spl_syscall.c | 137 +++++++++++++++++++++++++++++++++---------- stage0/spl_vm.c | 34 +++++++++-- stage0/spl_vm.h | 4 +- stage1/spl_ast.c | 26 +++++--- stage1/spl_ir2vm.c | 22 ++++--- stage1/spl_sema.c | 9 ++- 10 files changed, 191 insertions(+), 60 deletions(-) diff --git a/gramma.pest b/gramma.pest index 9f61f35..7ffc7c7 100644 --- a/gramma.pest +++ b/gramma.pest @@ -101,12 +101,13 @@ ArrowExpr = { RangeExpr ~ ((THIN_R_ARROW | THIN_L_ARROW | FAT_D_ARROW | THIN_D_A RangeExpr = { ShiftExpr ~ (DOT2 ~ ShiftExpr?)? } ShiftExpr = { AddExpr ~ ((L_ARROW2_EQ | L_ARROW2 | R_ARROW2_EQ | R_ARROW2) ~ AddExpr)* } AddExpr = { MulExpr ~ ((PLUS | MINUS) ~ MulExpr)* } -MulExpr = { PrefixExpr ~ ((ASTERISK | SLASH | PERCENT) ~ PrefixExpr)* } +MulExpr = { CastExpr ~ ((ASTERISK | SLASH | PERCENT) ~ CastExpr)* } +CastExpr = { PrefixExpr ~ (KEYWORD_as ~ TypeExpr)* } PrefixExpr = { PrefixOp* ~ PostfixExpr } PrefixOp = { MINUS | BANG | TILDE | AMPERSAND } PostfixExpr = { - PrimaryExpr ~ (LPAREN ~ ExprList ~ RPAREN | DOT ~ IDENTIFIER | DOT ~ ASTERISK | LBRACKET ~ Expr ~ RBRACKET | LBRACKET ~ Expr ~ DOT2 ~ Expr? ~ RBRACKET | KEYWORD_as ~ TypeExpr)* + PrimaryExpr ~ (LPAREN ~ ExprList ~ RPAREN | DOT ~ IDENTIFIER | DOT ~ ASTERISK | LBRACKET ~ Expr ~ RBRACKET | LBRACKET ~ Expr ~ DOT2 ~ Expr? ~ RBRACKET)* } ExprList = { (Expr ~ COMMA)* ~ Expr? } diff --git a/nob.c b/nob.c index b40f76a..2146a0b 100644 --- a/nob.c +++ b/nob.c @@ -379,7 +379,7 @@ int main(int argc, char **argv) { } 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 "spl_cli", "-d"); nob_cmd_append(&cmd, BUILD_FOLDER "test.sir"); return nob_cmd_run(&cmd) ? 0 : 1; } else { diff --git a/stage0/spl_cli.c b/stage0/spl_cli.c index cc8bf84..9d69cf4 100644 --- a/stage0/spl_cli.c +++ b/stage0/spl_cli.c @@ -637,10 +637,14 @@ int main(int argc, const char **argv) { spl_vm_t vm; spl_vm_init(&vm); - if (o.debug) + if (o.debug) { + fprintf(stderr, "spl_cli: debug mode on\n"); spl_vm_set_debug(&vm, 1); - if (o.trace) + } + if (o.trace) { + fprintf(stderr, "spl_cli: trace mode on\n"); spl_vm_set_trace(&vm, 1); + } if (spl_vm_load_prog(&vm, &prog) != 0) { fprintf(stderr, "spl_cli: failed to load prog\n"); spl_vm_drop(&vm); diff --git a/stage0/spl_mcode.h b/stage0/spl_mcode.h index 7ea8938..a71a0c6 100644 --- a/stage0/spl_mcode.h +++ b/stage0/spl_mcode.h @@ -170,7 +170,9 @@ typedef struct spl_vm_func { typedef VEC(spl_vm_func_t) spl_vm_func_vec_t; /* Native function pointer type */ -typedef spl_vm_val_t (*spl_vm_fn_t)(int nargs, spl_vm_val_t *args); +struct spl_vm; +typedef struct spl_vm spl_vm_t; +typedef spl_vm_val_t (*spl_vm_fn_t)(spl_vm_t *vm, int nargs, spl_vm_val_t *args); typedef struct spl_vm_native { char *name; spl_vm_val_t idx_of_strtab; diff --git a/stage0/spl_syscall.c b/stage0/spl_syscall.c index e804f18..f2dc532 100644 --- a/stage0/spl_syscall.c +++ b/stage0/spl_syscall.c @@ -36,21 +36,21 @@ } while (0) #define SYSCALL_0(name, ret_expr) \ - static spl_vm_val_t name(int nargs, spl_vm_val_t *args) { \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ CHECK_NARGS(#name, 0); \ (void)args; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_1(name, t1, ret_expr) \ - static spl_vm_val_t name(int nargs, spl_vm_val_t *args) { \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ CHECK_NARGS(#name, 1); \ t1 a1 = (t1)(uintptr_t)args[0]; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_2(name, t1, t2, ret_expr) \ - static spl_vm_val_t name(int nargs, spl_vm_val_t *args) { \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ CHECK_NARGS(#name, 2); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ @@ -58,7 +58,7 @@ } #define SYSCALL_3(name, t1, t2, t3, ret_expr) \ - static spl_vm_val_t name(int nargs, spl_vm_val_t *args) { \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ CHECK_NARGS(#name, 3); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ @@ -67,7 +67,7 @@ } #define SYSCALL_4(name, t1, t2, t3, t4, ret_expr) \ - static spl_vm_val_t name(int nargs, spl_vm_val_t *args) { \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ CHECK_NARGS(#name, 4); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ @@ -76,6 +76,42 @@ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } +/* syscall / VM 内部统一地址检查宏。 + * 失败时打印 ctx + 地址 + size + ip,置 native_error,return 0。 + * 要求所在函数有可用的 _vm 变量。 */ +#define ADDRCHECK(vm, ptr, size, ctx) \ + do { \ + uintptr_t _acp = (uintptr_t)(ptr); \ + usize _acs = (usize)(size); \ + if (!spl_vm_addr_valid(_acp, _acs)) { \ + fprintf(stderr, "%s: invalid address %p size=%zu (ip=%zu fp=%zu sp=%zu)\n", (ctx), \ + (void *)_acp, _acs, (vm)->ip, (vm)->fp, (vm)->sp); \ + spl_vm_backtrace((vm), (vm)->fp); \ + (vm)->exit_code = 2; \ + return 0; \ + } \ + } while (0) + +/* syscall 内部:把当前栈和调用栈打印出来,供出错时定位 */ +#define SYSCALL_DUMP(vm) \ + do { \ + fprintf(stderr, " --- syscall dump (sp=%zu fp=%zu cp=%zu ip=%zu) ---\n", (vm)->sp, \ + (vm)->fp, (vm)->cp, (vm)->ip); \ + spl_vm_backtrace((vm), (vm)->fp); \ + spl_vm_stackdump((vm), (vm)->sp); \ + } while (0) + +/* syscall 内部:报告致命错误,dump 后让 VM 停在当前 ip */ +#define SYSCALL_FAIL(vm, ...) \ + do { \ + fprintf(stderr, "syscall error: "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + SYSCALL_DUMP(vm); \ + (vm)->exit_code = 1; \ + return 0; \ + } while (0) + /* ================================================================= * OS syscalls * ================================================================= */ @@ -108,7 +144,7 @@ SYSCALL_4(vm_fread, void *, size_t, size_t, FILE *, fread(a1, a2, a3, a4)) SYSCALL_4(vm_fwrite, const void *, size_t, size_t, FILE *, fwrite(a1, a2, a3, a4)) /* vm_fsize - get file size in bytes */ -static spl_vm_val_t vm_fsize(int nargs, spl_vm_val_t *args) { +static spl_vm_val_t vm_fsize(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_fsize", 1); FILE *f = (FILE *)(uintptr_t)args[0]; long cur = ftell(f); @@ -123,7 +159,7 @@ SYSCALL_0(vm_stdout, stdout) SYSCALL_0(vm_stderr, stderr) /* vm_read_file - read entire file into a malloc'd, null-terminated buffer */ -static spl_vm_val_t vm_read_file(int nargs, spl_vm_val_t *args) { +static spl_vm_val_t vm_read_file(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_read_file", 1); const char *path = (const char *)(uintptr_t)args[0]; if (path == nullptr) { @@ -149,28 +185,69 @@ static spl_vm_val_t vm_read_file(int nargs, spl_vm_val_t *args) { return (spl_vm_val_t)(uintptr_t)buf; } -/* vm_alloc - allocate memory (malloc) */ -SYSCALL_1(vm_alloc, size_t, (uintptr_t)malloc(a1)) +static spl_vm_val_t vm_alloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_alloc", 1); + size_t sz = (size_t)args[0]; + if (sz == 0) + SYSCALL_FAIL(_vm, "vm_alloc: zero size"); + if (sz > (size_t)1 << 32) + SYSCALL_FAIL(_vm, "vm_alloc: size too large (%zu)", sz); + void *p = malloc(sz); + if (!p) + SYSCALL_FAIL(_vm, "vm_alloc: malloc(%zu) failed", sz); + return (spl_vm_val_t)(uintptr_t)p; +} -/* vm_free - free memory */ -SYSCALL_1(vm_free, void *, (free(a1), (spl_vm_val_t)0)) +static spl_vm_val_t vm_free(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_free", 1); + void *p = (void *)(uintptr_t)args[0]; + if (p) + free(p); + return 0; +} -/* vm_realloc - reallocate memory (realloc) */ -SYSCALL_2(vm_realloc, void *, size_t, (uintptr_t)realloc(a1, a2)) +static spl_vm_val_t vm_realloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_realloc", 2); + void *p = (void *)(uintptr_t)args[0]; + size_t sz = (size_t)args[1]; + if (!p) + SYSCALL_FAIL(_vm, "vm_realloc: NULL ptr"); + if (sz == 0) + SYSCALL_FAIL(_vm, "vm_realloc: zero size"); + ADDRCHECK(_vm, p, 1, "vm_realloc"); + void *np = realloc(p, sz); + if (!np) + SYSCALL_FAIL(_vm, "vm_realloc: realloc(%p, %zu) failed", p, sz); + return (spl_vm_val_t)(uintptr_t)np; +} -/* vm_strlen - get string length */ -SYSCALL_1(vm_strlen, const char *, strlen(a1)) +static spl_vm_val_t vm_memcpy(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_memcpy", 3); + void *dst = (void *)(uintptr_t)args[0]; + const void *src = (const void *)(uintptr_t)args[1]; + size_t size = (size_t)args[2]; + if (size == 0) + return (spl_vm_val_t)(uintptr_t)dst; + ADDRCHECK(_vm, dst, size, "vm_memcpy(dst)"); + ADDRCHECK(_vm, src, size, "vm_memcpy(src)"); + memcpy(dst, src, size); + return (spl_vm_val_t)(uintptr_t)dst; +} -/* vm_strcmp - compare two strings */ -SYSCALL_2(vm_strcmp, const char *, const char *, strcmp(a1, a2)) +static spl_vm_val_t vm_memcmp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_memcmp", 3); + const void *a = (const void *)(uintptr_t)args[0]; + const void *b = (const void *)(uintptr_t)args[1]; + size_t size = (size_t)args[2]; + if (size == 0) + return 0; + ADDRCHECK(_vm, a, size, "vm_memcmp(a)"); + ADDRCHECK(_vm, b, size, "vm_memcmp(b)"); + return (spl_vm_val_t)memcmp(a, b, size); +} -/* 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) { +static spl_vm_val_t vm_printf(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { if (nargs <= 0) return 0; @@ -245,7 +322,7 @@ static spl_vm_val_t vm_printf(int nargs, spl_vm_val_t *args) { * ================================================================= */ /* vm_new - create a new sub-VM instance, returns spl_vm_t* */ -static spl_vm_val_t vm_new(int nargs, spl_vm_val_t *args) { +static spl_vm_val_t vm_new(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_new", 0); (void)args; spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t)); @@ -256,7 +333,7 @@ static spl_vm_val_t vm_new(int nargs, spl_vm_val_t *args) { } /* vm_drop - destroy a sub-VM and its loaded program */ -static spl_vm_val_t vm_drop(int nargs, spl_vm_val_t *args) { +static spl_vm_val_t vm_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_drop", 1); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; if (!vm) @@ -272,7 +349,7 @@ static spl_vm_val_t vm_drop(int nargs, spl_vm_val_t *args) { } /* vm_load - load a .sir file, register syscalls, return spl_prog_t* */ -static spl_vm_val_t vm_load(int nargs, spl_vm_val_t *args) { +static spl_vm_val_t vm_load(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_load", 2); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; const char *path = (const char *)(uintptr_t)args[1]; @@ -296,7 +373,7 @@ static spl_vm_val_t vm_load(int nargs, spl_vm_val_t *args) { } /* vm_push - push a value onto the sub-VM's stack (for passing arguments) */ -static spl_vm_val_t vm_push(int nargs, spl_vm_val_t *args) { +static spl_vm_val_t vm_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_push", 2); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; spl_vm_val_t val = args[1]; @@ -321,7 +398,7 @@ static spl_vm_val_t vm_push(int nargs, spl_vm_val_t *args) { * - Sets fp = sp - nargs (so arg0 = data[fp], arg1 = data[fp+1], ...) * - Sets ip to the function address */ -static spl_vm_val_t vm_call(int nargs, spl_vm_val_t *args) { +static spl_vm_val_t vm_call(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_call", 3); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; const char *name = (const char *)(uintptr_t)args[1]; @@ -387,8 +464,6 @@ void spl_syscall_register(spl_prog_t *prog) { {"vm_alloc", 0, vm_alloc}, {"vm_free", 0, vm_free}, {"vm_realloc", 0, vm_realloc}, - {"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}, diff --git a/stage0/spl_vm.c b/stage0/spl_vm.c index 7950489..686197e 100644 --- a/stage0/spl_vm.c +++ b/stage0/spl_vm.c @@ -587,6 +587,25 @@ void spl_vm_drop(spl_vm_t *vm) { vec_free(vm->breakpoints); } +// FIXME +int spl_vm_addr_valid(uintptr_t p, usize size) { + if (p == 0) + return 0; + if (p < 0x1000) + return 0; + uintptr_t max = + (sizeof(void *) == 8) ? (uintptr_t)0x00007FFFFFFFFFFFULL : (uintptr_t)0x7FFFFFFF; + if (p > max) + return 0; + if (size > 0) { + if (p + size < p) + return 0; + if (p + size > max) + return 0; + } + return 1; +} + void spl_vm_add_breakpoint(spl_vm_t *vm, usize ip) { if (!vm) return; @@ -1108,10 +1127,17 @@ int spl_vm_run_once(spl_vm_t *vm) { VM_ERROR(vm->error_msg); } spl_vm_val_t *_arg_base = vm->stacks.data + vm->sp - _nargs; - // spl_vm_stackdump(vm, vm->sp); - // printf("addr %p nargs %zd sp %zd stack %p arg_base %p\n", _nat->impl_fn, _nargs, vm->sp, - // vm->stacks.data, _arg_base); - spl_vm_val_t _result = _nat->impl_fn(_nargs, _arg_base); + spl_vm_val_t _result = _nat->impl_fn(vm, _nargs, _arg_base); + if (vm->exit_code) { + snprintf(vm->error_msg, sizeof(vm->error_msg), "NCALL %s failed (ip=%zd)", + _nat->name ? _nat->name : "?", vm->ip - 1); + fprintf(stderr, "native call: %s\n", _nat->name ? _nat->name : "?"); + fprintf(stderr, " nargs=%zd arg_base=%p sp=%zu\n", _nargs, (void *)_arg_base, + vm->sp); + spl_vm_backtrace(vm, vm->fp); + spl_vm_stackdump(vm, vm->sp); + return -1; + } vm->sp -= _nargs; PUSH(_result); break; diff --git a/stage0/spl_vm.h b/stage0/spl_vm.h index f73b0fd..b546c78 100644 --- a/stage0/spl_vm.h +++ b/stage0/spl_vm.h @@ -19,7 +19,7 @@ typedef struct { typedef VEC(spl_vm_val_t) spl_stack_vec_t; typedef VEC(spl_callframe_t) spl_frame_vec_t; -typedef struct { +typedef struct spl_vm { spl_stack_vec_t stacks; spl_frame_vec_t frames; uintptr_t gp; // global pointer @@ -52,6 +52,8 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth); /* Free dynamically allocated memory in VM */ void spl_vm_drop(spl_vm_t *vm); +int spl_vm_addr_valid(uintptr_t p, usize size); + int spl_vm_load_prog(spl_vm_t *vm, spl_prog_t *prog); int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv, const char **envp); diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index 6c2f591..3638efa 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -148,6 +148,7 @@ static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p); static spl_ast_node_ref_t parse_var_pattern(parser_t *p); static spl_ast_node_ref_t parse_match_pattern(parser_t *p); +static spl_ast_node_ref_t parse_cast(parser_t *p); static spl_ast_node_ref_t parse_prefix(parser_t *p); static spl_ast_node_ref_t parse_postfix(parser_t *p); static spl_ast_node_ref_t parse_primary(parser_t *p); @@ -1215,7 +1216,7 @@ static spl_binary_op_t token_to_binary_op(spl_tok_type_t tt) { } static spl_ast_node_ref_t parse_expr_prec(parser_t *p, int min_prec) { - spl_ast_node_ref_t left = parse_prefix(p); + spl_ast_node_ref_t left = parse_cast(p); if (p->failed) return left; @@ -1259,6 +1260,22 @@ static spl_ast_node_ref_t parse_expr(parser_t *p) { return parse_expr_prec(p, 1); // 最低优先级 } +static spl_ast_node_ref_t parse_cast(parser_t *p) { + spl_ast_node_ref_t expr = parse_prefix(p); + while (!p->failed) { + const spl_tok_t *t = peek(p); + if (!t || t->type != KW_AS || p->stop_as) + break; + advance(p); + spl_ast_node_ref_t type = parse_type_expr(p); + spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CAST, t); + node_at(p->ast, ref)->cast.expr = expr; + node_at(p->ast, ref)->cast.type = type; + expr = ref; + } + return expr; +} + static spl_ast_node_ref_t parse_prefix(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) @@ -1393,13 +1410,6 @@ static spl_ast_node_ref_t parse_postfix(parser_t *p) { node_at(p->ast, ref)->index.index = begin; expr = ref; } - } else if (t->type == KW_AS && !p->stop_as) { - advance(p); - spl_ast_node_ref_t type = parse_type_expr(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CAST, t); - node_at(p->ast, ref)->cast.expr = expr; - node_at(p->ast, ref)->cast.type = type; - expr = ref; } else { break; } diff --git a/stage1/spl_ir2vm.c b/stage1/spl_ir2vm.c index 1db3504..52e0561 100644 --- a/stage1/spl_ir2vm.c +++ b/stage1/spl_ir2vm.c @@ -152,7 +152,12 @@ static uint8_t vm_kind_of(spl_ir2vm_t *ctx, spl_type_id_t tid) { } } -static spl_type_id_t ir_result_tid(const spl_ir_node_t *n) { +/* 计算 IR 节点的"值类型"。 + * 语义区分: + * mem.offset(elem_t, ptr, off) → 结果类型 *elem_t + * mem.field(agg_t, base, idx) → 结果类型 *field_t + * 这两个 builder 的 .tid 存的是 pointee / aggregate,不能直接当结果类型用。 */ +static spl_type_id_t ir_result_tid(spl_ir2vm_t *ctx, const spl_ir_node_t *n) { switch (n->kind) { case SPL_IR_ARITH_ADD: case SPL_IR_ARITH_SUB: @@ -194,9 +199,12 @@ static spl_type_id_t ir_result_tid(const spl_ir_node_t *n) { case SPL_IR_MEM_LOAD: return n->mem_load.tid; case SPL_IR_MEM_OFFSET: - return n->mem_offset.tid; - case SPL_IR_MEM_FIELD_PTR: - return n->mem_field_ptr.tid; + return spl_type_builder_ptr((spl_type_t *)ctx->type, n->mem_offset.tid); + case SPL_IR_MEM_FIELD_PTR: { + spl_type_id_t field = + ir_agg_field_tid(ctx, n->mem_field_ptr.tid, n->mem_field_ptr.field_idx); + return spl_type_builder_ptr((spl_type_t *)ctx->type, field); + } case SPL_IR_TYPE_CONST: return n->type_const.tid; case SPL_IR_TYPE_BITSIZEOF: @@ -304,7 +312,7 @@ static void frame_build(frame_layout_t *fl, spl_ir2vm_t *ctx, spl_ir_func_ref_t for (usize i = 1; i < n; ++i) { const spl_ir_node_t *node = &vec_at(f->nodes, i); - if (ir_result_tid(node)) { + if (ir_result_tid(ctx, node)) { vec_at(fl->slots, i).result_off = off; off += sizeof(spl_vm_val_t); } @@ -786,7 +794,7 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { for (usize i = 0; i < nargs; ++i) { spl_ir_node_ref_t pref = vec_at(n->control_call.params, i); const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref); - spl_type_id_t ptid = ir_result_tid(pn); + spl_type_id_t ptid = ir_result_tid(ctx, pn); uint8_t pk = vm_kind_of(ctx, ptid); cg_load_slot(cg, pref, pk); } @@ -802,7 +810,7 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { for (usize i = 0; i < nargs; ++i) { spl_ir_node_ref_t pref = vec_at(n->control_call.params, i); const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref); - spl_type_id_t ptid = ir_result_tid(pn); + spl_type_id_t ptid = ir_result_tid(ctx, pn); uint8_t pk = vm_kind_of(ctx, ptid); cg_load_slot(cg, pref, pk); } diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index 0aac0ab..eeb55d8 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -651,9 +651,11 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, switch (n->kind) { case SPL_AST_EXPR_UNARY: { - /* & 与 .* 的结果类型由操作数决定,不能靠 expected 反向定型 */ + /* ADDRESS / DEREF 的结果类型由操作数决定,不能用 expected 反向定型。 + * 但不能直接 return ——— 那会绕过 expected 兼容性检查。 + * 走 break 落到兜底:infer 后做 is_subtype / comptime 判定。 */ if (n->unary.op == SPL_UNARY_OP_ADDRESS || n->unary.op == SPL_UNARY_OP_DEREF) - return sema_infer(sema, ref); + break; if (!sema_coerce(sema, n->unary.operand, expected)) return 0; n->resolved_lang_tid = expected; @@ -1213,7 +1215,8 @@ 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_coerce(sema, vec_at(n->call.args, i), pt); + if (!sema_coerce(sema, vec_at(n->call.args, i), pt)) + return 0; } /* varargs:默认提升到 isize */ if (has_varargs) {