diff --git a/App/lib/Projectrans/Config.vp b/App/lib/Projectrans/Config.vp index 2d845da..1aa5d48 100644 --- a/App/lib/Projectrans/Config.vp +++ b/App/lib/Projectrans/Config.vp @@ -481,7 +481,7 @@ def get_includes_binary_dir() -> str: def print_config(): """打印当前配置""" - buf: t.CChar | t.CPtr = VLogger.fmt_buf() + buf: str = VLogger.fmt_buf() if buf is None: return if ProjectName is not None: diff --git a/App/lib/core/BuildPipeline.vp b/App/lib/core/BuildPipeline.vp index 682332f..c159ab7 100644 --- a/App/lib/core/BuildPipeline.vp +++ b/App/lib/core/BuildPipeline.vp @@ -125,7 +125,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, # # SyntaxError: HandlesType.dump_parse_traceback(file_path) - fb_parse: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_parse: str = VLogger.fmt_buf() if fb_parse is not None: err_line: t.CInt = ast.get_parse_err_line() err_col: t.CInt = ast.get_parse_err_col() @@ -216,6 +216,10 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, gen.extract_module_docstrings(tree, sha1_val) ret: int = tr.translate(tree) if ret != 0: + fb_tf: str = VLogger.fmt_buf() + if fb_tf is not None: + viperlib.snprintf(fb_tf, 1024, "文件翻译失败: %s", file_path) + VLogger.error(fb_tf, "Translate") return None return tr @@ -396,7 +400,7 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s asan_path, ir_path) opt_ret: int = stdlib.system(opt_cmd) if opt_ret != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "opt ASan 插桩失败 (module=%s)", module_name) VLogger.error(fb, "ASAN") @@ -414,7 +418,7 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s # 避免 subprocess 管道捕获丢失输出 sys_ret: int = stdlib.system(cmd) if sys_ret != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "编译失败 (module=%s, cmd=%s)", module_name, cmd) VLogger.error(fb, "LLC") @@ -430,17 +434,20 @@ def _CollectObjFilesImpl(base_dir: str, bd_len: t.CSizeT, """ find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__()) if find_data is None: + VLogger.warning("_CollectObjFilesImpl 分配 find_data 失败,少收集 .obj", "collect") return out_pos string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__()) pattern: bytes = _mbuddy.alloc(bd_len + 8) if pattern is None: + VLogger.warning("_CollectObjFilesImpl 分配 pattern 失败,少收集 .obj", "collect") return out_pos viperlib.snprintf(pattern, bd_len + 8, "%s/*", base_dir) handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data) _mbuddy.free(pattern) if handle == w32.win32base.INVALID_HANDLE_VALUE: + VLogger.warning("_CollectObjFilesImpl 无法打开目录,少收集 .obj", "collect") return out_pos while True: @@ -543,7 +550,7 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f if includes_binary_dir is not None: extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE) if extra_len > 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "附加 %d 字节的 includes.binary .obj 文件", extra_len) VLogger.info(fb, "link") @@ -585,7 +592,7 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f VLogger.error("subprocess.run 返回 None", "link") return 1 if result.returncode != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "链接失败,返回码: %d", result.returncode) VLogger.error(fb, "link") @@ -628,7 +635,7 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT, # Step 1: 写 .ll 文件 ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name) if ret != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", module_name) VLogger.error(fb, "compile") @@ -714,7 +721,7 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT, stdio.printf("=== clang++ 链接错误输出 ===\n%s\n", result.stdout) if result.stderr is not None: stdio.printf("=== clang++ stderr ===\n%s\n", result.stderr) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "链接失败,返回码: %d, 命令: %s", result.returncode, cmd) VLogger.error(fb, "link") diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 89e5f4d..5751999 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -84,7 +84,8 @@ class AssignGenMixin: if k == ast.ASTKind.Constant: cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node) if cn.const_kind != ast.CONST_INT: - return 0 + # 非 INT 常量:直接报错终止(fail-fast) + HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") return cn.int_val # Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN @@ -100,7 +101,8 @@ class AssignGenMixin: return left_val + right_val if bop.op == ast.OpKind.Sub: return left_val - right_val - return 0 + # 未知 BinOp 运算符:直接报错终止(fail-fast) + HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") # Case 3: Name — 引用已注册的 CDefine 常量 if k == ast.ASTKind.Name: @@ -109,7 +111,8 @@ class AssignGenMixin: looked_up: int = HandlesType.lookup_cdefine_constant(nm.id) if HandlesType.is_cdefine_found() != 0: return looked_up - return 0 + # 引用未注册:直接报错终止(fail-fast) + HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") # Case 4: Call — 如 t.CUnsignedLong(-11) if k == ast.ASTKind.Call: @@ -121,7 +124,8 @@ class AssignGenMixin: first_arg: ast.AST | t.CPtr = cl_args_list.get(0) arg_val: int = self.extract_cdefine_int_value(first_arg) return arg_val - return 0 + # Call 无参数:直接报错终止(fail-fast) + HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") # Case 5: UnaryOp — 如 -11 if k == ast.ASTKind.UnaryOp: @@ -133,9 +137,11 @@ class AssignGenMixin: return operand_val if uop.op == ast.OpKind.Invert: return ~operand_val - return 0 + # 未知 UnaryOp 运算符:直接报错终止(fail-fast) + HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") - return 0 + # 未知节点类型:直接报错终止(fail-fast) + HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") # ============================================================ # _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别) @@ -158,8 +164,16 @@ class AssignGenMixin: rec_d: t.CDouble = 0.0 if self._recover_cdefine_float(name, t.CPtr(c.Addr(rec_d))) != 0: use_val = rec_d + else: + # 源文件恢复失败:直接报错终止(fail-fast),避免注册被 pool 覆写的错误浮点值 + HandlesType.fatal_error(val_node, "CDefine 浮点值源文件恢复失败", "InternalCompilerError") + return HandlesType.register_cdefine_double(pool, name, use_val) return + if val_node is None: + # CDefine 声明缺少值节点:直接报错终止(fail-fast) + HandlesType.fatal_error(None, f"CDefine 值提取失败:'{name}' 缺少初始值", "TypeError") + return val_fp: int = self.extract_cdefine_int_value(val_node) HandlesType.register_cdefine_constant(pool, name, val_fp) @@ -484,17 +498,19 @@ class AssignGenMixin: elem_node: ast.AST | t.CPtr = elts.get(i) elem_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, elem_node, None, 0, trans) - if elem_val is not None: - idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i) - elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_ty, elem_ty, array_alloca, idx_val) - if elem_ptr is not None: - # 类型转换(如 i32 → i8 截断) - store_val: llvmlite.Value | t.CPtr = elem_val - if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: - store_val = HandlesExpr.coerce_to_type( - builder, elem_val, elem_ptr.Ty.Pointee, elem_node) - llvmlite.build_store(builder, store_val, elem_ptr) + if elem_val is None: + # 元素翻译失败:直接报错终止(fail-fast),暴露上游根因 + HandlesType.fatal_error(elem_node, "全局数组初始化元素翻译失败", "TypeError") + idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i) + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_ty, elem_ty, array_alloca, idx_val) + if elem_ptr is not None: + # 类型转换(如 i32 → i8 截断) + store_val: llvmlite.Value | t.CPtr = elem_val + if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: + store_val = HandlesExpr.coerce_to_type( + builder, elem_val, elem_ptr.Ty.Pointee, elem_node) + llvmlite.build_store(builder, store_val, elem_ptr) i += 1 return 0 diff --git a/App/lib/core/Gen/BaseGenMixin.vp b/App/lib/core/Gen/BaseGenMixin.vp index 3e04ab1..139fa6e 100644 --- a/App/lib/core/Gen/BaseGenMixin.vp +++ b/App/lib/core/Gen/BaseGenMixin.vp @@ -29,7 +29,7 @@ class BaseGenMixin: # 符号表/函数表 SymTab: HandlesVar.SymbolTable | t.CPtr Funcs: HandlesExprCall.FuncEntry | t.CPtr - FuncCount: t.CInt + FuncCount: int # 导入/模块信息 ImportedModules: str FromImports: str diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index c58495b..e37bdb5 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -88,11 +88,11 @@ class CallGenMixin: TempDirLen: t.CSizeT # --- 闭包名表(原 _g_closure_names/_g_closure_count) --- - ClosureNames: t.CChar | t.CPtr + ClosureNames: str ClosureCount: int # --- 函数指针签名表(原 _g_funcptr_names/_g_funcptr_rets/_g_funcptr_count) --- - FuncptrNames: t.CChar | t.CPtr + FuncptrNames: str FuncptrRets: t.CUInt64T | t.CPtr FuncptrCount: int @@ -236,7 +236,7 @@ class CallGenMixin: cur: llvmlite.Function | t.CPtr = mod.FuncHead # 第一遍:精确匹配 while cur is not None: - cur_name: t.CChar | t.CPtr = llvmlite.function_get_name(cur) + cur_name: str = llvmlite.function_get_name(cur) if cur_name is not None: if string.strcmp(cur_name, name) == 0: return cur @@ -253,7 +253,7 @@ class CallGenMixin: # cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。 cur = mod.FuncHead while cur is not None: - cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur) + cur_name2: str = llvmlite.function_get_name(cur) if cur_name2 is not None: cur_len: t.CSizeT = string.strlen(cur_name2) if cur_len > name_len + 1: @@ -271,7 +271,7 @@ class CallGenMixin: # 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用) cur = mod.FuncHead while cur is not None: - cur_name3: t.CChar | t.CPtr = llvmlite.function_get_name(cur) + cur_name3: str = llvmlite.function_get_name(cur) if cur_name3 is not None: cur_len3: t.CSizeT = string.strlen(cur_name3) if cur_len3 > name_len + 1: @@ -598,7 +598,7 @@ class CallGenMixin: """ if call_name is None: return 0 - first_dot: t.CChar | t.CPtr = string.strchr(call_name, '.') + first_dot: str = string.strchr(call_name, '.') if first_dot is None: return 0 pre_len: t.CSizeT = t.CSizeT(t.CUInt64T(first_dot) - t.CUInt64T(call_name)) @@ -728,7 +728,16 @@ class CallGenMixin: # 掩盖了缺陷。 match pointee: case llvmlite.LLVMType.Int(pointee_width): - if pointee_width == 8 and trans is not None and trans.CurAssignAnnot is not None: + # 仅当 c.Deref 是赋值语句的直接 RHS(如 v: int = c.Deref(p)) + # 时才用注解推断读取宽度(对齐 TPC _infer_deref_target_type + # 的直接 RHS 检查);嵌套在 while 条件/比较/binop/类型转换 + # 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p))) + # 不推断,否则 i8* 会被残留 CurAssignAnnot 误判为 i32* + # 读 4 字节 → StringIterTest ASCII sum/manual strcmp 失败。 + if pointee_width == 8 and trans is not None \ + and trans.CurAssignAnnot is not None \ + and trans.CurAssignNode is not None \ + and t.CUInt64T(cl) == t.CUInt64T(trans.CurAssignNode): dref_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( trans.Pool, trans.CurAssignAnnot, trans._imported_modules, trans._from_imports, trans) @@ -746,8 +755,9 @@ class CallGenMixin: case _: pass return llvmlite.build_load(builder, pointee, ptr_val) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - return llvmlite.build_load(builder, i8_ty, ptr_val) + # 非指针参数即类型推断退化:fail-fast,绝不按 i8 兜底读取(会读到垃圾宽度) + HandlesType.fatal_error(cl, "c.Deref 参数不是指针类型(类型推断退化)", "TypeError") + return None def translate_c_derefas(self, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, @@ -1028,8 +1038,8 @@ class CallGenMixin: llvmlite.build_store(builder, loaded, dst_cast) return loaded - def _asm_append_cstr(self, dst: t.CChar | t.CPtr, dst_size: t.CSizeT, - src: t.CChar | t.CPtr): + def _asm_append_cstr(self, dst: str, dst_size: t.CSizeT, + src: str): """将 C 字符串 src 追加到 dst 末尾""" if dst is None or src is None: return @@ -1045,12 +1055,12 @@ class CallGenMixin: dst[dlen + i] = '\0' def _asm_escape_for_ir(self, pool: memhub.MemBuddy | t.CPtr, - src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + src: str) -> str: """转义汇编文本用于 LLVM IR 字符串字面量""" if src is None: return None slen: t.CSizeT = string.strlen(src) - buf: t.CChar | t.CPtr = pool.alloc(slen * 4 + 8) + buf: str = pool.alloc(slen * 4 + 8) if buf is None: return None pos: t.CSizeT = 0 @@ -1292,7 +1302,7 @@ class CallGenMixin: string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS) # 分配 asm 文本缓冲区 - asm_text: t.CChar | t.CPtr = pool.alloc(ASM_TEXT_BUF_SIZE) + asm_text: str = pool.alloc(ASM_TEXT_BUF_SIZE) if asm_text is None: return None asm_text[0] = '\0' @@ -1545,6 +1555,8 @@ class CallGenMixin: if out_pn_head is not None and out_pn_n > 0: ret_ty = llvmlite.Struct(pool, out_pn_head, out_pn_n, None) else: + HandlesType.fatal_error( + cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") ret_ty = llvmlite.Int32(pool) else: out_op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, first_output_idx) @@ -1553,6 +1565,8 @@ class CallGenMixin: if out_op.Value.Ty.Pointee is not None: ret_ty = out_op.Value.Ty.Pointee else: + HandlesType.fatal_error( + cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") ret_ty = llvmlite.Int32(pool) # 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题 @@ -1613,7 +1627,7 @@ class CallGenMixin: if fv_fi < fv_count: orig_idx2: int = fv_orig_indices[fv_fi] new_idx2: int = orig_to_new[orig_idx2] - ph_buf2: t.CChar | t.CPtr = pool.alloc(16) + ph_buf2: str = pool.alloc(16) if ph_buf2 is not None: viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2) self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2) @@ -1626,7 +1640,7 @@ class CallGenMixin: # ============================================================ # 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后) # ============================================================ - const_buf: t.CChar | t.CPtr = pool.alloc(ASM_CONST_BUF_SIZE) + const_buf: str = pool.alloc(ASM_CONST_BUF_SIZE) if const_buf is None: return None const_buf[0] = '\0' @@ -1667,7 +1681,7 @@ class CallGenMixin: # ============================================================ # 6. 构建参数列表文本(仅输入操作数) # ============================================================ - args_buf: t.CChar | t.CPtr = pool.alloc(ASM_ARGS_BUF_SIZE) + args_buf: str = pool.alloc(ASM_ARGS_BUF_SIZE) if args_buf is None: return None args_buf[0] = '\0' @@ -1687,7 +1701,7 @@ class CallGenMixin: first_arg = 0 # 类型文本 - ty_buf: t.CChar | t.CPtr = pool.alloc(64) + ty_buf: str = pool.alloc(64) if ty_buf is not None: ty_buf[0] = '\0' llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool) @@ -1698,19 +1712,19 @@ class CallGenMixin: # ============================================================ # 7. 转义汇编文本 # ============================================================ - escaped_asm: t.CChar | t.CPtr = self._asm_escape_for_ir(pool, asm_text) + escaped_asm: str = self._asm_escape_for_ir(pool, asm_text) if escaped_asm is None: return None # ============================================================ # 8. 生成 IR 行并发射 # ============================================================ - line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE) + line: str = pool.alloc(ASM_LINE_BUF_SIZE) if line is None: return None line[0] = '\0' - ssa_name: t.CChar | t.CPtr = None + ssa_name: str = None if is_void == 0: ssa_name = pool.alloc(16) if ssa_name is not None: @@ -1718,7 +1732,7 @@ class CallGenMixin: builder.Counter += 1 # 获取返回类型文本 - ret_ty_buf: t.CChar | t.CPtr = pool.alloc(64) + ret_ty_buf: str = pool.alloc(64) if ret_ty_buf is not None: ret_ty_buf[0] = '\0' llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool) @@ -1750,8 +1764,8 @@ class CallGenMixin: # 多输出:extractvalue 取第 out_emit_idx 个元素后 store if oo.Value is not None and oo.Value.Ty is not None \ and oo.Value.Ty.Pointee is not None: - ev_name: t.CChar | t.CPtr = pool.alloc(32) - ev_line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE) + ev_name: str = pool.alloc(32) + ev_line: str = pool.alloc(ASM_LINE_BUF_SIZE) if ev_name is not None and ev_line is not None: # ssa_name 形如 "%N"(纯数字 ID),构造唯一名 # "%asm.N.e{i}"(字母开头,避免 %N.e{i} 被解析为 @@ -1800,7 +1814,7 @@ class CallGenMixin: out_count: int = 0 # 模板文本缓冲区 - text: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) + text: str = pool.alloc(LLVMIR_TEMPLATE_BUF) if text is None: return None text[0] = '\0' @@ -1897,7 +1911,7 @@ class CallGenMixin: oi: int for oi in range(out_count): oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr)) - rn: str = (t.CChar | t.CPtr)(t.CVoid(out_regname[oi], t.CPtr)) + rn: str = (str)(t.CVoid(out_regname[oi], t.CPtr)) if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None: continue reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) @@ -2020,7 +2034,7 @@ class CallGenMixin: # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) if is_oop == 0 and class_name is not None: - init_lookup_name: t.CChar | t.CPtr = pool.alloc(128) + init_lookup_name: str = pool.alloc(128) if init_lookup_name is not None: viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name) # 方案1: 检查当前模块的函数声明 @@ -2263,7 +2277,7 @@ class CallGenMixin: if renum_entry is None: renum_entry = HandlesStruct.find_struct(class_name) if renum_entry is None: - fb_re: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_re: str = VLogger.fmt_buf() if fb_re is not None: viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name) VLogger.error(fb_re, "RENUM") @@ -2286,7 +2300,7 @@ class CallGenMixin: # 写入 __tag 字段(索引 0) i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - tag_name_buf: t.CChar | t.CPtr = pool.alloc(32) + tag_name_buf: str = pool.alloc(32) if tag_name_buf is not None: viperlib.snprintf(tag_name_buf, 32, "%d", tag_value) tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt( @@ -2540,7 +2554,7 @@ class CallGenMixin: cmop_struct_ty = cmop_entry.Ty # 构造方法查找名: ClassName.method_name - lookup_name: t.CChar | t.CPtr = pool.alloc(128) + lookup_name: str = pool.alloc(128) if lookup_name is None: return None viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) @@ -2551,7 +2565,7 @@ class CallGenMixin: # 确定调用名 call_name: str = lookup_name if found_func is not None: - found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + found_name: str = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name else: @@ -2566,7 +2580,7 @@ class CallGenMixin: # fallback: 从 from_imports 查找类所属模块的 SHA1(含截断处理) cls_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, class_name) if cls_sha1 is None: - err_msg: t.CChar | t.CPtr = pool.alloc(256) + err_msg: str = pool.alloc(256) if err_msg is not None: viperlib.snprintf(err_msg, 256, "类 '%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name) HandlesType.fatal_error(node, err_msg) @@ -2587,7 +2601,7 @@ class CallGenMixin: elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0: # fail-fast:__getitem__/__new__ 必返回指针,返回类型缺失意味着 # stub declare 损坏,静默推断会截断指针(32 位)崩溃,立即终止。 - err_cm1: t.CChar | t.CPtr = pool.alloc(256) + err_cm1: str = pool.alloc(256) if err_cm1 is not None: viperlib.snprintf(err_cm1, 256, "方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)", method_name) @@ -2605,14 +2619,14 @@ class CallGenMixin: if cmop_struct_ty is not None: call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty) else: - err_cm2: t.CChar | t.CPtr = pool.alloc(256) + err_cm2: str = pool.alloc(256) if err_cm2 is not None: viperlib.snprintf(err_cm2, 256, "方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)", method_name) HandlesType.fatal_error(node, err_cm2) HandlesType.fatal_error(node, "self 结构体类型未知") elif string.strcmp(method_name, "__getitem__") == 0: - err_cm3: t.CChar | t.CPtr = pool.alloc(256) + err_cm3: str = pool.alloc(256) if err_cm3 is not None: viperlib.snprintf(err_cm3, 256, "方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型", @@ -2690,38 +2704,14 @@ class CallGenMixin: total_count += 1 mdf_pi += 1 continue - # 无默认值时用零值兜底(需要 found_func 获取参数类型) - if found_func is not None: - param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - skip_z: int = 0 - while skip_z <= mdf_pi and param_node_z is not None: - param_node_z = llvmlite.param_get_next(param_node_z) - skip_z += 1 - if param_node_z is not None: - zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z) - zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty) - if zero_val is not None: - llvmlite.value_set_next(zero_val, None) - llvmlite.value_set_next(tail, zero_val) - tail = zero_val - total_count += 1 + # 无默认值即必传参数缺失:fail-fast,绝不零值兜底 + HandlesType.fatal_error( + node, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError") mdf_pi += 1 elif found_func is not None: - # 无默认参数信息但有 found_func:用零值填充(保留原有逻辑) - param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - skip_idx: int = 0 - while skip_idx < total_count and param_node is not None: - param_node = llvmlite.param_get_next(param_node) - skip_idx += 1 - while param_node is not None: - missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node) - zero_val2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty) - if zero_val2 is not None: - llvmlite.value_set_next(zero_val2, None) - llvmlite.value_set_next(tail, zero_val2) - tail = zero_val2 - total_count += 1 - param_node = llvmlite.param_get_next(param_node) + # 无默认参数信息但有 found_func:剩余形参即调用缺参(无默认值),fail-fast + HandlesType.fatal_error( + node, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError") # 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0) # 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT), @@ -2857,7 +2847,7 @@ class CallGenMixin: # _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型 # # 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc → - # "t.CChar | t.CPtr")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 + # "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 # 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。 # 无需硬编码白名单——返回类型始终来自方法定义处。 # ============================================================ @@ -3256,7 +3246,7 @@ class CallGenMixin: return None # 构造查找名: ClassName.method_name - lookup_name: t.CChar | t.CPtr = pool.alloc(128) + lookup_name: str = pool.alloc(128) if lookup_name is None: return None viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) @@ -3267,7 +3257,7 @@ class CallGenMixin: # 确定调用名 call_name: str = lookup_name if found_func is not None: - found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + found_name: str = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name else: @@ -3358,7 +3348,7 @@ class CallGenMixin: trans.SymTab, obj_nm.id) if var_entry is not None and var_entry.AnnotClassName is not None: annot_val: str = var_entry.AnnotClassName - dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.') + dot_ptr: str = string.strrchr(annot_val, '.') if dot_ptr is not None: return dot_ptr + 1 return annot_val @@ -3429,7 +3419,7 @@ class CallGenMixin: llvmlite.value_set_next(rhs_val, None) llvmlite.value_set_next(obj_val, rhs_val) # setter 函数名带 $set 后缀 - setter_name_buf: t.CChar | t.CPtr = pool.alloc(128) + setter_name_buf: str = pool.alloc(128) if setter_name_buf is None: return 0 viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr) @@ -3466,7 +3456,7 @@ class CallGenMixin: return 0 llvmlite.value_set_next(obj_val, None) # deleter 函数名带 $del 后缀 - del_name_buf: t.CChar | t.CPtr = pool.alloc(128) + del_name_buf: str = pool.alloc(128) if del_name_buf is None: return 0 viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr) @@ -3580,7 +3570,7 @@ class CallGenMixin: mc_entry = HandlesStruct.find_struct(class_name) # 构造方法查找名: ClassName.method_name - lookup_name: t.CChar | t.CPtr = pool.alloc(128) + lookup_name: str = pool.alloc(128) if lookup_name is None: return None viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) @@ -3593,7 +3583,7 @@ class CallGenMixin: # 用对象实际特化名(mc_entry.Name)构造后缀匹配,获得精确返回类型。 if found_func is None and mc_entry is not None and mc_entry.Name is not None: if string.strcmp(mc_entry.Name, class_name) != 0: - spec_lookup: t.CChar | t.CPtr = pool.alloc(160) + spec_lookup: str = pool.alloc(160) if spec_lookup is not None: viperlib.snprintf(spec_lookup, 160, "%s.%s", mc_entry.Name, method_name) found_func = self.find_func_in_module(mod, spec_lookup) @@ -3606,7 +3596,7 @@ class CallGenMixin: while mro_ptr is not None and mro_ptr[mi] != 0: anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) if anc is not None: - parent_lookup: t.CChar | t.CPtr = pool.alloc(128) + parent_lookup: str = pool.alloc(128) if parent_lookup is not None: viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, method_name) parent_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, parent_lookup) @@ -3619,7 +3609,7 @@ class CallGenMixin: # 确定调用名 call_name: str = lookup_name if found_func is not None: - found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + found_name: str = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name else: @@ -3805,7 +3795,7 @@ class CallGenMixin: if pi_k < can: arg_node_k = cargs.get(pi_k) else: - pname_k: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param_k) + pname_k: str = llvmlite.param_get_name(cur_param_k) if pname_k is not None: ki_k: int for ki_k in range(kwc): @@ -3820,10 +3810,8 @@ class CallGenMixin: arg_val_k = HandlesExpr.translate_value( builder, pool, mod, arg_node_k, None, 0, trans) if arg_val_k is None: - # 缺失参数:零值兜底(保持参数数量匹配) - pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) - if pty_k is not None: - arg_val_k = llvmlite.ConstZero(pool, pty_k) + # 缺失参数且无默认值必传:fail-fast,绝不零值兜底(会静默吞掉调用错误) + HandlesType.fatal_error(cl, f"方法 '{lookup_name}' 缺少必传参数", "TypeError") if arg_val_k is not None: pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) if pty_k2 is not None: @@ -3936,21 +3924,9 @@ class CallGenMixin: total_count += 1 mdf_pi += 1 continue - # 无默认值时用零值兜底(需要 found_func 获取参数类型) - if found_func is not None: - param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - skip_z: int = 0 - while skip_z <= mdf_pi and param_node_z is not None: - param_node_z = llvmlite.param_get_next(param_node_z) - skip_z += 1 - if param_node_z is not None: - zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z) - zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty) - if zero_val is not None: - llvmlite.value_set_next(zero_val, None) - llvmlite.value_set_next(tail, zero_val) - tail = zero_val - total_count += 1 + # 无默认值即必传参数缺失:fail-fast,绝不零值兜底 + HandlesType.fatal_error( + cl, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError") mdf_pi += 1 # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 @@ -4030,7 +4006,7 @@ class CallGenMixin: while mro_sp is not None and mro_sp[mi_sp] != 0: anc_sp: str = (str | t.CPtr)(t.CVoid(mro_sp[mi_sp], t.CPtr)) if anc_sp is not None: - probe_sp: t.CChar | t.CPtr = pool.alloc(160) + probe_sp: str = pool.alloc(160) if probe_sp is not None: viperlib.snprintf(probe_sp, 160, "%s.%s", anc_sp, method_name) if HandlesExprCall.find_func_global(probe_sp) is not None: @@ -4038,7 +4014,7 @@ class CallGenMixin: break mi_sp += 1 if anc is None: - err_sp: t.CChar | t.CPtr = pool.alloc(256) + err_sp: str = pool.alloc(256) if err_sp is not None: viperlib.snprintf(err_sp, 256, "super(): 当前类 %s 的父类链未定义方法 %s", cur_class, method_name) @@ -4104,7 +4080,7 @@ class CallGenMixin: anc_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_sp.Ty) self_arg = llvmlite.build_bitcast(builder, adj_sp, anc_ptr_sp) # 4. 查找父类方法函数 + 构造调用名(SHA1 mangled) - anc_lookup: t.CChar | t.CPtr = pool.alloc(160) + anc_lookup: str = pool.alloc(160) if anc_lookup is None: return None viperlib.snprintf(anc_lookup, 160, "%s.%s", anc, method_name) @@ -4114,7 +4090,7 @@ class CallGenMixin: if anc_sha1_sp is None: anc_sha1_sp = trans.ModuleSha1 if found_func is not None: - fname_sp: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + fname_sp: str = llvmlite.function_get_name(found_func) if fname_sp is not None: call_name = fname_sp else: @@ -4186,6 +4162,15 @@ class CallGenMixin: pool, anc_sha1_sp, anc, method_name) if looked_sp is not None: ret_ty_sp = looked_sp + else: + vpi_ret_sp: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( + pool, anc_sha1_sp, anc, method_name) + if vpi_ret_sp is not None: + ret_ty_sp = vpi_ret_sp + else: + # 查找链(函数/text.ll/vpi stub)全部未命中:fail-fast, + # 绝不静默保持默认 i32(会截断指针/i64 返回值) + self._fail_method_ret_ty(method_name, cl) # 7. 跨模块:创建 declare;生成 call if found_func is None: self._ensure_method_declare(pool, mod, call_name, ret_ty_sp, head, arg_count_sp) @@ -4242,7 +4227,7 @@ class CallGenMixin: # 跳过 % 前缀后逐字符比较 # ============================================================ def _kwarg_name_matches(self, kw_arg: str, - param_name: t.CChar | t.CPtr) -> int: + param_name: str) -> int: """检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)""" if kw_arg is None or param_name is None: return 0 @@ -4295,7 +4280,7 @@ class CallGenMixin: # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) if is_oop == 0 and class_name is not None: - kw_init_lookup: t.CChar | t.CPtr = pool.alloc(128) + kw_init_lookup: str = pool.alloc(128) if kw_init_lookup is not None: viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name) # 方案1: 检查当前模块的函数声明 @@ -4438,6 +4423,9 @@ class CallGenMixin: else: fe = HandlesStruct.get_field_by_index(class_name, ai) if fe is None: + # 位置参数越界(字段表无对应项):fail-fast,绝不静默跳过 + HandlesType.fatal_error( + arg, f"结构体 '{class_name}' 位置参数越界(无对应字段)", "TypeError") continue field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( builder, struct_ty, fe.Ty, tmp, fe.Index) @@ -4458,6 +4446,9 @@ class CallGenMixin: fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class( class_name, kw.arg, kw_sha1) if fe is None: + # 关键字字段不存在:fail-fast(AttributeError),绝不静默跳过 + HandlesType.fatal_error( + kw, f"结构体 '{class_name}' 无字段 '{kw.arg}'", "AttributeError") continue kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, kw.value, None, 0, trans) @@ -4523,7 +4514,7 @@ class CallGenMixin: builder, pool, mod, arg, None, 0, trans) else: # 查找匹配的关键字参数 - param_name: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param) + param_name: str = llvmlite.param_get_name(cur_param) if param_name is not None: for ki in range(kw_count): kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) @@ -4564,7 +4555,7 @@ class CallGenMixin: # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference call_name: str = func_name - found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + found_name: str = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name @@ -4715,14 +4706,19 @@ class CallGenMixin: # 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 # ============================================================ def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy | t.CPtr, - arg_node: ast.AST | t.CPtr) -> str: - """从构造实参 AST 推断泛型类型实参名;无法推断时默认 "int"(与 TPC 一致) + arg_node: ast.AST | t.CPtr, + class_name: str) -> str: + """从构造实参 AST 推断泛型类型实参名;无法推断时 fail-fast(绝不默认 "int") 裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。 对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。 注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。 """ if pool is None or arg_node is None: + HandlesType.fatal_error( + None, + f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", + "TypeError") return "int" k: int = arg_node.kind() # 常量: 42→int, 3.14→double, "abc"→str @@ -4751,6 +4747,11 @@ class CallGenMixin: return "double" if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None: return "int" + # 无法从 AST 静态推断:fail-fast,绝不静默默认 "int"(会特化出错误类型) + HandlesType.fatal_error( + arg_node, + f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", + "TypeError") return "int" def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr, @@ -5022,7 +5023,7 @@ class CallGenMixin: funcs_ptr, func_count, trans) # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 - # 等价于 (t.CChar | t.CPtr)(x) / (t.CInt32T)(x) + # 等价于 (str)(x) / (t.CInt32T)(x) # 单参数:str(val) → bitcast val to i8* # int(val) → trunc/sext val to i32 # 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名 @@ -5349,7 +5350,9 @@ class CallGenMixin: # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, # 导致 llc 报错 "base of getelementptr must be a pointer" if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: - return llvmlite.const_int64(pool, 0) + # 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误 + HandlesType.fatal_error( + len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError") i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) # 注意: 必须用 const_int64 而非 ConstInt(...,"0") # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 @@ -5407,7 +5410,7 @@ class CallGenMixin: len_cls_nm: str = HandlesStruct.get_class_name_by_type( pool, len_struct_ty) if len_cls_nm is not None: - len_lookup: t.CChar | t.CPtr = pool.alloc(128) + len_lookup: str = pool.alloc(128) if len_lookup is not None: viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm) len_fn2: llvmlite.Function | t.CPtr = self.find_func_in_module( @@ -5415,7 +5418,7 @@ class CallGenMixin: if len_fn2 is not None: len_ret_ty2: llvmlite.LLVMType | t.CPtr = \ llvmlite.function_get_ret_ty(len_fn2) - len_fn_name2: t.CChar | t.CPtr = \ + len_fn_name2: str = \ llvmlite.function_get_name(len_fn2) if len_ret_ty2 is not None and len_fn_name2 is not None: # self 参数类型对齐(按方法首个形参 bitcast) @@ -5538,7 +5541,7 @@ class CallGenMixin: if var_entry is not None and var_entry.AnnotClassName is not None: annot_val: str = var_entry.AnnotClassName # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" - dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.') + dot_ptr: str = string.strrchr(annot_val, '.') cls_nm2: str = annot_val mod_nm2: str = None if dot_ptr is not None: @@ -5673,7 +5676,7 @@ class CallGenMixin: if field_info is not None: field_annot: str = HandlesStruct.get_field_annot_class_name(field_info) if field_annot is not None: - dot_p: t.CChar | t.CPtr = string.strrchr(field_annot, 46) + dot_p: str = string.strrchr(field_annot, 46) if dot_p is not None: field_cls_nm = dot_p + 1 else: @@ -5715,15 +5718,10 @@ class CallGenMixin: # 可能返回 i32 0 (非指针),直接 GEP 会导致 # "base of getelementptr must be a pointer" 错误 if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0: - lm_node_kind: int = lm_at.value.kind() - fb_lm: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_lm is not None: - viperlib.snprintf(fb_lm, 1024, - "list 方法 '%s' 的目标对象非指针 (node kind=%d)," - "translate_value 类型推断失败", - lm_name, lm_node_kind) - VLogger.critical(fb_lm, "LIST-METHOD") - return None + # translate_value 类型推断失败(目标对象非指针): + # fail-fast,绝不 VLogger.critical 后 return None 静默吞掉 + HandlesType.fatal_error( + lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError") i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) @@ -5816,6 +5814,12 @@ class CallGenMixin: elif string.strcmp(lm_name, "append") == 0: if can >= 1: ap_sha1: str = self._lookup_module_sha1("_list") + if ap_sha1 is None: + # 依赖模块未编译(_list 未预加入编译链):fail-fast, + # 绝不静默跳过 append(元素永远不会被加入列表) + HandlesType.fatal_error( + cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", + "InternalCompilerError") if ap_sha1 is not None: ap_mlen: t.CSizeT = string.strlen(ap_sha1) + 13 ap_mangled: str = pool.alloc(ap_mlen) @@ -5974,7 +5978,7 @@ class CallGenMixin: if hint_bare is not None: hi_bare: t.CSizeT for hi_bare in range(can): - hty_bare: str = self._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare)) + hty_bare: str = self._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare), func_name) if string.strcmp(hty_bare, "int") != 0: hint_bare.append(hty_bare) tpi_bare: t.CSizeT = 0 @@ -5983,7 +5987,7 @@ class CallGenMixin: if tpi_bare < len(hint_bare): ta_bare = hint_bare.get(tpi_bare) elif tpi_bare < can: - ta_bare = self._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare)) + ta_bare = self._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare), func_name) inferred_args_bare.append(ta_bare) spec_name_bare: str = HandlesClassDef._specialize_generic_class( trans, func_name, inferred_args_bare) @@ -6040,7 +6044,7 @@ class CallGenMixin: # 模块函数(SHA1.func)或子模块函数(SHA1.submod.func)的后缀匹配保留。 found_func = self.find_func_in_module(mod, func_name) if found_func is not None: - ff_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + ff_name: str = llvmlite.function_get_name(found_func) if ff_name is not None: ff_dots: int = 0 ffi2: t.CSizeT = 0 @@ -6050,7 +6054,7 @@ class CallGenMixin: ffi2 += 1 if ff_dots >= 2: # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) - seg2: t.CChar | t.CPtr = pool.alloc(64) + seg2: str = pool.alloc(64) if seg2 is not None: seg2[0] = '\0' si: t.CSizeT = 0 @@ -6318,7 +6322,7 @@ class CallGenMixin: # 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败 orig_func_name: str = None if found_func is not None: - found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + found_name: str = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name else: @@ -6340,7 +6344,7 @@ class CallGenMixin: is_xmod_imported = HandlesImports.is_module_imported( trans._imported_modules, xmod_nm.id) if is_xmod_imported == 0: - err_ni: t.CChar | t.CPtr = pool.alloc(256) + err_ni: str = pool.alloc(256) if err_ni is not None: viperlib.snprintf(err_ni, 256, "跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)", @@ -6393,7 +6397,7 @@ class CallGenMixin: call_name = alias_mangled else: # 已导入模块但 SHA1 未注册:该模块未被编译,立即报错 - err_msg_imp: t.CChar | t.CPtr = pool.alloc(256) + err_msg_imp: str = pool.alloc(256) if err_msg_imp is not None: viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_nm.id) HandlesType.fatal_error(xmod_nm, err_msg_imp) @@ -6417,7 +6421,7 @@ class CallGenMixin: viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name) call_name = fmangled else: - err_msg2: t.CChar | t.CPtr = pool.alloc(256) + err_msg2: str = pool.alloc(256) if err_msg2 is not None: viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_nm.id, func_name) HandlesType.fatal_error(xmod_nm, err_msg2) @@ -6464,13 +6468,13 @@ class CallGenMixin: viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name) call_name = bare_mangled else: - err_msg3: t.CChar | t.CPtr = pool.alloc(256) + err_msg3: str = pool.alloc(256) if err_msg3 is not None: viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name) HandlesType.fatal_error(node, err_msg3) HandlesType.fatal_error(node, "裸名调用未定义且未导入") else: - err_msg4: t.CChar | t.CPtr = pool.alloc(256) + err_msg4: str = pool.alloc(256) if err_msg4 is not None: viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name) HandlesType.fatal_error(node, err_msg4) @@ -6501,13 +6505,13 @@ class CallGenMixin: # ============================================================ if self._is_sha1_mangled_call(call_name) != 0: if trans is None or trans._declare_only == 0: - cf_dot: t.CChar | t.CPtr = string.strchr(call_name, '.') - cf_last: t.CChar | t.CPtr = string.strrchr(call_name, '.') + cf_dot: str = string.strchr(call_name, '.') + cf_last: str = string.strrchr(call_name, '.') if cf_dot is not None and cf_last is not None: - cf_sha1: t.CChar | t.CPtr = stdlib.malloc(17) + cf_sha1: str = stdlib.malloc(17) cf_bare_len: t.CSizeT = string.strlen(call_name) - \ (t.CSizeT(t.CUInt64T(cf_last) - t.CUInt64T(call_name))) - 1 - cf_bare: t.CChar | t.CPtr = stdlib.malloc(cf_bare_len + 1) + cf_bare: str = stdlib.malloc(cf_bare_len + 1) if cf_sha1 is not None and cf_bare is not None: string.strncpy(cf_sha1, call_name, 16) cf_sha1[16] = '\0' @@ -6544,7 +6548,7 @@ class CallGenMixin: # 保持白名单类型继续,Phase A 多遍循环下遍重译—— # 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。 if self._dep_text_ll_exists(pool, cf_sha1) != 0: - cf_err: t.CChar | t.CPtr = VLogger.fmt_buf() + cf_err: str = VLogger.fmt_buf() if cf_err is not None: viperlib.snprintf( cf_err, 1024, @@ -6558,7 +6562,7 @@ class CallGenMixin: else: if trans is not None: trans._deps_pending = 1 - cf_dbg: t.CChar | t.CPtr = VLogger.fmt_buf() + cf_dbg: str = VLogger.fmt_buf() if cf_dbg is not None: viperlib.snprintf( cf_dbg, 1024, @@ -6597,11 +6601,13 @@ class CallGenMixin: trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: """isinstance(obj, Cls):运行时 vtable 子类集合比较,返回 i1""" if obj_node is None or cls_node is None: - return llvmlite.const_int(pool, 1, 0) + # 参数缺失即调用错误:fail-fast,绝不返回 True 掩盖 + HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, obj_node, None, 0, trans) if obj_val is None or obj_val.Ty is None: - return llvmlite.const_int(pool, 1, 0) + # obj 类型推断失败:fail-fast,绝不返回 True 掩盖 + HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") # 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load obj_ptr: llvmlite.Value | t.CPtr = obj_val match obj_val.Ty: @@ -6624,7 +6630,8 @@ class CallGenMixin: res: llvmlite.Value | t.CPtr = None cls_names: t.CSizeT | t.CPtr = self._extract_isinstance_class_names(pool, cls_node) if cls_names is None: - return llvmlite.const_int(pool, 1, 0) + # 类名提取失败:fail-fast,绝不返回 True 掩盖 + HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") ci: int = 0 while cls_names[ci] != 0: cn: str = (str | t.CPtr)(t.CVoid(cls_names[ci], t.CPtr)) @@ -6666,7 +6673,8 @@ class CallGenMixin: k += 1 ci += 1 if res is None: - return llvmlite.const_int(pool, 1, 0) + # 未产生任何比较结果(obj 非指针且类全部为 CVTable):推断失败,fail-fast + HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") return res def _extract_isinstance_class_names(self, pool: memhub.MemBuddy | t.CPtr, @@ -6788,7 +6796,7 @@ class CallGenMixin: return None i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - buf: t.CChar | t.CPtr = pool.alloc(256) + buf: str = pool.alloc(256) if buf is None: return None viperlib.snprintf(buf, 256, "%s.vtable", class_name) @@ -6801,7 +6809,7 @@ class CallGenMixin: if sha1 is None: return None mangled: str = HandlesFunctions._mangle_name_with_sha1(sha1, vn) - ref_name: t.CChar | t.CPtr = pool.alloc(256) + ref_name: str = pool.alloc(256) if ref_name is None: return None # vtable 名含 sha1 点号前缀,一律 @"..." 引号形式 @@ -7052,9 +7060,13 @@ class CallGenMixin: tail = arg_val arg_count += 1 - # 3. 按实参类型 + 注册的返回类型构造签名(未注册返回类型时默认 i32) + # 3. 按实参类型 + 注册的返回类型构造签名(未注册即 t.Callable 注解缺失,fail-fast) ret_ty: llvmlite.LLVMType | t.CPtr = self.lookup_func_ptr_ret(func_name) if ret_ty is None: + HandlesType.fatal_error( + None, + f"函数指针变量 '{func_name}' 的返回类型未注册(t.Callable 注解缺失)", + "TypeError") ret_ty = i32_ty fp_first: llvmlite.ParamNode | t.CPtr = None fp_prev: llvmlite.ParamNode | t.CPtr = None @@ -7179,7 +7191,7 @@ class CallGenMixin: # "(null)" 兜底。静默输出 "(null)" 会掩盖表达式翻译失败 # (变量未定义/类型退化等),运行期 printf 打出 "(null)" 会 # 误导为数据问题而非编译器 bug。 - fb_pp: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_pp: str = VLogger.fmt_buf() if fb_pp is not None: viperlib.snprintf(fb_pp, 1024, "print 参数翻译失败(表达式返回 None): [arg=%d]", ai) VLogger.error(fb_pp, "PRINT") @@ -7208,7 +7220,7 @@ class CallGenMixin: case _: pass - token: t.CChar | t.CPtr = None + token: str = None chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本 arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) @@ -7314,7 +7326,7 @@ class CallGenMixin: t.CInt / t.CInt32T → i32 t.CInt64T → i64 t.CDouble → double - t.CPtr / t.CChar | t.CPtr → i8* + t.CPtr / str → i8* str / bytes → i8* 无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32) """ @@ -7325,7 +7337,8 @@ class CallGenMixin: pool, type_node, trans._imported_modules, trans._from_imports, trans) if resolved is not None: return resolved - # 回退为 i32 + # 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位) + HandlesType.fatal_error(type_node, "va_arg 类型解析失败", "TypeError") return llvmlite.Int32(pool) def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, @@ -7638,19 +7651,19 @@ class CallGenMixin: return 1 def _build_func_type_str(self, pool: memhub.MemBuddy | t.CPtr, - func: llvmlite.Function | t.CPtr) -> t.CChar | t.CPtr: + func: llvmlite.Function | t.CPtr) -> str: """生成函数类型文本(stdlib 分配)""" if func is None: return None # 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲 - ty_buf: t.CChar | t.CPtr = pool.alloc(1024) + ty_buf: str = pool.alloc(1024) if ty_buf is None: return None ty_buf[0] = '\0' # 返回类型 ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) - ret_part: t.CChar | t.CPtr = pool.alloc(512) + ret_part: str = pool.alloc(512) if ret_part is not None and ret_ty is not None: ret_part[0] = '\0' llvmlite.TypePrint(ret_part, 512, ret_ty, pool) @@ -7660,7 +7673,7 @@ class CallGenMixin: # 参数类型(全部经 _asm_append_cstr 有界追加,防止 strcat 无界写穿 1024 缓冲) cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) first: int = 1 - param_part: t.CChar | t.CPtr = pool.alloc(512) + param_part: str = pool.alloc(512) while cur is not None: if first == 0: self._asm_append_cstr(ty_buf, 1024, ", ") @@ -7676,7 +7689,7 @@ class CallGenMixin: # 深拷贝到 stdlib 区(TypeStr 跨文件永久存活) ts_len: t.CSizeT = string.strlen(ty_buf) - ts_copy: t.CChar | t.CPtr = stdlib.malloc(ts_len + 1) + ts_copy: str = stdlib.malloc(ts_len + 1) if ts_copy is None: return None string.strcpy(ts_copy, ty_buf) @@ -7705,7 +7718,7 @@ class CallGenMixin: # Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件 # reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃) name_len: t.CSizeT = string.strlen(name) - name_copy: t.CChar | t.CPtr = stdlib.malloc(name_len + 1) + name_copy: str = stdlib.malloc(name_len + 1) if name_copy is None: return 1 string.strcpy(name_copy, name) @@ -7787,7 +7800,7 @@ class CallGenMixin: entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) # Name 深拷贝到 stdlib(全局表跨文件永久存活) nm_len: t.CSizeT = string.strlen(name) - nm_copy: t.CChar | t.CPtr = stdlib.malloc(nm_len + 1) + nm_copy: str = stdlib.malloc(nm_len + 1) if nm_copy is None: return 1 string.strcpy(nm_copy, name) @@ -7814,7 +7827,7 @@ class CallGenMixin: ints[di] = dcn.int_val if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None: slen: t.CSizeT = string.strlen(dcn.str_val) - scopy: t.CChar | t.CPtr = stdlib.malloc(slen + 1) + scopy: str = stdlib.malloc(slen + 1) if scopy is not None: string.strcpy(scopy, dcn.str_val) strs[di] = t.CSizeT(scopy) diff --git a/App/lib/core/Gen/ClassGenMixin.vp b/App/lib/core/Gen/ClassGenMixin.vp index fc470c2..9037bce 100644 --- a/App/lib/core/Gen/ClassGenMixin.vp +++ b/App/lib/core/Gen/ClassGenMixin.vp @@ -762,9 +762,15 @@ class ClassGenMixin: if left_bits >= right_bits: return left_ty return right_ty - return llvmlite.Int32(pool) + # fail-fast:BinOp 但非 BitOr(未知联合运算),不再静默回退 i32 + HandlesType.fatal_error( + ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError") + return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) - return llvmlite.Int32(pool) + # fail-fast:未知注解节点 kind,不再静默回退 i32 + HandlesType.fatal_error( + ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError") + return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) def _is_state_annotation(self, node: ast.AST | t.CPtr) -> int: """检查注解节点是否为 t.State,返回 1=是 / 0=否""" @@ -816,7 +822,7 @@ class ClassGenMixin: children: list[ast.AST | t.CPtr] | t.CPtr = cd.children if children is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "%s has no body", class_name) VLogger.warning(fb, "ENUM") @@ -917,7 +923,7 @@ class ClassGenMixin: member_count += 1 if member_count == 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "%s has no members", class_name) VLogger.warning(fb, "ENUM") @@ -941,7 +947,7 @@ class ClassGenMixin: entry: HandlesEnum.EnumEntry | t.CPtr = HandlesEnum.register_enum( pool, class_name, base_ty) if entry is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "failed to register %s", class_name) VLogger.error(fb, "ENUM") @@ -962,7 +968,7 @@ class ClassGenMixin: if mname is not None and mty2 is not None: HandlesEnum.add_enum_member(pool, entry, mname, mval, mty2) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "registered %s with %d members, base_bits=%d", class_name, member_count, max_bits) @@ -1078,7 +1084,7 @@ class ClassGenMixin: children: list[ast.AST | t.CPtr] | t.CPtr = cd.children if children is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "%s has no body", class_name) VLogger.warning(fb, "UNION") @@ -1143,7 +1149,7 @@ class ClassGenMixin: field_count += 1 if field_count == 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "%s has no fields", class_name) VLogger.warning(fb, "UNION") @@ -1167,14 +1173,14 @@ class ClassGenMixin: # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" union_type_name: str = class_name if trans.ModuleSha1 is not None: - union_name_buf: t.CChar | t.CPtr = pool.alloc(64) + union_name_buf: str = pool.alloc(64) if union_name_buf is not None: viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) union_type_name = union_name_buf union_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, pnode, 1, union_type_name) if union_ty is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "failed to create type for %s", class_name) VLogger.error(fb, "UNION") @@ -1193,7 +1199,7 @@ class ClassGenMixin: entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( pool, class_name, union_ty, trans.ModuleSha1) if entry is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "failed to register %s", class_name) VLogger.error(fb, "UNION") @@ -1219,7 +1225,7 @@ class ClassGenMixin: if fname is not None and fty2 is not None: HandlesStruct.add_field(pool, entry, fname, fty2, None, None) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "registered %s with %d fields, max_size=%d", class_name, field_count, max_size) @@ -1307,7 +1313,7 @@ class ClassGenMixin: children: list[ast.AST | t.CPtr] | t.CPtr = cd.children if children is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "%s has no body", class_name) VLogger.warning(fb, "RENUM") @@ -1369,7 +1375,7 @@ class ClassGenMixin: variant_count += 1 if variant_count == 0: - fb2: t.CChar | t.CPtr = VLogger.fmt_buf() + fb2: str = VLogger.fmt_buf() if fb2 is not None: viperlib.snprintf(fb2, 1024, "%s has no variants", class_name) VLogger.warning(fb2, "RENUM") @@ -1425,7 +1431,7 @@ class ClassGenMixin: first_node = tail_node if first_node is None: - fb3: t.CChar | t.CPtr = VLogger.fmt_buf() + fb3: str = VLogger.fmt_buf() if fb3 is not None: viperlib.snprintf(fb3, 1024, "failed to build field list for %s", class_name) VLogger.error(fb3, "RENUM") @@ -1434,7 +1440,7 @@ class ClassGenMixin: # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" renum_type_name: str = class_name if trans.ModuleSha1 is not None: - renum_name_buf: t.CChar | t.CPtr = pool.alloc(64) + renum_name_buf: str = pool.alloc(64) if renum_name_buf is not None: viperlib.snprintf(renum_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) renum_type_name = renum_name_buf @@ -1442,7 +1448,7 @@ class ClassGenMixin: renum_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( pool, first_node, total_positions, renum_type_name) if renum_ty is None: - fb4: t.CChar | t.CPtr = VLogger.fmt_buf() + fb4: str = VLogger.fmt_buf() if fb4 is not None: viperlib.snprintf(fb4, 1024, "failed to create type for %s", class_name) VLogger.error(fb4, "RENUM") @@ -1462,7 +1468,7 @@ class ClassGenMixin: entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( pool, class_name, renum_ty, trans.ModuleSha1) if entry is None: - fb5: t.CChar | t.CPtr = VLogger.fmt_buf() + fb5: str = VLogger.fmt_buf() if fb5 is not None: viperlib.snprintf(fb5, 1024, "failed to register %s", class_name) VLogger.error(fb5, "RENUM") @@ -1485,7 +1491,7 @@ class ClassGenMixin: payload_ty: llvmlite.LLVMType | t.CPtr = i32_ty if psize2 > 4: payload_ty = i64_ty - field_name_buf: t.CChar | t.CPtr = pool.alloc(16) + field_name_buf: str = pool.alloc(16) if field_name_buf is not None: viperlib.snprintf(field_name_buf, 16, "_p%d", pos) HandlesStruct.add_field(pool, entry, field_name_buf, payload_ty, None, None) @@ -1495,7 +1501,7 @@ class ClassGenMixin: # 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题) - fb6: t.CChar | t.CPtr = VLogger.fmt_buf() + fb6: str = VLogger.fmt_buf() if fb6 is not None: viperlib.snprintf(fb6, 1024, "registered %s with %d variants, %d positions", class_name, variant_count, total_positions) @@ -1557,7 +1563,7 @@ class ClassGenMixin: break if tag >= RENUM_VARIANT_PER_CLASS: # 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错 - fb_rv: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_rv: str = VLogger.fmt_buf() if fb_rv is not None: viperlib.snprintf(fb_rv, 1024, "REnum 变体数超过上限 %d: %s", RENUM_VARIANT_PER_CLASS, class_name) @@ -2017,8 +2023,8 @@ class ClassGenMixin: # 深拷贝字符串到 stdlib 区 key_len: t.CSizeT = string.strlen(spec_key) name_len: t.CSizeT = string.strlen(spec_name) - key_copy: t.CChar | t.CPtr = stdlib.malloc(key_len + 1) - name_copy: t.CChar | t.CPtr = stdlib.malloc(name_len + 1) + key_copy: str = stdlib.malloc(key_len + 1) + name_copy: str = stdlib.malloc(name_len + 1) if key_copy is None or name_copy is None: return string.strcpy(key_copy, spec_key) @@ -2068,7 +2074,7 @@ class ClassGenMixin: # 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。 self.GenericSpecDepth += 1 if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH: - err_spec: t.CChar | t.CPtr = trans.Pool.alloc(256) + err_spec: str = trans.Pool.alloc(256) if err_spec is not None: viperlib.snprintf(err_spec, 256, "泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d", @@ -2112,6 +2118,9 @@ class ClassGenMixin: # 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解 # 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr) # 导致无限递归补译 → OOM。补译完成后已设置,无需恢复。 + # 注意:此处提前置位后调用 _translate_oop_methods 必须传 reemit=1 + # (补译模式),否则其 MethodsEmitted==1 防重复检查会拦截补译, + # 方法体永不发射 → 特化方法只有 call 无 define → 链接 undefined symbol。 pre_existing.MethodsEmitted = 1 tp_names_pre: list[str] | t.CPtr = template_cd.type_params spec_cd_pre: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec( @@ -2134,7 +2143,7 @@ class ClassGenMixin: if tpl_file_pre is not None: HandlesType.set_current_file(tpl_file_pre) HandlesType.push_trace(tpl_file_pre, template_cd.lineno) - self._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0) + self._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0, 1) if tpl_file_pre is not None: HandlesType.pop_trace() HandlesType.set_current_file(saved_cur_pre) @@ -2324,10 +2333,10 @@ class ClassGenMixin: ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, existing.Ty) if ty_deep is not None: existing.Ty = ty_deep - old_name: t.CChar | t.CPtr = llvmlite.get_struct_name(existing.Ty) + old_name: str = llvmlite.get_struct_name(existing.Ty) if old_name is not None: on_len: t.CSizeT = string.strlen(old_name) - on_copy: t.CChar | t.CPtr = stdlib.malloc(on_len + 1) + on_copy: str = stdlib.malloc(on_len + 1) if on_copy is not None: string.strcpy(on_copy, old_name) c.DerefAs(existing.Ty, llvmlite.LLVMType.Struct( @@ -2595,7 +2604,7 @@ class ClassGenMixin: i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) vtable_node: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) if vtable_node is None: - fb_vn: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_vn: str = VLogger.fmt_buf() if fb_vn is not None: viperlib.snprintf(fb_vn, 1024, "failed to alloc vtable node for %s", class_name) VLogger.error(fb_vn, "CLASS") @@ -2631,13 +2640,13 @@ class ClassGenMixin: # reset_to(mark1) 存活 → 用 stdlib 深拷贝;Phase 1a 仍用 pool(无需跨文件)。 type_name: str = class_name if trans.ModuleSha1 is not None: - name_buf: t.CChar | t.CPtr = pool.alloc(64) + name_buf: str = pool.alloc(64) if name_buf is not None: viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) type_name = name_buf if trans._declare_only == 0 and type_name is not None: tn_len: t.CSizeT = string.strlen(type_name) - tn_copy: t.CChar | t.CPtr = stdlib.malloc(tn_len + 1) + tn_copy: str = stdlib.malloc(tn_len + 1) if tn_copy is not None: string.strcpy(tn_copy, type_name) type_name = tn_copy @@ -2645,7 +2654,7 @@ class ClassGenMixin: # 创建 StructType(命名结构体) struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, total_field_count, type_name) if struct_ty is None: - fb_st: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_st: str = VLogger.fmt_buf() if fb_st is not None: viperlib.snprintf(fb_st, 1024, "failed to create StructType for %s", class_name) VLogger.error(fb_st, "CLASS") @@ -2680,7 +2689,7 @@ class ClassGenMixin: entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( pool, class_name, struct_ty, trans.ModuleSha1) if entry is None: - fb_re: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_re: str = VLogger.fmt_buf() if fb_re is not None: viperlib.snprintf(fb_re, 1024, "failed to register %s", class_name) VLogger.error(fb_re, "CLASS") @@ -2697,7 +2706,7 @@ class ClassGenMixin: # find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活 if HandlesStruct.get_stdlib_alloc() != 0: pn_len: t.CSizeT = string.strlen(parent_name) - pn_buf: t.CChar | t.CPtr = stdlib.malloc(pn_len + 1) + pn_buf: str = stdlib.malloc(pn_len + 1) if pn_buf is not None: string.strcpy(pn_buf, parent_name) entry.ParentName = pn_buf @@ -2729,9 +2738,9 @@ class ClassGenMixin: fdef = (ast.AST | t.CPtr)(t.CVoid(fdef_addr, t.CPtr)) # 恢复注解类名指针 fannot_addr: t.CSizeT = field_annot_buf[fi] - fannot: t.CChar | t.CPtr = None + fannot: str = None if fannot_addr != 0: - fannot = (t.CChar | t.CPtr)(t.CVoid(fannot_addr, t.CPtr)) + fannot = (str)(t.CVoid(fannot_addr, t.CPtr)) if fname is not None and fty2 is not None: HandlesStruct.add_field(pool, entry, fname, fty2, fdef, fannot) @@ -2750,8 +2759,8 @@ class ClassGenMixin: # ============================================================ # _vtable_strcat — 将 src 追加到 dst 末尾 # ============================================================ - def _vtable_strcat(self, dst: t.CChar | t.CPtr, dst_size: t.CSizeT, - src: t.CChar | t.CPtr): + def _vtable_strcat(self, dst: str, dst_size: t.CSizeT, + src: str): """将 src 追加到 dst 末尾""" if dst is None or src is None: return @@ -2787,7 +2796,7 @@ class ClassGenMixin: # 例如: void ({i32, i32}*, i32) # ============================================================ def _format_func_type_str(self, pool: memhub.MemBuddy | t.CPtr, - buf: t.CChar | t.CPtr, buf_size: t.CSizeT, + buf: str, buf_size: t.CSizeT, func: llvmlite.Function | t.CPtr) -> int: """从 Function 对象生成函数类型字符串""" if buf is None or func is None or buf_size == 0: @@ -2795,7 +2804,7 @@ class ClassGenMixin: buf[0] = '\0' # 打印返回类型(使用访问器函数避免跨模块直接字段访问) ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) - ret_buf: t.CChar | t.CPtr = pool.alloc(128) + ret_buf: str = pool.alloc(128) if ret_buf is not None and ret_ty is not None: ret_buf[0] = '\0' llvmlite.TypePrint(ret_buf, 128, ret_ty, pool) @@ -2805,7 +2814,7 @@ class ClassGenMixin: # 遍历参数(使用访问器函数避免跨模块直接字段访问) cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) first: int = 1 - param_buf: t.CChar | t.CPtr = pool.alloc(128) + param_buf: str = pool.alloc(128) _pc: int = 0 while cur is not None: _pc += 1 @@ -2942,20 +2951,20 @@ class ClassGenMixin: while mro_ptr is not None and mro_ptr[mro_i] != 0: anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mro_i], t.CPtr)) if anc is not None: - probe_buf: t.CChar | t.CPtr = pool.alloc(128) + probe_buf: str = pool.alloc(128) if probe_buf is not None: viperlib.snprintf(probe_buf, 128, "%s.%s", anc, pmethod_name) if HandlesExprCall.find_func_global(probe_buf) is not None: def_class = anc break mro_i += 1 - pfname_buf: t.CChar | t.CPtr = pool.alloc(128) + pfname_buf: str = pool.alloc(128) if pfname_buf is not None: viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name) full_names_buf[method_count] = t.CSizeT(pfname_buf) # 复制方法名(短名) pmname_len: t.CSizeT = string.strlen(pmethod_name) - pmname_buf: t.CChar | t.CPtr = stdlib.malloc(pmname_len + 1) + pmname_buf: str = stdlib.malloc(pmname_len + 1) if pmname_buf is not None: string.strcpy(pmname_buf, pmethod_name) method_names_buf[method_count] = t.CSizeT(pmname_buf) @@ -3009,14 +3018,14 @@ class ClassGenMixin: if already_in_vt == 1: continue # 构造 full_name = "ClassName.method_name" - fname_buf: t.CChar | t.CPtr = pool.alloc(128) + fname_buf: str = pool.alloc(128) if fname_buf is not None: viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname) full_names_buf[method_count] = t.CSizeT(fname_buf) # 复制方法名 mname_len: t.CSizeT = string.strlen(mname) - mname_buf: t.CChar | t.CPtr = stdlib.malloc(mname_len + 1) + mname_buf: str = stdlib.malloc(mname_len + 1) if mname_buf is not None: string.strcpy(mname_buf, mname) method_names_buf[method_count] = t.CSizeT(mname_buf) @@ -3095,7 +3104,7 @@ class ClassGenMixin: # 3. 构造初始化字符串 # 大 vtable(如 MemBuddy 28+ 方法)每个方法 bitcast 约 100+ 字节, # 4096 可能写满导致截断/strlen 越界,用 16384 预留足够空间。 - init_buf: t.CChar | t.CPtr = pool.alloc(16384) + init_buf: str = pool.alloc(16384) if init_buf is None: return 0 init_buf[0] = '\0' @@ -3158,11 +3167,14 @@ class ClassGenMixin: self._vtable_strcat(init_buf, 16384, mangled_name) self._vtable_strcat(init_buf, 16384, " to i8*)") continue - self._vtable_strcat(init_buf, 16384, "i8* null") + # fail-fast:func 无效且全局表 TypeStr 回退也失败, + # 不再写 "i8* null" 静默掩盖缺失实现。 + HandlesType.fatal_error( + cd, f"vtable 方法 '{full_name}' 找不到函数实现", "InternalCompilerError") continue # 构造函数类型字符串 - func_ty_buf: t.CChar | t.CPtr = pool.alloc(512) + func_ty_buf: str = pool.alloc(512) if func_ty_buf is None: self._vtable_strcat(init_buf, 16384, "i8* null") continue @@ -3184,7 +3196,7 @@ class ClassGenMixin: self._vtable_strcat(init_buf, 16384, " }") # 4. 构造 VTable 全局变量名 - vtable_name_buf: t.CChar | t.CPtr = pool.alloc(128) + vtable_name_buf: str = pool.alloc(128) if vtable_name_buf is None: return 0 viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name) @@ -3226,10 +3238,15 @@ class ClassGenMixin: cd: ast.ClassDef | t.CPtr, struct_ty: llvmlite.LLVMType | t.CPtr, class_name: str, - mark_only: int = 0) -> int: + mark_only: int = 0, + reemit: int = 0) -> int: """扫描 class body 中的方法并翻译,生成 __before_init__ mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) + reemit: 1=补译模式(_specialize_generic_class Phase B 补译分支调用)。 + 补译分支为防重入已提前置 MethodsEmitted=1,但方法体尚未发射, + 必须跳过下方 MethodsEmitted==1 的防重复检查强制发射,否则补译 + 被自身拦截 → 特化方法只有 call 无 define → 链接 undefined symbol。 """ if trans is None or cd is None or struct_ty is None or class_name is None: return 0 @@ -3310,7 +3327,9 @@ class ClassGenMixin: # 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量 # 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。 # 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。 - if oop_entry is not None and oop_entry.MethodsEmitted == 1: + # reemit=1(补译模式)时跳过本检查:补译分支为防重入已提前置 + # MethodsEmitted=1,但方法体尚未发射,必须强制发射。 + if oop_entry is not None and oop_entry.MethodsEmitted == 1 and reemit == 0: return 0 # 防重入:方法体翻译前先标记 MethodsEmitted=1。 @@ -3398,7 +3417,7 @@ class ClassGenMixin: # 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter) func_meta: int = self._extract_func_meta(fd.decorator_list) # property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突 - method_name_buf: t.CChar | t.CPtr = pool.alloc(128) + method_name_buf: str = pool.alloc(128) if method_name_buf is None: return 0 viperlib.snprintf(method_name_buf, 128, "%s", fd.name) @@ -3421,7 +3440,7 @@ class ClassGenMixin: is_class_m = 1 # 构建方法全名: ClassName.method_name - full_name_buf: t.CChar | t.CPtr = pool.alloc(128) + full_name_buf: str = pool.alloc(128) if full_name_buf is None: return 0 viperlib.snprintf(full_name_buf, 128, "%s.%s", class_name, method_name) @@ -3494,7 +3513,7 @@ class ClassGenMixin: fd_first_arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fd_ags.args.get(0)) if fd_first_arg is not None and fd_first_arg.arg is not None: first_pname = fd_first_arg.arg - first_pname_buf: t.CChar | t.CPtr = pool.alloc(32) + first_pname_buf: str = pool.alloc(32) if first_pname_buf is not None: viperlib.snprintf(first_pname_buf, 32, "%%%s", first_pname) llvmlite.add_param(pool, func, self_ptr_ty, first_pname_buf) @@ -3528,7 +3547,7 @@ class ClassGenMixin: param_ty = llvmlite.Ptr(pool, aelem_ty) case _: param_ty = resolved - pname: t.CChar | t.CPtr = pool.alloc(32) + pname: str = pool.alloc(32) if pname is not None: viperlib.snprintf(pname, 32, "%%%s", arg.arg) llvmlite.add_param(pool, func, param_ty, pname) @@ -3564,7 +3583,7 @@ class ClassGenMixin: cfirst: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(cags.args.get(0)) if cfirst is not None and cfirst.arg is not None: self_var_name = cfirst.arg - self_ssa_name_buf: t.CChar | t.CPtr = pool.alloc(32) + self_ssa_name_buf: str = pool.alloc(32) if self_ssa_name_buf is not None: viperlib.snprintf(self_ssa_name_buf, 32, "%%%s", cfirst.arg) self_ssa_name = self_ssa_name_buf @@ -3591,6 +3610,12 @@ class ClassGenMixin: if arg2.annotation is not None: resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, arg2.annotation, imported_modules, from_imports, trans) + if resolved2 is None: + # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 + HandlesType.fatal_error( + arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败", + "NameError") + resolved2 = i32_ty # 不可达(fatal_error 已退出) if resolved2 is not None: # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针) # CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致) @@ -3611,7 +3636,7 @@ class ClassGenMixin: if cls_nm_oc is not None: HandlesVar.set_var_annot_class_name( trans.SymTab, arg2.arg, cls_nm_oc) - pname2: t.CChar | t.CPtr = pool.alloc(32) + pname2: str = pool.alloc(32) if pname2 is not None: viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( @@ -3725,7 +3750,7 @@ class ClassGenMixin: void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) # 构建函数名: ClassName.__before_init__ - full_name_buf: t.CChar | t.CPtr = pool.alloc(128) + full_name_buf: str = pool.alloc(128) if full_name_buf is None: return 0 viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name) @@ -3804,7 +3829,7 @@ class ClassGenMixin: vt_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_ty) # 构造 vtable 全局变量名 - vt_name_buf: t.CChar | t.CPtr = pool.alloc(128) + vt_name_buf: str = pool.alloc(128) if vt_name_buf is not None: viperlib.snprintf(vt_name_buf, 128, "%s.vtable", class_name) vt_full_name: str = vt_name_buf @@ -3820,7 +3845,7 @@ class ClassGenMixin: llvmlite.value_set_ty(vt_ref, vt_ptr_ty) llvmlite.value_set_isconst(vt_ref, 1) # Name 格式: @"mangled" 或 @mangled - vt_ref_name: t.CChar | t.CPtr = pool.alloc(256) + vt_ref_name: str = pool.alloc(256) if vt_ref_name is not None: vt_ref_name[0] = '\0' if self._vtable_name_needs_quote(vt_mangled) != 0: diff --git a/App/lib/core/Gen/ExprGenMixin.vp b/App/lib/core/Gen/ExprGenMixin.vp index f932342..d48be59 100644 --- a/App/lib/core/Gen/ExprGenMixin.vp +++ b/App/lib/core/Gen/ExprGenMixin.vp @@ -105,13 +105,13 @@ class ExprGenMixin: # 转义 LLVM IR 字符串字面量 # ============================================================ def escape_llvm_string(self, pool: memhub.MemBuddy | t.CPtr, - src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + src: str) -> str: """将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """ if src is None: return None slen: t.CSizeT = string.strlen(src) alloc_size: t.CSizeT = 4 * slen + 8 - buf: t.CChar | t.CPtr = pool.alloc(alloc_size) + buf: str = pool.alloc(alloc_size) if buf is None: return None pos: t.CSizeT = 0 @@ -386,7 +386,7 @@ class ExprGenMixin: cls_ugi: str = self._sub_base_class_name(pool, trans, sub_node) if cls_ugi is None: return 0 - lookup_ugi: t.CChar | t.CPtr = pool.alloc(128) + lookup_ugi: str = pool.alloc(128) if lookup_ugi is None: return 0 viperlib.snprintf(lookup_ugi, 128, "%s.__getitem__", cls_ugi) @@ -566,7 +566,7 @@ class ExprGenMixin: str_val: str, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """创建全局字符串常量并返回 i8* bitcast""" - escaped: t.CChar | t.CPtr = self.escape_llvm_string(pool, str_val) + escaped: str = self.escape_llvm_string(pool, str_val) if escaped is None: return None @@ -581,7 +581,7 @@ class ExprGenMixin: trans._label_counter += 1 # 字符串名加 SHA1 前缀,和函数导出规则一致,避免跨模块重名 - gv_name: t.CChar | t.CPtr = pool.alloc(48) + gv_name: str = pool.alloc(48) if gv_name is None: return None if trans.ModuleSha1 is not None: @@ -602,7 +602,7 @@ class ExprGenMixin: gv.Initializer = escaped arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty) - gv_ref_name: t.CChar | t.CPtr = pool.alloc(64) + gv_ref_name: str = pool.alloc(64) if gv_ref_name is None: return None viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name) @@ -669,9 +669,13 @@ class ExprGenMixin: # ============================================================ def _infer_elem_type_from_value(self, pool: memhub.MemBuddy | t.CPtr, value: llvmlite.Value | t.CPtr) -> str: - """从 LLVM Value 的类型推断 list 元素类型名""" + """从 LLVM Value 的类型推断 list 元素类型名 + + fail-fast:值类型缺失/无法映射时返回 None(调用方携带节点报错终止), + 绝不静默回退 "str"(掩盖上游 Value 类型缺失根因)。 + """ if value is None or value.Ty is None: - return "str" + return None ty: llvmlite.LLVMType | t.CPtr = value.Ty bits: int = self.get_llvm_type_bits(ty) if bits != 0: @@ -683,7 +687,7 @@ class ExprGenMixin: return "CInt8T" if bits == 16: return "CInt16T" - return "int" + return None if self.is_ptr_type(ty) != 0: return "str" fbits: int = self.get_llvm_float_bits(ty) @@ -692,7 +696,7 @@ class ExprGenMixin: return "CDouble" if fbits == 32: return "CFloat" - return "str" + return None # ============================================================ # _find_pool_var — 查找上下文中的 pool 变量 @@ -741,7 +745,7 @@ class ExprGenMixin: llvmlite.module_add_global(trans.Module, gv_ext) # 创建 Value 引用(@_mbuddy, 类型为 i8**) i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb) - ref_name_fb: t.CChar | t.CPtr = pool.alloc(16) + ref_name_fb: str = pool.alloc(16) if ref_name_fb is not None: string.strcpy(ref_name_fb, "@_mbuddy") gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb) @@ -788,12 +792,21 @@ class ExprGenMixin: inferred_type_name: str = elem_type_name first_elem_val: llvmlite.Value | t.CPtr = None if inferred_type_name is None: - inferred_type_name = "str" if elts_count > 0: first_elem_node: ast.AST | t.CPtr = elts.get(0) first_elem_val = self.translate_value(builder, pool, mod, first_elem_node, None, 0, trans) - if first_elem_val is not None: - inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val) + if first_elem_val is None or first_elem_val.Ty is None: + # fail-fast:首元素翻译失败/Value 类型缺失,立即终止编译(暴露上游根因) + HandlesType.fatal_error( + first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError") + inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val) + if inferred_type_name is None: + # fail-fast:首元素 Value 类型无法映射为 list 元素类型,立即终止编译 + HandlesType.fatal_error( + first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError") + else: + # 空 list 无元素可推断,保持默认 str(list[str]) + inferred_type_name = "str" # 查找 pool 变量 pool_alloca: llvmlite.Value | t.CPtr = self._find_pool_var(trans) @@ -964,7 +977,7 @@ class ExprGenMixin: return None # 编译期格式串缓冲(pool 分配) - fmt_buf: t.CChar | t.CPtr = pool.alloc(FSTR_BUF_SIZE) + fmt_buf: str = pool.alloc(FSTR_BUF_SIZE) if fmt_buf is None: return None fmt_buf[0] = '\0' @@ -1005,7 +1018,8 @@ class ExprGenMixin: if c_fmt is None: c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans) if c_fmt is None: - c_fmt = "%d" + # fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译 + HandlesType.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError") # 追加格式说明符 if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: string.strcat(fmt_buf, c_fmt) @@ -1035,7 +1049,7 @@ class ExprGenMixin: fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(node) if fv is None or fv.value is None: return None - fmt_buf: t.CChar | t.CPtr = pool.alloc(FSTR_BUF_SIZE) + fmt_buf: str = pool.alloc(FSTR_BUF_SIZE) if fmt_buf is None: return None fmt_buf[0] = '\0' @@ -1056,7 +1070,8 @@ class ExprGenMixin: if c_fmt is None: c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans) if c_fmt is None: - c_fmt = "%d" + # fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译 + HandlesType.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError") if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: string.strcat(fmt_buf, c_fmt) cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value( @@ -1072,7 +1087,7 @@ class ExprGenMixin: def _fstr_finalize(self, builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, - fmt_buf: t.CChar | t.CPtr, + fmt_buf: str, arg_head: llvmlite.Value | t.CPtr, arg_tail: llvmlite.Value | t.CPtr, arg_count: int, @@ -1108,7 +1123,7 @@ class ExprGenMixin: llvmlite.build_call(builder, "snprintf", buf_ptr, 3 + arg_count, i32_ty, 1) return buf_ptr - def _fstr_append_literal(self, fmt_buf: t.CChar | t.CPtr, + def _fstr_append_literal(self, fmt_buf: str, lit: str) -> None: """追加字面量到格式串(% 转义为 %%)""" if fmt_buf is None or lit is None: @@ -1135,7 +1150,7 @@ class ExprGenMixin: si += 1 fmt_buf[cur_len] = '\0' - def _fstr_append_raw(self, fmt_buf: t.CChar | t.CPtr, s: str) -> None: + def _fstr_append_raw(self, fmt_buf: str, s: str) -> None: """追加原始字符串(不做 % 转义)""" if fmt_buf is None or s is None: return @@ -1152,7 +1167,7 @@ class ExprGenMixin: if spec_node is None or pool is None or val is None: return None # 1. 提取 spec 字符串(JoinedStr 仅常量拼接) - spec: t.CChar | t.CPtr = pool.alloc(FSTR_SPEC_MAX) + spec: str = pool.alloc(FSTR_SPEC_MAX) if spec is None: return None spec[0] = '\0' @@ -1197,9 +1212,9 @@ class ExprGenMixin: if ch1 == '<' or ch1 == '>' or ch1 == '^' or ch1 == '=': align_char = ch1 pos += 2 - c_flags: t.CChar | t.CPtr = pool.alloc(FSTR_FMT_MAX) - c_width: t.CChar | t.CPtr = pool.alloc(32) - c_prec: t.CChar | t.CPtr = pool.alloc(32) + c_flags: str = pool.alloc(FSTR_FMT_MAX) + c_width: str = pool.alloc(32) + c_prec: str = pool.alloc(32) if c_flags is None or c_width is None or c_prec is None: return None c_flags[0] = '\0' @@ -1254,7 +1269,7 @@ class ExprGenMixin: return None # 多余字符无法解析 # 3. 长度修饰(按值类型位宽) - len_mod: t.CChar | t.CPtr = pool.alloc(4) + len_mod: str = pool.alloc(4) if len_mod is None: return None len_mod[0] = '\0' @@ -1269,7 +1284,7 @@ class ExprGenMixin: string.strcpy(len_mod, "hh") # 4. 组装 C 格式串 - out: t.CChar | t.CPtr = pool.alloc(FSTR_FMT_MAX) + out: str = pool.alloc(FSTR_FMT_MAX) if out is None: return None out[0] = '\0' @@ -1299,7 +1314,7 @@ class ExprGenMixin: elif fmt_type == 'f' or fmt_type == 'F': string.strcat(out, "f") elif fmt_type == 'e' or fmt_type == 'E' or fmt_type == 'g' or fmt_type == 'G': - tmp_ch: t.CChar | t.CPtr = pool.alloc(2) + tmp_ch: str = pool.alloc(2) if tmp_ch is None: return None tmp_ch[0] = fmt_type @@ -1316,7 +1331,7 @@ class ExprGenMixin: string.strcat(out, "d") elif fmt_type == 'x' or fmt_type == 'X' or fmt_type == 'o' or fmt_type == 'u': string.strcat(out, len_mod) - tmp_ch2: t.CChar | t.CPtr = pool.alloc(2) + tmp_ch2: str = pool.alloc(2) if tmp_ch2 is None: return None tmp_ch2[0] = fmt_type @@ -1333,7 +1348,7 @@ class ExprGenMixin: """无 format_spec 时按值类型推断 C printf 格式(对齐 TPC 无 spec 分支,带 % 前缀)""" if val is None or pool is None: return None - out: t.CChar | t.CPtr = pool.alloc(16) + out: str = pool.alloc(16) if out is None: return None out[0] = '\0' @@ -1359,7 +1374,9 @@ class ExprGenMixin: return "%f" if HandlesExpr.is_ptr_type(val.Ty) != 0: return "%s" - return "%d" + # fail-fast:值类型缺失(非整数/浮点/指针),无法推断 C 格式,立即终止编译 + HandlesType.fatal_error(arg_node, "f-string 格式无法推断(值类型缺失)", "TypeError") + return None def _fstr_cast_value(self, builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, @@ -1454,7 +1471,7 @@ class ExprGenMixin: # 2. 创建三个基本块 cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) if name_buf is None: return None viperlib.snprintf(name_buf, 32, "ifexp.then.%d", cnt) @@ -1476,7 +1493,8 @@ class ExprGenMixin: builder, pool, mod, ie.body, None, 0, trans) then_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock if body_val is None: - body_val = llvmlite.const_int32(pool, 0) + # fail-fast:三元表达式 then 分支翻译失败,立即终止编译(暴露上游根因) + HandlesType.fatal_error(ie.body, "三元表达式分支翻译失败", "TypeError") # 暂不 br,等类型对齐后再 br # 5. else 分支 @@ -1485,7 +1503,8 @@ class ExprGenMixin: builder, pool, mod, ie.orelse, None, 0, trans) else_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock if orelse_val is None: - orelse_val = llvmlite.const_int32(pool, 0) + # fail-fast:三元表达式 else 分支翻译失败,立即终止编译(暴露上游根因) + HandlesType.fatal_error(ie.orelse, "三元表达式分支翻译失败", "TypeError") # 暂不 br,等类型对齐后再 br # 类型对齐 (两分支类型可能不同) @@ -1528,7 +1547,8 @@ class ExprGenMixin: phi_ty: llvmlite.LLVMType | t.CPtr = body_val.Ty if phi_ty is None: - phi_ty = llvmlite.Int32(pool) + # fail-fast:三元表达式分支类型缺失,立即终止编译(暴露上游根因) + HandlesType.fatal_error(node, "三元表达式分支类型缺失", "TypeError") inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( pool, body_val, then_blk_for_phi) @@ -1824,17 +1844,12 @@ class ExprGenMixin: lhs = llvmlite.ConstNull(pool, rhs.Ty, "null") else: # 类型不匹配:数值vs指针 或 不同级指针 - # 用 fmt_buf 构造可读消息(Viper % 格式化在部分路径生成 null) - fmt_msg: t.CChar | t.CPtr = VLogger.fmt_buf() - if fmt_msg is not None: - viperlib.snprintf( - fmt_msg, 1024, - "比较类型不匹配(行 %d): lhs 层级=%d (ty=%p), rhs 层级=%d (ty=%p)", - cmp.lineno, lhs_ptr_level, lhs.Ty, rhs_ptr_level, rhs.Ty) - VLogger.error(fmt_msg, "Compare") - else: - VLogger.error("比较类型不匹配: 数值与指针/不同级指针比较", "Compare") - return None + # fail-fast:比较类型不匹配立即终止编译(暴露上游根因), + # 不再 VLogger.error + 返回 None 静默跳过 + HandlesType.fatal_error( + cmp, + f"比较类型不匹配: 数值与指针/不同级指针比较 (lhs 层级={lhs_ptr_level}, rhs 层级={rhs_ptr_level})", + "TypeError") else: # None 比较: None 被翻译为 i8* null(一级指针) # 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型 @@ -1890,8 +1905,8 @@ class ExprGenMixin: rhs_is_ptr_now: int = self.is_ptr_type(rhs.Ty) if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0: # 两边都是指针,用 TypePrint 比较类型字符串 - lhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128) - rhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128) + lhs_ty_buf: str = pool.alloc(128) + rhs_ty_buf: str = pool.alloc(128) if lhs_ty_buf is not None and rhs_ty_buf is not None: llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool) llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool) @@ -2044,7 +2059,7 @@ class ExprGenMixin: # move_to_end 保证 BB 文本顺序与控制流顺序一致,标签名用 counter 安全) cnt: int = builder.Counter builder.Counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) if name_buf is None: return None viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt) @@ -2841,7 +2856,9 @@ class ExprGenMixin: if mod_alloca.Ty is not None: load_ty = mod_alloca.Ty.Pointee if load_ty is None: - load_ty = llvmlite.Int32(pool) + # fail-fast:global 变量存储类型缺失,立即终止编译(暴露上游根因) + HandlesType.fatal_error( + node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") return llvmlite.build_load(builder, load_ty, mod_alloca) # nonlocal 变量:通过闭包 env 访问 @@ -2865,7 +2882,9 @@ class ExprGenMixin: if alloca.Ty is not None: load_ty = alloca.Ty.Pointee if load_ty is None: - load_ty = llvmlite.Int32(pool) + # fail-fast:局部变量存储类型缺失,立即终止编译(暴露上游根因) + HandlesType.fatal_error( + node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") # 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`): # 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。 # 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致 @@ -2901,13 +2920,15 @@ class ExprGenMixin: fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module( trans.Module, nm_id) if fn_ref is not None: - fn_name: t.CChar | t.CPtr = llvmlite.function_get_name(fn_ref) + fn_name: str = llvmlite.function_get_name(fn_ref) if fn_name is None: return None # 构造函数类型:ret_ty + 参数 ParamNode 链表 fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref) if fn_ret_ty is None: - fn_ret_ty = llvmlite.Int32(pool) + # fail-fast:函数返回类型缺失,无法构造函数指针(暴露上游根因) + HandlesType.fatal_error( + node, f"函数 '{nm_id}' 返回类型缺失,无法构造函数指针", "TypeError") fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref) fn_first_node: llvmlite.ParamNode | t.CPtr = None fn_prev_node: llvmlite.ParamNode | t.CPtr = None @@ -2933,7 +2954,7 @@ class ExprGenMixin: return None llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty)) llvmlite.value_set_isconst(fn_ref_v, 1) - fn_ref_name: t.CChar | t.CPtr = pool.alloc(256) + fn_ref_name: str = pool.alloc(256) if fn_ref_name is not None: fn_ref_name[0] = '\0' if HandlesClassDef._vtable_name_needs_quote(fn_name) != 0: @@ -2976,27 +2997,24 @@ class ExprGenMixin: while fi_orig[og_len_fi] != ' ' and fi_orig[og_len_fi] != '\0': og_len_fi += 1 if og_len_fi > 0: - og_buf_fi: t.CChar | t.CPtr = pool.alloc(og_len_fi + 1) + og_buf_fi: str = pool.alloc(og_len_fi + 1) if og_buf_fi is not None: string.strncpy(og_buf_fi, fi_orig, og_len_fi) og_buf_fi[og_len_fi] = '\0' fi_gname = og_buf_fi - # stub 已注入全局(精确类型)→ 直接引用;未注入 → external 声明 + # stub 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast + # (不再创建 external i8* 声明,否则 llc 报 "use of undefined value", + # 静默回退掩盖 stub 未注入的上游根因) gv_fi: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module( trans.Module, fi_gname) ref_fi: llvmlite.Value | t.CPtr = None if gv_fi is not None and gv_fi.Ty is not None: ref_fi = self.make_global_ref(pool, fi_gname, gv_fi.Ty) else: - i8_ptr_hint_fi: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - ext_gv_fi: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( - pool, fi_gname, i8_ptr_hint_fi) - if ext_gv_fi is not None: - ext_gv_fi.Linkage = "external" - ext_gv_fi.Initializer = None - llvmlite.module_add_global(trans.Module, ext_gv_fi) - ref_fi = self.make_global_ref(pool, fi_gname, i8_ptr_hint_fi) + HandlesType.fatal_error( + node, + f"跨模块全局变量 '{fi_gname}' 类型未知(stub 未注入)", + "TypeError") if ref_fi is not None and ref_fi.Ty is not None: lty_fi: llvmlite.LLVMType | t.CPtr = ref_fi.Ty.Pointee if lty_fi is not None: @@ -3004,19 +3022,21 @@ class ExprGenMixin: return ref_fi # 所有查找路径均失败 - # fail-fast: 仅对符合 CDefine 命名约定(ALL_CAPS)的名字报错 - # 避免对 match/self/pool 等关键字和变量名误报 - # 跨模块 CDefine 查找已在上方完成,此处不重复 - if self._is_cdefine_name_pattern(nm_id) != 0: - err_buf2: str = pool.alloc(256) - if err_buf2 is not None: - cur_sha1: str = "(unknown)" - if trans is not None and trans.ModuleSha1 is not None: - cur_sha1 = trans.ModuleSha1 - viperlib.snprintf(err_buf2, 256, - "[CD] FATAL: Name '%s' NOT found (CDefine local+cross + global + nonlocal + alloca + module alias) in module sha1=%s\n", - nm_id, cur_sha1) - VLogger.error(err_buf2, "CD") + # fail-fast:未定义名称立即终止编译(NameError,暴露上游根因), + # 不再静默返回 None(否则下游 store/call 到 None 崩溃,掩盖名称查找失败)。 + # 豁免:关键字/内建名(self/pool/true/false/None/match 上下文关键字、_、 + # CIf 系等特殊名字)——这些名字不注册 SymTab 属正常,调用方有合法语义 + # 处理路径(如 CIf 未定义名特判走 else),保持返回 None 不报错。 + if nm_id is None: + return None + if string.strcmp(nm_id, "self") == 0 or string.strcmp(nm_id, "pool") == 0 \ + or string.strcmp(nm_id, "true") == 0 or string.strcmp(nm_id, "false") == 0 \ + or string.strcmp(nm_id, "None") == 0 or string.strcmp(nm_id, "match") == 0 \ + or string.strcmp(nm_id, "_") == 0 \ + or string.strcmp(nm_id, "CIf") == 0 or string.strcmp(nm_id, "CIfdef") == 0 \ + or string.strcmp(nm_id, "CIfndef") == 0: + return None + HandlesType.fatal_error(node, f"未定义名称 '{nm_id}'", "NameError") return None # ============================================================ @@ -3094,9 +3114,21 @@ class ExprGenMixin: return llvmlite.Float(pool) if string.strstr(struct_name, "list[CChar]") is not None: return llvmlite.Int8(pool) - # str/bytes/CPtr/其他指针类型 → i8* + # str/bytes/CPtr 等已知指针元素类型 → i8*(元素存储为 8 字节地址) i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - return llvmlite.Ptr(pool, i8_ty_d) + if string.strstr(struct_name, "list[str]") is not None: + return llvmlite.Ptr(pool, i8_ty_d) + if string.strstr(struct_name, "list[bytes]") is not None: + return llvmlite.Ptr(pool, i8_ty_d) + if string.strstr(struct_name, "list[CPtr]") is not None: + return llvmlite.Ptr(pool, i8_ty_d) + # fail-fast:未知 list[T] 元素类型无法映射 LLVM 类型,立即终止编译 + # (不再静默回退 Ptr(i8),暴露上游元素类型缺失根因) + HandlesType.fatal_error( + None, + f"list 元素类型未知:'{struct_name}' 无法映射 LLVM 类型", + "TypeError") + return None # ============================================================ # list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 @@ -3347,7 +3379,7 @@ class ExprGenMixin: # (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__)) cls_nm_rd_ptr: str = self._get_custom_struct_cls_nm(pool, inner_ty) if not (cls_nm_rd_ptr is None): - gi_lookup_rd: t.CChar | t.CPtr = pool.alloc(128) + gi_lookup_rd: str = pool.alloc(128) if gi_lookup_rd is not None: viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr) if HandlesExprCall.find_func_in_module(mod, gi_lookup_rd) is not None: @@ -3425,7 +3457,7 @@ class ExprGenMixin: # 否则普通结构体指针按下标做 GEP 数组访问 cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee) if not (cls_nm_sub is None): - gi_lookup_sub: t.CChar | t.CPtr = pool.alloc(128) + gi_lookup_sub: str = pool.alloc(128) if gi_lookup_sub is not None: viperlib.snprintf(gi_lookup_sub, 128, "%s.__getitem__", cls_nm_sub) if HandlesExprCall.find_func_in_module(mod, gi_lookup_sub) is not None: @@ -3476,7 +3508,7 @@ class ExprGenMixin: # 否则普通结构体指针按下标做 GEP 数组访问 cls_nm_rd_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) if not (cls_nm_rd_gen is None): - gi_lookup_gen: t.CChar | t.CPtr = pool.alloc(128) + gi_lookup_gen: str = pool.alloc(128) if gi_lookup_gen is not None: viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen) if HandlesExprCall.find_func_in_module(mod, gi_lookup_gen) is not None: @@ -3552,7 +3584,7 @@ class ExprGenMixin: if name is None or ty is None: return None ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty) - ref_name: t.CChar | t.CPtr = pool.alloc(64) + ref_name: str = pool.alloc(64) if ref_name is None: return None viperlib.snprintf(ref_name, 64, "@%s", name) @@ -4088,7 +4120,7 @@ class ExprGenMixin: enum_nm.id) if base_ty is not None: # 生成数字字符串作为常量名(LLVM IR 要求常量输出数字值) - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) if name_buf is not None: viperlib.snprintf(name_buf, 32, "%lld", member.Value) return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf) @@ -4113,7 +4145,7 @@ class ExprGenMixin: base_ty_e: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( inner_at_e.attr) if base_ty_e is not None: - name_buf_e: t.CChar | t.CPtr = pool.alloc(32) + name_buf_e: str = pool.alloc(32) if name_buf_e is not None: viperlib.snprintf(name_buf_e, 32, "%lld", member_e.Value) return llvmlite.ConstInt(pool, base_ty_e, member_e.Value, name_buf_e) @@ -4177,7 +4209,7 @@ class ExprGenMixin: is_submod: int = 0 if trans._imported_modules is not None: submod_len: t.CSizeT = string.strlen(nm_ma.id) + string.strlen(at.attr) + 2 - submod_buf: t.CChar | t.CPtr = pool.alloc(submod_len) + submod_buf: str = pool.alloc(submod_len) if submod_buf is not None: viperlib.snprintf(submod_buf, submod_len, "%s.%s", nm_ma.id, at.attr) if HandlesImports.is_module_imported(trans._imported_modules, submod_buf) == 1: @@ -4214,19 +4246,13 @@ class ExprGenMixin: # 此处返回 None,让上层嵌套属性访问路径处理 if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0: return None - # CDefine 未找到且属性名符合 ALL_CAPS 约定: 报 FATAL 错误 + # CDefine 未找到且属性名符合 ALL_CAPS 约定: fail-fast 终止编译 # 不再创建未定义的外部全局变量引用(否则 llc 报 "use of undefined value") if self._is_cdefine_name_pattern(at.attr) != 0: - err_buf_sma: str = pool.alloc(256) - if err_buf_sma is not None: - cur_sha1_sma: str = "(unknown)" - if trans is not None and trans.ModuleSha1 is not None: - cur_sha1_sma = trans.ModuleSha1 - viperlib.snprintf(err_buf_sma, 256, - "[CD] FATAL: Module attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n", - nm_ma.id, at.attr, cur_sha1_sma) - VLogger.error(err_buf_sma, "CD") - return None + HandlesType.fatal_error( + at, + f"跨模块 CDefine 未找到: '{nm_ma.id}.{at.attr}'(CDefine cross-module lookup failed)", + "TypeError") # 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针) i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) mod_gv_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global( @@ -4246,7 +4272,7 @@ class ExprGenMixin: if HandlesVar.lookup_var(trans.SymTab, inner_nm.id) is None: # 构建限定模块名: "w32.win32file" qual_len: t.CSizeT = string.strlen(inner_nm.id) + string.strlen(inner_at.attr) + 2 - qual_buf: t.CChar | t.CPtr = pool.alloc(qual_len) + qual_buf: str = pool.alloc(qual_len) if qual_buf is not None: viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr) if HandlesImports.is_module_imported(trans._imported_modules, qual_buf) == 1: @@ -4276,20 +4302,15 @@ class ExprGenMixin: if HandlesType.is_cdefine_double() != 0: return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nst) return llvmlite.const_int32(pool, cdef_val_nested) - # CDefine 未找到: 报 FATAL 错误(不再创建未定义的全局变量引用) + # CDefine 未找到: fail-fast 终止编译(不再创建未定义的全局变量引用) # 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义, # 导致 llc 报 "use of undefined value" 错误。 # 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。 if self._is_cdefine_name_pattern(at.attr) != 0: - err_buf_ma: str = pool.alloc(256) - if err_buf_ma is not None: - cur_sha1_ma: str = "(unknown)" - if trans is not None and trans.ModuleSha1 is not None: - cur_sha1_ma = trans.ModuleSha1 - viperlib.snprintf(err_buf_ma, 256, - "[CD] FATAL: Nested attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n", - qual_buf, at.attr, cur_sha1_ma) - VLogger.error(err_buf_ma, "CD") + HandlesType.fatal_error( + at, + f"嵌套属性跨模块 CDefine 未找到: '{qual_buf}.{at.attr}'(CDefine cross-module lookup failed)", + "TypeError") return None # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体); @@ -4463,7 +4484,7 @@ class ExprGenMixin: annot_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, annot_struct.Ty) return llvmlite.build_bitcast(builder, loaded_val, annot_ptr_ty) return loaded_val - # fast-fail: 字段未找到,打印诊断信息 + # fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None) if trans is not None: diag_annot: str = None diag_var_nm: str = None @@ -4475,16 +4496,19 @@ class ExprGenMixin: trans.SymTab, dnm.id) if dve is not None: diag_annot = dve.AnnotClassName - fb_attr: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_attr is not None: - viperlib.snprintf(fb_attr, 1024, - "属性访问失败: .%s (var=%s annot=%s sha1=%s:%d)", - at.attr, - diag_var_nm if diag_var_nm is not None else "?", - diag_annot if diag_annot is not None else "None", - trans.ModuleSha1 if trans.ModuleSha1 is not None else "?", - at.lineno if at.lineno is not None else 0) - VLogger.error(fb_attr, "ATTR") + diag_var_txt: str = "?" + if diag_var_nm is not None: + diag_var_txt = diag_var_nm + diag_annot_txt: str = "None" + if diag_annot is not None: + diag_annot_txt = diag_annot + sha1_attr: str = "?" + if trans.ModuleSha1 is not None: + sha1_attr = trans.ModuleSha1 + HandlesType.fatal_error( + at, + f"属性访问失败: .{at.attr} (var={diag_var_txt} annot={diag_annot_txt} sha1={sha1_attr})", + "TypeError") return None case _: # fast-fail: 对非指针类型做属性访问(如 i32.x), @@ -4562,7 +4586,7 @@ class ExprGenMixin: # 做 GEP 数组访问(走下方指针遍历路径) cls_nm_ptr_chk: str = self._get_custom_struct_cls_nm(pool, inner_ty) if not (cls_nm_ptr_chk is None): - si_lookup_gsp: t.CChar | t.CPtr = pool.alloc(128) + si_lookup_gsp: str = pool.alloc(128) if si_lookup_gsp is not None: viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk) if HandlesExprCall.find_func_in_module(mod, si_lookup_gsp) is not None: @@ -4654,7 +4678,7 @@ class ExprGenMixin: # 否则普通结构体指针按下标做 GEP 数组访问 cls_nm_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) if not (cls_nm_gen is None): - si_lookup_gen: t.CChar | t.CPtr = pool.alloc(128) + si_lookup_gen: str = pool.alloc(128) if si_lookup_gen is not None: viperlib.snprintf(si_lookup_gen, 128, "%s.__setitem__", cls_nm_gen) if find_func_in_module(mod, si_lookup_gen) is not None: @@ -4866,7 +4890,7 @@ class ExprGenMixin: # 普通结构体:GEP 获取字段指针 return llvmlite.build_gep_struct( builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index) - # fast-fail: 字段未找到,打印诊断信息 + # fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None) if trans is not None: diag_annot_g: str = None diag_var_nm_g: str = None @@ -4878,16 +4902,19 @@ class ExprGenMixin: trans.SymTab, dnm_g.id) if dve_g is not None: diag_annot_g = dve_g.AnnotClassName - fb_attr_g: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_attr_g is not None: - viperlib.snprintf(fb_attr_g, 1024, - "属性写入失败: .%s (var=%s annot=%s sha1=%s:%d)", - at.attr, - diag_var_nm_g if diag_var_nm_g is not None else "?", - diag_annot_g if diag_annot_g is not None else "None", - trans.ModuleSha1 if trans.ModuleSha1 is not None else "?", - at.lineno if at.lineno is not None else 0) - VLogger.error(fb_attr_g, "ATTR") + diag_var_txt_g: str = "?" + if diag_var_nm_g is not None: + diag_var_txt_g = diag_var_nm_g + diag_annot_txt_g: str = "None" + if diag_annot_g is not None: + diag_annot_txt_g = diag_annot_g + sha1_attr_g: str = "?" + if trans.ModuleSha1 is not None: + sha1_attr_g = trans.ModuleSha1 + HandlesType.fatal_error( + at, + f"属性写入失败: .{at.attr} (var={diag_var_txt_g} annot={diag_annot_txt_g} sha1={sha1_attr_g})", + "TypeError") return None case _: # fast-fail: 对非指针类型做属性写入(如 i32.x = ...), @@ -4997,7 +5024,7 @@ class ExprGenMixin: return None # 在继承链中查找 dunder 方法 - lookup_name: t.CChar | t.CPtr = pool.alloc(128) + lookup_name: str = pool.alloc(128) if lookup_name is None: return None viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) @@ -5011,7 +5038,7 @@ class ExprGenMixin: while mro_ptr is not None and mro_ptr[mi] != 0: anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) if anc is not None: - parent_lookup: t.CChar | t.CPtr = pool.alloc(128) + parent_lookup: str = pool.alloc(128) if parent_lookup is not None: viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup) @@ -5097,7 +5124,7 @@ class ExprGenMixin: return None # 在继承链中查找 dunder 方法 - lookup_name: t.CChar | t.CPtr = pool.alloc(128) + lookup_name: str = pool.alloc(128) if lookup_name is None: return None viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) @@ -5111,7 +5138,7 @@ class ExprGenMixin: while mro_ptr is not None and mro_ptr[mi] != 0: anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) if anc is not None: - parent_lookup: t.CChar | t.CPtr = pool.alloc(128) + parent_lookup: str = pool.alloc(128) if parent_lookup is not None: viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup) @@ -5259,10 +5286,11 @@ class ExprGenMixin: # 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。 if lhs_bits == 0 and rhs_bits == 0: if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift: - VLogger.error( + # fail-fast:位运算操作数类型非法,立即终止编译(暴露上游根因) + HandlesType.fatal_error( + node, "位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算", - "BinOp") - return None + "TypeError") if op == ast.OpKind.Add: return llvmlite.build_add(builder, lhs, rhs) diff --git a/App/lib/core/Gen/FuncGenMixin.vp b/App/lib/core/Gen/FuncGenMixin.vp index 5219f6e..7f7a423 100644 --- a/App/lib/core/Gen/FuncGenMixin.vp +++ b/App/lib/core/Gen/FuncGenMixin.vp @@ -67,7 +67,7 @@ class FuncGenMixin: # ============================================================ def extract_func_attrs(self, pool: memhub.MemBuddy | t.CPtr, decorator_list: list[ast.AST | t.CPtr] | t.CPtr, - imported_modules: str) -> t.CChar | t.CPtr: + imported_modules: str) -> str: """从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串""" if decorator_list is None: return None @@ -75,7 +75,7 @@ class FuncGenMixin: if dn == 0: return None - attrs_buf: t.CChar | t.CPtr = pool.alloc(256) + attrs_buf: str = pool.alloc(256) if attrs_buf is None: return None attrs_buf[0] = '\0' @@ -153,7 +153,7 @@ class FuncGenMixin: return None - def _append_llvm_attr(self, attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int: + def _append_llvm_attr(self, attrs_buf: str, attr_name: str) -> int: """将属性名映射到 LLVM 属性名并追加到缓冲区 返回 1 表示已追加,0 表示不支持该属性 @@ -191,7 +191,7 @@ class FuncGenMixin: self._append_str(attrs_buf, llvm_name) return 1 - def _append_str(self, buf: t.CChar | t.CPtr, s: str, + def _append_str(self, buf: str, s: str, max_len: t.CSizeT = 256) -> None: """将字符串追加到 buf 末尾(有界,防 strcpy 越界写穿定长缓冲)""" if buf is None or s is None: @@ -455,7 +455,7 @@ class FuncGenMixin: param_ty = llvmlite.Ptr(pool, aelem_ty) case _: param_ty = resolved - pname: t.CChar | t.CPtr = pool.alloc(32) + pname: str = pool.alloc(32) if pname is not None: viperlib.snprintf(pname, 32, "%%%s", arg.arg) llvmlite.add_param(pool, func, param_ty, pname) @@ -589,6 +589,13 @@ class FuncGenMixin: if arg_e.annotation is not None: resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, arg_e.annotation, imported_modules, from_imports, trans) + if resolved_e is None: + # fail-fast:外部声明函数参数有注解但类型解析失败, + # 不再静默保持 i32(声明签名错误会在 ABI 层暴露) + HandlesType.fatal_error( + arg_e, f"参数 '{arg_e.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg_e.annotation)}", + "NameError") + resolved_e = i32_ty # 不可达(fatal_error 已退出) if resolved_e is not None: # 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致) # CArray 形参 → 元素指针 ty*(C 数组衰减) @@ -599,13 +606,13 @@ class FuncGenMixin: param_ty_e = llvmlite.Ptr(pool, aelem_ty_e) case _: param_ty_e = resolved_e - pname_e: t.CChar | t.CPtr = pool.alloc(32) + pname_e: str = pool.alloc(32) if pname_e is not None: viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg) llvmlite.add_param(pool, func, param_ty_e, pname_e) # 提取 @c.Attribute 装饰器属性并设置到函数 - func_attrs_e: t.CChar | t.CPtr = self.extract_func_attrs(pool, fd.decorator_list, imported_modules) + func_attrs_e: str = self.extract_func_attrs(pool, fd.decorator_list, imported_modules) if func_attrs_e is not None: llvmlite.function_set_attrs(func, func_attrs_e) @@ -623,21 +630,21 @@ class FuncGenMixin: # 复用前向声明:清除 IsDeclared 标记,转为 define func.IsDeclared = 0 # 装饰器属性设置(前向声明时未设置) - func_attrs_reuse: t.CChar | t.CPtr = self.extract_func_attrs(pool, fd.decorator_list, imported_modules) + func_attrs_reuse: str = self.extract_func_attrs(pool, fd.decorator_list, imported_modules) if func_attrs_reuse is not None: llvmlite.function_set_attrs(func, func_attrs_reuse) else: # 创建新的 LLVM 函数(使用 SHA1 混淆名) func = llvmlite.create_function(pool, mod, mangled_name, ret_ty) if func is None: - fb_cf: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_cf: str = VLogger.fmt_buf() if fb_cf is not None: viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name) VLogger.error(fb_cf, "FUNC") return 0 # 提取 @c.Attribute 装饰器属性并设置到函数 - func_attrs: t.CChar | t.CPtr = self.extract_func_attrs(pool, fd.decorator_list, imported_modules) + func_attrs: str = self.extract_func_attrs(pool, fd.decorator_list, imported_modules) if func_attrs is not None: llvmlite.function_set_attrs(func, func_attrs) @@ -691,7 +698,7 @@ class FuncGenMixin: param_ty = llvmlite.Ptr(pool, aelem_ty) case _: param_ty = resolved - pname: t.CChar | t.CPtr = pool.alloc(32) + pname: str = pool.alloc(32) if pname is not None: viperlib.snprintf(pname, 32, "%%%s", arg.arg) llvmlite.add_param(pool, func, param_ty, pname) @@ -749,6 +756,12 @@ class FuncGenMixin: if arg2.annotation is not None: resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, arg2.annotation, imported_modules, from_imports, trans) + if resolved2 is None: + # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 + HandlesType.fatal_error( + arg2, f"参数 '{arg2.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg2.annotation)}", + "NameError") + resolved2 = i32_ty # 不可达(fatal_error 已退出) if resolved2 is not None: # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针); # CArray 形参 → 元素指针 ty*(数组衰减,alloca 类型须与形参一致, @@ -771,7 +784,7 @@ class FuncGenMixin: if cls_nm is not None: HandlesVar.set_var_annot_class_name( trans.SymTab, arg2.arg, cls_nm) - pname2: t.CChar | t.CPtr = pool.alloc(32) + pname2: str = pool.alloc(32) if pname2 is not None: viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( @@ -933,7 +946,7 @@ class FuncGenMixin: i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) # 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突) - promoted_name: t.CChar | t.CPtr = pool.alloc(64) + promoted_name: str = pool.alloc(64) if promoted_name is not None: viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name) mangled_promoted: str = self._mangle_name(trans, promoted_name) @@ -981,7 +994,7 @@ class FuncGenMixin: pty_slot_n: str | t.CPtr = (t.CVoid | t.CPtr)( t.CUInt64T(param_tys) + param_count * 8) pty_slot_n[0] = pty_n - pname_n: t.CChar | t.CPtr = pool.alloc(32) + pname_n: str = pool.alloc(32) if pname_n is not None: viperlib.snprintf(pname_n, 32, "%%%s", arg_n.arg) llvmlite.add_param(pool, func, pty_n, pname_n) @@ -1039,7 +1052,7 @@ class FuncGenMixin: if cls_nm_p is not None: HandlesVar.set_var_annot_class_name( trans.SymTab, arg_p.arg, cls_nm_p) - pname2_n: t.CChar | t.CPtr = pool.alloc(32) + pname2_n: str = pool.alloc(32) if pname2_n is not None: viperlib.snprintf(pname2_n, 32, "%%%s", arg_p.arg) p_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, pty2_n, pname2_n) @@ -1162,7 +1175,7 @@ class FuncGenMixin: # 1. 优先查全局堆地址映射(_prepare_chain_nonlocals 已为 # 链内 nonlocal 建堆并 store 到 @nlheap.*;不同层捕获 # 不同变量时(ClosureTest2 Test 7)level2 的 b 经此共享) - gname_ck: t.CChar | t.CPtr = self._nl_heap_global_name( + gname_ck: str = self._nl_heap_global_name( pool, trans, nl_name) if gname_ck is not None \ and self._nl_heap_global_exists(mod, gname_ck) != 0: @@ -1257,7 +1270,7 @@ class FuncGenMixin: fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) # 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名) - fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64) + fn_ptr_name: str = pool.alloc(64) if fn_ptr_name is not None: # SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func") if string.strchr(mangled_promoted, '.') is not None: @@ -1348,12 +1361,12 @@ class FuncGenMixin: # ============================================================ def _nl_heap_global_name(self, pool: memhub.MemBuddy | t.CPtr, trans: HT.Translator | t.CPtr, - name: str) -> t.CChar | t.CPtr: + name: str) -> str: """构造 nonlocal 堆地址全局映射变量名 nlheap_{sha1}.{name}""" if pool is None or trans is None or name is None: return None mangled: str = self._mangle_name(trans, name) - buf: t.CChar | t.CPtr = pool.alloc(160) + buf: str = pool.alloc(160) if buf is not None: viperlib.snprintf(buf, 160, "nlheap_%s", mangled) return buf @@ -1367,12 +1380,12 @@ class FuncGenMixin: """获取 nonlocal 堆地址全局映射变量的引用(@"..." 引号包裹)""" if pool is None or trans is None or name is None: return None - gname: t.CChar | t.CPtr = self._nl_heap_global_name(pool, trans, name) + gname: str = self._nl_heap_global_name(pool, trans, name) if gname is None: return None i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - ref_buf: t.CChar | t.CPtr = pool.alloc(176) + ref_buf: str = pool.alloc(176) if ref_buf is None: return None viperlib.snprintf(ref_buf, 176, "@\"%s\"", gname) @@ -1432,7 +1445,7 @@ class FuncGenMixin: continue dup: int = 0 for di in range(count): - if string.strcmp((t.CChar | t.CPtr)( + if string.strcmp((str)( t.CUInt64T(names) + di * 8), nm_x.id) == 0: dup = 1 break @@ -1490,7 +1503,7 @@ class FuncGenMixin: nl_ty: llvmlite.LLVMType | t.CPtr = local_alloca.Ty.Pointee if nl_ty is None: continue - gname: t.CChar | t.CPtr = self._nl_heap_global_name(pool, trans, nl_name) + gname: str = self._nl_heap_global_name(pool, trans, nl_name) if gname is None: continue # 建堆(按类型字节大小)并拷贝当前值——每次本函数执行都新建共享堆, @@ -1578,14 +1591,14 @@ class FuncGenMixin: # _PreRegisterClassMembers fallback 崩溃(FuncGen.py L437) lambda_id: int = trans._lambda_count trans._lambda_count += 1 - pname_buf: t.CChar | t.CPtr = pool.alloc(64) + pname_buf: str = pool.alloc(64) if pname_buf is None: return None viperlib.snprintf(pname_buf, 64, "__lambda_%d", lambda_id) mangled_promoted: str = self._mangle_name(trans, pname_buf) # 2. 解析参数(名称 + 类型,类型默认 i32,有注解则解析) - param_names: t.CChar | t.CPtr = pool.alloc(32 * 64) # 64 参数 × 32 字节名 + param_names: str = pool.alloc(32 * 64) # 64 参数 × 32 字节名 if param_names is None: return None string.memset(param_names, 0, 32 * 64) @@ -1610,6 +1623,12 @@ class FuncGenMixin: if arg_n.annotation is not None: resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, arg_n.annotation, trans._imported_modules, trans._from_imports, trans) + if resolved is None: + # fail-fast:lambda 参数有注解但类型解析失败,不再静默保持 i32 + HandlesType.fatal_error( + arg_n, f"参数 '{arg_n.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg_n.annotation)}", + "NameError") + resolved = i32_ty # 不可达(fatal_error 已退出) if resolved is not None: match resolved: case llvmlite.LLVMType.Struct(_, _, _): @@ -1624,7 +1643,7 @@ class FuncGenMixin: param_count += 1 # 3. 收集捕获变量(body 中的外部 Name 引用) - cap_names: t.CChar | t.CPtr = pool.alloc(64 * 64) # 64 捕获 × 64 字节名 + cap_names: str = pool.alloc(64 * 64) # 64 捕获 × 64 字节名 if cap_names is None: return None string.memset(cap_names, 0, 64 * 64) @@ -1652,7 +1671,7 @@ class FuncGenMixin: p_ty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot2[0]) if p_ty2 is None: p_ty2 = i32_ty - pname_l: t.CChar | t.CPtr = pool.alloc(32) + pname_l: str = pool.alloc(32) if pname_l is not None: viperlib.snprintf(pname_l, 32, "%%%s", param_names + pi2 * 32) llvmlite.add_param(pool, func, p_ty2, pname_l) @@ -1691,7 +1710,7 @@ class FuncGenMixin: # 9. 捕获变量:从 env 堆槽加载值到局部 alloca for ci in range(cap_count): cap_addr: t.CUInt64T = t.CUInt64T(cap_names) + ci * 64 - cap_slot: t.CChar | t.CPtr = (t.CChar | t.CPtr)(cap_addr) + cap_slot: str = (str)(cap_addr) if cap_slot[0] == '\0': continue ty_addr3: t.CUInt64T = t.CUInt64T(cap_tys) + ci * 8 @@ -1727,8 +1746,11 @@ class FuncGenMixin: ty_slot4: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr4) p_ty3: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot4[0]) if p_ty3 is None: - p_ty3 = i32_ty - pname_ref: t.CChar | t.CPtr = pool.alloc(32) + # fail-fast:lambda 参数类型槽缺失(内部状态不一致),不再静默保持 i32 + HandlesType.fatal_error( + lam, f"lambda 参数 '{param_names + pi3 * 32}' 类型信息缺失", "InternalCompilerError") + p_ty3 = i32_ty # 不可达(fatal_error 已退出) + pname_ref: str = pool.alloc(32) if pname_ref is not None: viperlib.snprintf(pname_ref, 32, "%%%s", param_names + pi3 * 32) param_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, p_ty3, pname_ref) @@ -1750,11 +1772,11 @@ class FuncGenMixin: if ret_val is not None: llvmlite.build_ret(func_builder, ret_val) else: - zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - llvmlite.build_ret(func_builder, zero_val) + # fail-fast:lambda 体类型转换失败,不再静默 ret 0 + HandlesType.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError") else: - zero_val2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - llvmlite.build_ret(func_builder, zero_val2) + # fail-fast:lambda 体翻译失败,不再静默 ret 0 + HandlesType.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError") # 12. 退出 lambda 作用域,恢复父函数状态 HandlesVar.exit_scope(trans.SymTab) @@ -1777,7 +1799,7 @@ class FuncGenMixin: if env_ptr is not None: for ci3 in range(cap_count): cap_addr3: t.CUInt64T = t.CUInt64T(cap_names) + ci3 * 64 - cap_slot3: t.CChar | t.CPtr = (t.CChar | t.CPtr)(cap_addr3) + cap_slot3: str = (str)(cap_addr3) if cap_slot3[0] == '\0': continue al_addr: t.CUInt64T = t.CUInt64T(cap_allocas) + ci3 * 8 @@ -1832,7 +1854,7 @@ class FuncGenMixin: fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) - fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64) + fn_ptr_name: str = pool.alloc(64) if fn_ptr_name is not None: if string.strchr(mangled_promoted, '.') is not None: viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) @@ -1872,9 +1894,9 @@ class FuncGenMixin: # ============================================================ def _lambda_scan_body(self, trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr, - param_names: t.CChar | t.CPtr, + param_names: str, param_count: int, - cap_names: t.CChar | t.CPtr, + cap_names: str, cap_allocas: t.CVoid | t.CPtr, cap_tys: t.CVoid | t.CPtr, cap_count: int) -> int: @@ -2040,7 +2062,7 @@ class FuncGenMixin: pool, arg.annotation, None, None, None) if resolved is not None: param_ty = resolved - pname: t.CChar | t.CPtr = pool.alloc(32) + pname: str = pool.alloc(32) if pname is not None: viperlib.snprintf(pname, 32, "%%%s", arg.arg) llvmlite.add_param(pool, func, param_ty, pname) diff --git a/App/lib/core/Gen/ImportsGenMixin.vp b/App/lib/core/Gen/ImportsGenMixin.vp index e0b1e58..096af26 100644 --- a/App/lib/core/Gen/ImportsGenMixin.vp +++ b/App/lib/core/Gen/ImportsGenMixin.vp @@ -9,6 +9,7 @@ import stdio import sys import w32.fileio as fileio import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesType as HandlesType # ============================================================ @@ -65,7 +66,7 @@ class ImportsGenMixin: return imported_modules if imported_modules is None: nlen: t.CSizeT = string.strlen(name) - buf: t.CChar | t.CPtr = pool.alloc(nlen + 1) + buf: str = pool.alloc(nlen + 1) if buf is not None: string.strcpy(buf, name) return buf @@ -74,7 +75,7 @@ class ImportsGenMixin: old_len: t.CSizeT = string.strlen(imported_modules) name_len: t.CSizeT = string.strlen(name) new_len: t.CSizeT = old_len + 1 + name_len - buf2: t.CChar | t.CPtr = pool.alloc(new_len + 1) + buf2: str = pool.alloc(new_len + 1) if buf2 is not None: string.strcpy(buf2, imported_modules) buf2[old_len] = ' ' @@ -90,7 +91,7 @@ class ImportsGenMixin: if name is None or imported_modules is None: return 0 name_len: t.CSizeT = string.strlen(name) - cur: t.CChar | t.CPtr = imported_modules + cur: str = imported_modules total_len: t.CSizeT = string.strlen(imported_modules) ci: t.CSizeT = 0 while ci < total_len: @@ -129,7 +130,7 @@ class ImportsGenMixin: """ if local_name is None or module_name is None: return from_imports - entry: t.CChar | t.CPtr = pool.alloc(256) + entry: str = pool.alloc(256) if entry is None: return from_imports if original_name is not None and string.strcmp(original_name, local_name) != 0: @@ -142,7 +143,7 @@ class ImportsGenMixin: old_len: t.CSizeT = string.strlen(from_imports) entry_len: t.CSizeT = string.strlen(entry) new_len: t.CSizeT = old_len + 1 + entry_len - buf: t.CChar | t.CPtr = pool.alloc(new_len + 1) + buf: str = pool.alloc(new_len + 1) if buf is not None: string.strcpy(buf, from_imports) buf[old_len] = ' ' @@ -162,7 +163,7 @@ class ImportsGenMixin: if local_name is None or from_imports is None: return None name_len: t.CSizeT = string.strlen(local_name) - cur: t.CChar | t.CPtr = from_imports + cur: str = from_imports ci: t.CSizeT = 0 total_len: t.CSizeT = string.strlen(from_imports) while ci < total_len: @@ -236,7 +237,7 @@ class ImportsGenMixin: if name is None or from_imports is None: return None name_len: t.CSizeT = string.strlen(name) - cur: t.CChar | t.CPtr = from_imports + cur: str = from_imports ci: t.CSizeT = 0 total_len: t.CSizeT = string.strlen(from_imports) star_mod: str = None @@ -380,6 +381,8 @@ class ImportsGenMixin: if level <= 0: return module if current_package is None: + # 相对导入但无当前包上下文:直接报错终止(fail-fast),暴露上游根因 + HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError") return module # 从 current_package 开始,上溯 (level-1) 级 @@ -396,12 +399,14 @@ class ImportsGenMixin: found = 1 i += 1 if found == 0: - # 无更多父级,包变为空 + # 无更多父级(相对导入越界):直接报错终止(fail-fast) + HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError") pkg = None break # 截断到最后一个 '.' 处 new_pkg: str = pool.alloc(last_dot + 1) if new_pkg is None: + HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError") return module string.strncpy(new_pkg, pkg, last_dot) new_pkg[last_dot] = '\0' @@ -412,13 +417,15 @@ class ImportsGenMixin: # from . import Y → 模块就是包本身 return pkg if pkg is None: - # 包已上溯到空,直接用 module + # 包已上溯到空(相对导入越界):直接报错终止(fail-fast) + HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError") return module # 拼接 pkg + "." + module pkg_len2: t.CSizeT = string.strlen(pkg) mod_len: t.CSizeT = string.strlen(module) buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1) if buf is None: + HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError") return module string.strcpy(buf, pkg) buf[pkg_len2] = '.' @@ -612,7 +619,7 @@ class ImportsGenMixin: # SHA1 在项目文件列表而非 includes 扫描存储器,不应报错) if self._is_local_module_file(mod_name) != 0: return 1 - err_buf: t.CChar | t.CPtr = stdlib.malloc(256) + err_buf: str = stdlib.malloc(256) if err_buf is not None: viperlib.snprintf(err_buf, 256, "模块 '%s' 未注册 SHA1(includes 扫描未找到该模块,请检查 project.json 的 includes 路径配置)", diff --git a/App/lib/core/Gen/StmtGenMixin.vp b/App/lib/core/Gen/StmtGenMixin.vp index b8a2236..6532239 100644 --- a/App/lib/core/Gen/StmtGenMixin.vp +++ b/App/lib/core/Gen/StmtGenMixin.vp @@ -123,6 +123,8 @@ class StmtGenMixin: return trans.MatchH.Handle(node) elif k == ast.ASTKind.Delete: return self.translate_delete(trans, node) + # 未知语句类型:直接报错终止(fail-fast),暴露上游解析问题 + HandlesType.fatal_error(node, f"未知语句类型 kind={k}", "SyntaxError") return 0 def translate_delete(self, trans: HT.Translator | t.CPtr, @@ -194,12 +196,12 @@ class StmtGenMixin: if var_alloca is not None and var_alloca.Ty is not None: var_ty = var_alloca.Ty.Pointee # Void 类型视为无效(Pointee 访问异常时可能返回 Void), - # 设为 None 让 add_nonlocal_name 回退为 i32,避免生成 + # 类型无效直接报错终止(fail-fast),避免生成 # "bitcast ... to void*" / "load void, void*" 非法 IR if var_ty is not None: match var_ty: case llvmlite.LLVMType.Void(): - var_ty = None + HandlesType.fatal_error(nm_node, f"nonlocal 变量 '{nm.id}' 类型无效(Void/无法解析)", "TypeError") case _: pass HT.add_nonlocal_name(trans, nm.id, var_ty) @@ -225,7 +227,8 @@ class StmtGenMixin: func_name: str = HandlesExpr.get_func_name(func_node) if func_name is None: - return 0 + # 函数名解析失败:直接报错终止(fail-fast) + HandlesType.fatal_error(call_node, "表达式语句的函数名解析失败", "SyntaxError") # printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf) if string.strcmp(func_name, "printf") == 0: @@ -276,7 +279,7 @@ class StmtGenMixin: # 创建死代码 BB,用于后续语句(break 后面的代码不可达) cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "dead.%d", cnt) dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) llvmlite.position_at_end(builder, dead_bb) @@ -299,7 +302,7 @@ class StmtGenMixin: # 创建死代码 BB,用于后续语句 cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "dead.%d", cnt) dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) llvmlite.position_at_end(builder, dead_bb) @@ -846,8 +849,8 @@ class StmtGenMixin: # 获取变量类型(从注册时存储的类型信息) var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) if var_ty is None or self._is_void_type(var_ty) != 0: - # Void 类型视为无效(会导致 "load void, void*" 非法 IR),回退为 i32 - var_ty = llvmlite.Int32(pool) + # 类型缺失/无效直接报错终止(fail-fast),避免生成 "load void, void*" 非法 IR + HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError") # bitcast raw i8* to var_ty* var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) @@ -872,8 +875,8 @@ class StmtGenMixin: # 获取变量类型 var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) if var_ty is None or self._is_void_type(var_ty) != 0: - # Void 类型视为无效(会导致 "bitcast ... to void*" 非法 IR),回退为 i32 - var_ty = llvmlite.Int32(pool) + # 类型缺失/无效直接报错终止(fail-fast),避免生成 "bitcast ... to void*" 非法 IR + HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError") # bitcast raw i8* to var_ty* var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) @@ -926,7 +929,7 @@ class StmtGenMixin: return existing if self.EnumCount >= ENUM_MAX: - fb_et: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_et: str = VLogger.fmt_buf() if fb_et is not None: viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name) VLogger.error(fb_et, "ENUM") @@ -945,7 +948,7 @@ class StmtGenMixin: # 复制类名 name_len: t.CSizeT = string.strlen(name) - name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) + name_buf: str = pool.alloc(name_len + 1) if name_buf is not None: string.strcpy(name_buf, name) entry.Name = name_buf @@ -966,7 +969,7 @@ class StmtGenMixin: return -1 if enum_entry.MemberCount >= ENUM_MEMBER_MAX: - fb_em: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_em: str = VLogger.fmt_buf() if fb_em is not None: viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name) VLogger.error(fb_em, "ENUM") @@ -979,7 +982,7 @@ class StmtGenMixin: # 复制成员名 name_len: t.CSizeT = string.strlen(member_name) - name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) + name_buf: str = pool.alloc(name_len + 1) if name_buf is not None: string.strcpy(name_buf, member_name) me.Name = name_buf diff --git a/App/lib/core/Gen/StructGenMixin.vp b/App/lib/core/Gen/StructGenMixin.vp index a0ec83b..d60c18c 100644 --- a/App/lib/core/Gen/StructGenMixin.vp +++ b/App/lib/core/Gen/StructGenMixin.vp @@ -172,7 +172,7 @@ class StructGenMixin: return existing if self.StructCount >= STRUCT_MAX: - fb_st: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_st: str = VLogger.fmt_buf() if fb_st is not None: viperlib.snprintf(fb_st, 1024, "table full, cannot register %s", name) VLogger.error(fb_st, "STRUCT") @@ -197,7 +197,7 @@ class StructGenMixin: # Name 越界读 → G3 LinkedNode.prepend 挂起根因。stdlib 分配不随 # pool reset 回收,多遍去重(Ty 比较)避免重复分配。) name_len: t.CSizeT = string.strlen(name) - name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1) + name_buf: str = stdlib.malloc(name_len + 1) if name_buf is not None: string.strcpy(name_buf, name) entry.Name = name_buf @@ -209,7 +209,7 @@ class StructGenMixin: # SHA1 同样统一 stdlib(跨 1a/1b 存活,防 strcmp 悬空) if sha1 is not None: sha1_len: t.CSizeT = string.strlen(sha1) - sha1_buf: t.CChar | t.CPtr = stdlib.malloc(sha1_len + 1) + sha1_buf: str = stdlib.malloc(sha1_len + 1) if sha1_buf is not None: string.strcpy(sha1_buf, sha1) entry.ModuleSha1 = sha1_buf @@ -227,7 +227,7 @@ class StructGenMixin: return 0 # 复制 SHA1 字符串(统一 stdlib,跨 1a/1b 存活防 strcmp 悬空) sha1_len: t.CSizeT = string.strlen(sha1) - sha1_buf: t.CChar | t.CPtr = stdlib.malloc(sha1_len + 1) + sha1_buf: str = stdlib.malloc(sha1_len + 1) if sha1_buf is None: return 0 string.strcpy(sha1_buf, sha1) @@ -248,7 +248,7 @@ class StructGenMixin: field_name: str, field_ty: llvmlite.LLVMType | t.CPtr, default_val: ast.AST | t.CPtr = None, - annot_class_name: t.CChar | t.CPtr = None) -> int: + annot_class_name: str = None) -> int: """向结构体添加字段,返回字段索引(-1 失败) default_val: 字段默认值 AST 节点(可选,None=无默认值) @@ -258,7 +258,7 @@ class StructGenMixin: return -1 if struct_entry.FieldCount >= FIELD_MAX: - fb_sf: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_sf: str = VLogger.fmt_buf() if fb_sf is not None: viperlib.snprintf(fb_sf, 1024, "field table full for %s", struct_entry.Name) VLogger.error(fb_sf, "STRUCT") @@ -273,7 +273,7 @@ class StructGenMixin: # 否则 lookup_field 的 strcmp(fe.Name, ...) 读悬空越界挂起, # 与 register_struct 的 Name 悬空同根因) name_len: t.CSizeT = string.strlen(field_name) - name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1) + name_buf: str = stdlib.malloc(name_len + 1) if name_buf is not None: string.strcpy(name_buf, field_name) fe.Name = name_buf @@ -293,7 +293,7 @@ class StructGenMixin: fe.Ty = field_ty if annot_class_name is not None: annot_len: t.CSizeT = string.strlen(annot_class_name) - annot_buf: t.CChar | t.CPtr = stdlib.malloc(annot_len + 1) + annot_buf: str = stdlib.malloc(annot_len + 1) if annot_buf is not None: string.strcpy(annot_buf, annot_class_name) fe.AnnotClassName = annot_buf @@ -346,7 +346,7 @@ class StructGenMixin: dst_c.float_val = src_c.float_val if src_c.str_val is not None: s_len: t.CSizeT = string.strlen(src_c.str_val) - s_copy: t.CChar | t.CPtr = stdlib.malloc(s_len + 1) + s_copy: str = stdlib.malloc(s_len + 1) if s_copy is not None: string.strcpy(s_copy, src_c.str_val) dst_c.str_val = s_copy @@ -593,7 +593,7 @@ class StructGenMixin: entry = self.find_struct(class_name) if entry is None: # 诊断:目标类未注册 - fb_lfbc: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_lfbc: str = VLogger.fmt_buf() if fb_lfbc is not None: viperlib.snprintf(fb_lfbc, 1024, "lookup_field_by_class: 类 '%s' 未注册 (struct_count=%d)", @@ -611,14 +611,14 @@ class StructGenMixin: for fi in range(entry.FieldCount): fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) if fe is not None: - fb_fn: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_fn: str = VLogger.fmt_buf() if fb_fn is not None: if fe.Name is not None: viperlib.snprintf(fb_fn, 1024, " 字段[%d]: '%s'", fi, fe.Name) else: viperlib.snprintf(fb_fn, 1024, " 字段[%d]: (null)", fi) VLogger.warning(fb_fn, "STRUCT") - fb_fields: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_fields: str = VLogger.fmt_buf() if fb_fields is not None: viperlib.snprintf(fb_fields, 1024, "lookup_field_by_class: 类 '%s' 已注册 (FieldCount=%d) 但字段 '%s' 未找到", @@ -795,7 +795,7 @@ class StructGenMixin: # 构造 "SHA1.ClassName" 格式进行比较 entry2_sha1: str = entry2.ModuleSha1 if entry2_sha1 is not None: - full_nm: t.CChar | t.CPtr = pool.alloc(128) + full_nm: str = pool.alloc(128) if full_nm is not None: viperlib.snprintf(full_nm, 128, "%s.%s", entry2_sha1, entry2.Name) if string.strcmp(full_nm, ty_name) == 0: @@ -891,7 +891,7 @@ class StructGenMixin: src: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr)) if src is not None: slen: t.CSizeT = string.strlen(src) - dup: t.CChar | t.CPtr = stdlib.malloc(slen + 1) + dup: str = stdlib.malloc(slen + 1) if dup is not None: string.strcpy(dup, src) arr[i] = t.CSizeT(dup) @@ -990,7 +990,7 @@ class StructGenMixin: return None return entry.ParentName - def set_vtable_methods(self, name: str, methods: t.CChar | t.CPtr, count: int) -> int: + def set_vtable_methods(self, name: str, methods: str, count: int) -> int: """设置虚表方法名数组,返回 1=成功 / 0=失败""" if name is None: return 0 @@ -1076,7 +1076,7 @@ class StructGenMixin: case _: pass # 获取结构体名称(非 Struct 类型返回 None) - sname: t.CChar | t.CPtr = llvmlite.get_struct_name(ty) + sname: str = llvmlite.get_struct_name(ty) if sname is None: return # 检查是否为跨模块引用(名称包含 '.') @@ -1095,7 +1095,7 @@ class StructGenMixin: total_len: t.CSizeT = string.strlen(sname) class_name_len: t.CSizeT = string.strlen(class_name) sha1_len: t.CSizeT = total_len - class_name_len - 1 - sha1_buf: t.CChar | t.CPtr = pool.alloc(32) + sha1_buf: str = pool.alloc(32) if sha1_buf is None: return # 32 字节缓冲:strncpy 不截断,前缀超过 31 字符会越界写 + 手动 NUL 再越界 diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index 588d11c..d92d565 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -244,7 +244,7 @@ class TranslatorGenMixin: # 按数组声明长度 arr_count 计算(元素不足时补零,可能多于 elts_count) cnt_total: t.CSizeT = t.CSizeT(arr_count) buf_size: t.CSizeT = 64 + cnt_total * 32 - buf: t.CChar | t.CPtr = pool.alloc(buf_size) + buf: str = pool.alloc(buf_size) if buf is None: return None @@ -298,7 +298,7 @@ class TranslatorGenMixin: return None # 构造内部字符串常量名称: .str.{var_name} - str_name_buf: t.CChar | t.CPtr = pool.alloc(64) + str_name_buf: str = pool.alloc(64) if str_name_buf is None: return None viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name) @@ -311,7 +311,7 @@ class TranslatorGenMixin: # 生成 GEP 初始化器文本 str_len: t.CSizeT = string.strlen(str_val) - init_buf: t.CChar | t.CPtr = pool.alloc(128) + init_buf: str = pool.alloc(128) if init_buf is None: return None viperlib.snprintf(init_buf, 128, @@ -437,7 +437,7 @@ class TranslatorGenMixin: gv.Linkage = None if init_kind == 1: # 整数初始值 - init_buf: t.CChar | t.CPtr = pool.alloc(48) + init_buf: str = pool.alloc(48) if init_buf is not None: viperlib.snprintf(init_buf, 48, "%lld", init_val) gv.Initializer = init_buf @@ -447,14 +447,16 @@ class TranslatorGenMixin: if arr_init is not None: gv.Initializer = arr_init else: - gv.Initializer = "zeroinitializer" + # 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer + HandlesType.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError") elif init_kind == 3: # 字符串字面量 → 创建字符串常量全局 + GEP 引用 str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val) if str_init is not None: gv.Initializer = str_init else: - gv.Initializer = "zeroinitializer" + # 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer + HandlesType.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError") else: # 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer, # 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type" @@ -462,7 +464,7 @@ class TranslatorGenMixin: # 创建 Value 引用(@var_name, 类型为 var_ty*) var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) - ref_name: t.CChar | t.CPtr = pool.alloc(64) + ref_name: str = pool.alloc(64) if ref_name is not None: viperlib.snprintf(ref_name, 64, "@%s", var_name) gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name) @@ -641,12 +643,11 @@ class TranslatorGenMixin: if trans._nonlocal_types is not None: ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8 ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2) - # var_ty 为 None 时存入 i32 作为默认类型 + # var_ty 为 None 时直接报错终止(fail-fast),不再默认 i32 stored_ty: llvmlite.LLVMType | t.CPtr = var_ty if stored_ty is None: - pool: memhub.MemBuddy | t.CPtr = trans.Pool - if pool is not None: - stored_ty = llvmlite.Int32(pool) + HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法注册", "TypeError") + return ty_slot2[0] = stored_ty trans._nonlocal_name_count += 1 trans._closure_env_count += 1 diff --git a/App/lib/core/Gen/TypeGenMixin.vp b/App/lib/core/Gen/TypeGenMixin.vp index 64e8a09..da82236 100644 --- a/App/lib/core/Gen/TypeGenMixin.vp +++ b/App/lib/core/Gen/TypeGenMixin.vp @@ -512,7 +512,7 @@ class TypeGenMixin: self.ConstEvalOk = 1 return x_val # 定位日志:跨模块 CDefine 查找失败(t.CArray count 场景) - fb_cdf: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_cdf: str = VLogger.fmt_buf() if fb_cdf is not None: viperlib.snprintf(fb_cdf, 1024, "[CDEF-MISS] name=%s fi=%s im=%s", @@ -945,7 +945,7 @@ class TypeGenMixin: type_name: str) -> llvmlite.LLVMType | t.CPtr: """将 t.CXxx / c.CXxx 类型名映射到 LLVMType - 注意: t.CChar | t.CPtr = i8* = str = bytes + 注意: str = i8* = str = bytes """ if type_name is None: return None @@ -995,7 +995,7 @@ class TypeGenMixin: return llvmlite.Double(pool) elif string.strcmp(type_name, "CFloat128T") == 0: return llvmlite.FP128(pool) - # 指针/void: t.CPtr = i8*, t.CChar | t.CPtr = i8* = str = bytes + # 指针/void: t.CPtr = i8*, str = i8* = str = bytes elif string.strcmp(type_name, "CPtr") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) elif string.strcmp(type_name, "CVoid") == 0: @@ -1316,7 +1316,7 @@ class TypeGenMixin: if at.value is not None: prefix: str = self.annotation_to_str(at.value) if prefix is not None: - buf: t.CChar | t.CPtr = stdlib.malloc( + buf: str = stdlib.malloc( string.strlen(prefix) + string.strlen(at.attr) + 2) if buf is not None: viperlib.snprintf(buf, @@ -1330,7 +1330,7 @@ class TypeGenMixin: sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) base: str = self.annotation_to_str(sub.value) if base is not None: - buf2: t.CChar | t.CPtr = stdlib.malloc(string.strlen(base) + 5) + buf2: str = stdlib.malloc(string.strlen(base) + 5) if buf2 is not None: viperlib.snprintf(buf2, string.strlen(base) + 5, "%s[...]", base) @@ -1343,7 +1343,7 @@ class TypeGenMixin: left_s: str = self.annotation_to_str(bo.left) right_s: str = self.annotation_to_str(bo.right) if left_s is not None and right_s is not None: - buf3: t.CChar | t.CPtr = stdlib.malloc( + buf3: str = stdlib.malloc( string.strlen(left_s) + string.strlen(right_s) + 5) if buf3 is not None: viperlib.snprintf(buf3, @@ -1420,7 +1420,7 @@ class TypeGenMixin: if val_nm2.id is not None and string.strcmp(val_nm2.id, "t") == 0: return at.attr # 返回模块限定名 "module.Class"(如 "memhub.MemBuddy") - mod_qual_buf: t.CChar | t.CPtr = stdlib.malloc( + mod_qual_buf: str = stdlib.malloc( string.strlen(val_nm2.id) + string.strlen(at.attr) + 2) if mod_qual_buf is not None: viperlib.snprintf(mod_qual_buf, @@ -1699,7 +1699,7 @@ class TypeGenMixin: gp_sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, gp_ta, nm.ctx) if gp_sub_node is not None: return self.resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports, trans) - # str = bytes = t.CChar | t.CPtr = i8* + # str = bytes = str = i8* if string.strcmp(nm.id, "str") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) elif string.strcmp(nm.id, "int") == 0: @@ -1910,8 +1910,12 @@ class TypeGenMixin: other_cls_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(other_cls_nm) if other_cls_ty is not None: return llvmlite.Ptr(pool, other_cls_ty) - # CPtr 单独使用或其他无效类型 → i8* - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # fail-fast:CPtr 标记下 other 侧类型完全无法解析, + # 不再静默退化为 i8*,暴露上游类型错误根因。 + # (t.CVoid | t.CPtr → i8* 的合法语义分支在 other_is_cvoid 处已提前返回) + HandlesType.fatal_error( + node, f"联合类型 '{HandlesType.annotation_to_str(node)}' 中类型无法解析", "NameError") + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 不可达(fatal_error 已退出) return llvmlite.Ptr(pool, other_ty) # 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略) @@ -2123,13 +2127,13 @@ class TypeGenMixin: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) if nm.id is not None and param_types is not None: # 在 param_types 中查找: "name:bits" 格式 - search_key: t.CChar | t.CPtr = pool.alloc(64) + search_key: str = pool.alloc(64) if search_key is not None: viperlib.snprintf(search_key, 64, "%s:", nm.id) - found: t.CChar | t.CPtr = string.strstr(param_types, search_key) + found: str = string.strstr(param_types, search_key) if found is not None: colon_pos: t.CSizeT = string.strlen(nm.id) + 1 - bits_str: t.CChar | t.CPtr = found + colon_pos + bits_str: str = found + colon_pos bits: int = 0 for bi in range(4): ch: t.CChar = bits_str[bi] @@ -2196,7 +2200,7 @@ class TypeGenMixin: return None buf_size: t.CSizeT = an * 32 + 1 - buf: t.CChar | t.CPtr = pool.alloc(buf_size) + buf: str = pool.alloc(buf_size) if buf is None: return None buf[0] = '\0' @@ -2217,7 +2221,7 @@ class TypeGenMixin: bits: int = self.get_llvm_type_bits(param_ty) if bits == 0: bits = 32 - tmp: t.CChar | t.CPtr = pool.alloc(32) + tmp: str = pool.alloc(32) if tmp is not None: viperlib.snprintf(tmp, 32, "%s:%d", arg.arg, bits) if ai > 0: @@ -2225,7 +2229,7 @@ class TypeGenMixin: self._strappend(buf, buf_size, tmp) return buf - def _strappend(self, dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + def _strappend(self, dst: str, dst_size: t.CSizeT, src: str): """将 src 追加到 dst 末尾""" if dst is None or src is None: return diff --git a/App/lib/core/Handles/HandlesAnnAssign.vp b/App/lib/core/Handles/HandlesAnnAssign.vp index f7e324b..6d450e0 100644 --- a/App/lib/core/Handles/HandlesAnnAssign.vp +++ b/App/lib/core/Handles/HandlesAnnAssign.vp @@ -369,11 +369,11 @@ class AnnAssignHandle(HandlesBase.Mixin): f"变量类型注解解析失败,变量名: {nm.id}", "TypeError") else: - # fast-fail: AnnAssign 必须有 annotation - VLogger.error( + # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) + HandlesType.fatal_error( + aa, f"AnnAssign 缺少类型注解,变量名: {nm.id}", - "HandlesAnnAssign") - var_ty = llvmlite.Int32(pool) + "SyntaxError") # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) HandlesStruct.ensure_struct_def_in_module(pool, self.Trans.Module, var_ty) @@ -441,11 +441,11 @@ class AnnAssignHandle(HandlesBase.Mixin): f"变量类型注解解析失败,变量名: {nm.id}", "TypeError") else: - # fast-fail: AnnAssign 必须有 annotation - VLogger.error( + # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) + HandlesType.fatal_error( + aa, f"AnnAssign 缺少类型注解,变量名: {nm.id}", - "HandlesAnnAssign") - var_ty = llvmlite.Int32(pool) + "SyntaxError") # t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型) callable_ret: llvmlite.LLVMType | t.CPtr = HandlesType.try_extract_callable_ret( @@ -533,7 +533,11 @@ class AnnAssignHandle(HandlesBase.Mixin): alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( self.Trans.SymTab, pool, builder, nm.id, var_ty) if alloca is None: - return 0 + # fail-fast: 存储创建失败,立即终止(禁止静默跳过) + HandlesType.fatal_error( + aa, + f"无法为变量 {nm.id} 创建存储", + "TypeError") # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) if annot is not None: cls_nm_hd: str = HandlesType.extract_class_name_from_annotation( @@ -573,7 +577,10 @@ class AnnAssignHandle(HandlesBase.Mixin): builder, pool, mod, alloca, aa.value, self.Trans) else: # 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32 + # CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref + # 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。 self.Trans.CurAssignAnnot = aa.annotation + self.Trans.CurAssignNode = aa.value rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, aa.value, None, 0, self.Trans) @@ -619,6 +626,11 @@ class AnnAssignHandle(HandlesBase.Mixin): if target_ty is not None: rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) llvmlite.build_store(builder, rhs_val, alloca) + # 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该 + # AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的 + # c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。 + self.Trans.CurAssignAnnot = None + self.Trans.CurAssignNode = None return 0 diff --git a/App/lib/core/Handles/HandlesAssign.vp b/App/lib/core/Handles/HandlesAssign.vp index 1999c26..69a1b9d 100644 --- a/App/lib/core/Handles/HandlesAssign.vp +++ b/App/lib/core/Handles/HandlesAssign.vp @@ -60,13 +60,15 @@ class AssignHandle(HandlesBase.Mixin): mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module # 翻译 RHS 值 - # 无注解赋值无目标类型可推断,清空 CurAssignAnnot(防残留误判 c.Deref 宽度) + # 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode + # (防残留误判 c.Deref 宽度) self.Trans.CurAssignAnnot = None + self.Trans.CurAssignNode = None rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, asgn.value, None, 0, self.Trans) if rhs_val is None: # 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位 - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None and asgn.value is not None: sha1: str = self.Trans.ModuleSha1 val_kind: int = asgn.value.kind() @@ -164,8 +166,11 @@ class AssignHandle(HandlesBase.Mixin): break fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur) fcur = llvmlite.paramnode_get_next(fcur) + if fty is None: + # fail-fast: 字段类型缺失,立即终止 + HandlesType.fatal_error(target, "元组解包字段类型缺失", "TypeError") # 守卫:非 Name 元素无法解包,跳过 - if fty is None or tgt_elt.kind() != ast.ASTKind.Name: + if tgt_elt.kind() != ast.ASTKind.Name: continue tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt) if tgt_nm2.id is None: @@ -203,9 +208,11 @@ class AssignHandle(HandlesBase.Mixin): if sub_node is not None and sub_node.slice is not None: list_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, sub_node.slice, None, 0, self.Trans) - if list_idx_val is not None: - HandlesExpr.list_setitem_inline( - builder, pool, list_obj, list_idx_val, rhs_val, target) + if list_idx_val is None: + # fail-fast: list 下标翻译失败,立即终止 + HandlesType.fatal_error(target, "list 下标翻译失败", "TypeError") + HandlesExpr.list_setitem_inline( + builder, pool, list_obj, list_idx_val, rhs_val, target) continue # 普通 Subscript 赋值 elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( @@ -369,7 +376,7 @@ class AssignHandle(HandlesBase.Mixin): if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name: obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value) obj_name = obj_nm.id - err_buf: t.CChar | t.CPtr = pool.alloc(256) + err_buf: str = pool.alloc(256) if err_buf is not None: viperlib.snprintf(err_buf, 256, "attribute ptr is None: %s.%s", @@ -390,7 +397,11 @@ class AssignHandle(HandlesBase.Mixin): mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( self.Trans.SymTab, nm.id) if mod_alloca is None: - continue + # fail-fast: global 变量未注册,无法赋值 + HandlesType.fatal_error( + target, + f"global 变量 '{nm.id}' 未注册,无法赋值", + "NameError") target_ty: llvmlite.LLVMType | t.CPtr = None if mod_alloca.Ty is not None: target_ty = mod_alloca.Ty.Pointee @@ -404,18 +415,22 @@ class AssignHandle(HandlesBase.Mixin): nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( self.Trans, nm.id) if nl_ptr is None: - continue + # fail-fast: nonlocal 变量指针解析失败 + HandlesType.fatal_error( + target, + f"nonlocal 变量 '{nm.id}' 指针解析失败", + "NameError") # 从 nl_ptr 的类型推断 nonlocal 变量实际类型, # 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏) nl_target_ty: llvmlite.LLVMType | t.CPtr = None if nl_ptr.Ty is not None: nl_target_ty = nl_ptr.Ty.Pointee if nl_target_ty is None: - # fast-fail: nl_ptr 类型信息丢失,无法安全 store - VLogger.error( - f"nonlocal 变量类型信息丢失,无法写入: {nm.id}", - "HandlesAssign") - continue + # fail-fast: nl_ptr 类型信息丢失,无法安全 store + HandlesType.fatal_error( + target, + f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入", + "TypeError") rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( builder, rhs_val, nl_target_ty, node) llvmlite.build_store(builder, rhs_coerced, nl_ptr) @@ -428,7 +443,7 @@ class AssignHandle(HandlesBase.Mixin): mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( self.Trans.SymTab, nm.id) if mod_gv is not None: - fb_g: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_g: str = VLogger.fmt_buf() msg_g: str = "global 声明缺失" if fb_g is not None: viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id) @@ -457,10 +472,11 @@ class AssignHandle(HandlesBase.Mixin): if existing is None: new_vars += 1 else: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "alloca failed for %s", nm.id) - VLogger.error(fb, "ASGN") + # fail-fast: 变量存储创建失败,立即终止 + HandlesType.fatal_error( + target, + f"变量 '{nm.id}' 存储创建失败", + "TypeError") return new_vars diff --git a/App/lib/core/Handles/HandlesAugAssign.vp b/App/lib/core/Handles/HandlesAugAssign.vp index 7336f3a..2039d02 100644 --- a/App/lib/core/Handles/HandlesAugAssign.vp +++ b/App/lib/core/Handles/HandlesAugAssign.vp @@ -12,6 +12,7 @@ import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesType as HandlesType # ============================================================ @@ -78,40 +79,41 @@ class AugAssignHandle(HandlesBase.Mixin): field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( builder, pool, mod, target, self.Trans) if field_ptr is None: - VLogger.error("attribute ptr is None", "AUGASGN") - return 0 + # fail-fast: 属性指针解析失败 + HandlesType.fatal_error(target, "attribute ptr is None", "TypeError") # 2. 确定字段类型并加载当前值 - target_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if field_ptr.Ty is not None: + target_ty: llvmlite.LLVMType | t.CPtr = None + if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None: target_ty = field_ptr.Ty.Pointee + if target_ty is None: + # fail-fast: 字段类型信息缺失,禁止兜底 i32 + HandlesType.fatal_error(target, "字段类型信息缺失", "TypeError") cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, target_ty, field_ptr) if cur_val is None: - VLogger.error("cannot load attribute", "AUGASGN") - return 0 + # fail-fast: 属性当前值加载失败 + HandlesType.fatal_error(target, "无法加载 attribute 当前值", "TypeError") # 3. 翻译 RHS 值 rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, aug.value, None, 0, self.Trans) if rhs_val is None: - VLogger.error("rhs is None", "AUGASGN") - return 0 + # fail-fast: RHS 翻译失败 + HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") # 4. 应用二元运算 result: llvmlite.Value | t.CPtr = _apply_aug_op( pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target) if result is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "binop failed for attr op=%d", aug.op) - VLogger.error(fb, "AUGASGN") - return 0 + # fail-fast: attribute 二元运算失败 + HandlesType.fatal_error(target, f"attribute 二元运算失败 op={aug.op}", "TypeError") # 5. 类型对齐并存储 result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) if result is None: - return 0 + # fail-fast: 类型对齐失败 + HandlesType.fatal_error(target, "类型对齐失败", "TypeError") llvmlite.build_store(builder, result, field_ptr) return 0 @@ -126,46 +128,48 @@ class AugAssignHandle(HandlesBase.Mixin): elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( builder, pool, mod, target, self.Trans) if elem_ptr is None: - VLogger.error("subscript ptr is None", "AUGASGN") - return 0 + # fail-fast: 下标指针解析失败 + HandlesType.fatal_error(target, "subscript ptr is None", "TypeError") # 2. 确定元素类型并加载当前值 - target_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + target_ty: llvmlite.LLVMType | t.CPtr = None if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: target_ty = elem_ptr.Ty.Pointee + if target_ty is None: + # fail-fast: 元素类型信息缺失,禁止兜底 i32 + HandlesType.fatal_error(target, "元素类型信息缺失", "TypeError") cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, target_ty, elem_ptr) if cur_val is None: - VLogger.error("cannot load subscript element", "AUGASGN") - return 0 + # fail-fast: 元素当前值加载失败 + HandlesType.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError") # 3. 翻译 RHS 值 rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, aug.value, None, 0, self.Trans) if rhs_val is None: - VLogger.error("rhs is None", "AUGASGN") - return 0 + # fail-fast: RHS 翻译失败 + HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") # 4. 应用二元运算 result: llvmlite.Value | t.CPtr = _apply_aug_op( pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target) if result is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "binop failed for sub op=%d", aug.op) - VLogger.error(fb, "AUGASGN") - return 0 + # fail-fast: subscript 二元运算失败 + HandlesType.fatal_error(target, f"subscript 二元运算失败 op={aug.op}", "TypeError") # 5. 类型对齐并存储 result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) if result is None: - return 0 + # fail-fast: 类型对齐失败 + HandlesType.fatal_error(target, "类型对齐失败", "TypeError") llvmlite.build_store(builder, result, elem_ptr) return 0 if tk != ast.ASTKind.Name: - VLogger.error("only Name/Attribute/Subscript target supported", "AUGASGN") - return 0 + # fail-fast: 不支持的 AugAssign 目标类型 + HandlesType.fatal_error( + target, "AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript", "TypeError") nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) if nm is None or nm.id is None: @@ -174,7 +178,6 @@ class AugAssignHandle(HandlesBase.Mixin): pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) # 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal scope_type: int = 0 @@ -186,15 +189,17 @@ class AugAssignHandle(HandlesBase.Mixin): # 2. 加载当前值 cur_val: llvmlite.Value | t.CPtr = None target_alloca: llvmlite.Value | t.CPtr = None - target_ty: llvmlite.LLVMType | t.CPtr = i32_ty + target_ty: llvmlite.LLVMType | t.CPtr = None if scope_type == 1: # global 变量 target_alloca = HandlesVar.lookup_module_var( self.Trans.SymTab, nm.id) if target_alloca is not None: - if target_alloca.Ty is not None: - target_ty = target_alloca.Ty.Pointee + if target_alloca.Ty is None: + # fail-fast: 变量类型信息缺失,禁止兜底 i32 + HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError") + target_ty = target_alloca.Ty.Pointee cur_val = llvmlite.build_load(builder, target_ty, target_alloca) elif scope_type == 2: # nonlocal 变量(通过闭包 env) @@ -205,39 +210,42 @@ class AugAssignHandle(HandlesBase.Mixin): # 普通局部变量 target_alloca = HandlesVar.lookup_var(self.Trans.SymTab, nm.id) if target_alloca is not None: - if target_alloca.Ty is not None: - target_ty = target_alloca.Ty.Pointee + if target_alloca.Ty is None: + # fail-fast: 变量类型信息缺失,禁止兜底 i32 + HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError") + target_ty = target_alloca.Ty.Pointee cur_val = llvmlite.build_load(builder, target_ty, target_alloca) if cur_val is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "cannot load target %s", nm.id) - VLogger.error(fb, "AUGASGN") - return 0 + # fail-fast: 目标变量当前值加载失败 + HandlesType.fatal_error( + target, + f"无法加载目标变量 '{nm.id}' 的当前值", + "TypeError") # 3. 翻译 RHS 值 rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, aug.value, None, 0, self.Trans) if rhs_val is None: - VLogger.error("rhs is None", "AUGASGN") - return 0 + # fail-fast: RHS 翻译失败 + HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") # 4. 类型对齐 + 应用二元运算 # 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__) result: llvmlite.Value | t.CPtr = _apply_aug_op( pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target) if result is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "binop failed for op=%d", aug.op) - VLogger.error(fb, "AUGASGN") - return 0 + # fail-fast: 二元运算失败 + HandlesType.fatal_error( + target, + f"对变量 '{nm.id}' 应用二元运算失败 op={aug.op}", + "TypeError") # 5. 存储结果 result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) if result is None: - return 0 + # fail-fast: 类型对齐失败 + HandlesType.fatal_error(target, "类型对齐失败", "TypeError") if scope_type == 1: # global 变量 diff --git a/App/lib/core/Handles/HandlesBase.vp b/App/lib/core/Handles/HandlesBase.vp index 558c2de..1625ba4 100644 --- a/App/lib/core/Handles/HandlesBase.vp +++ b/App/lib/core/Handles/HandlesBase.vp @@ -147,7 +147,7 @@ def NewTypeRegistry(pool: memhub.MemBuddy | t.CPtr) -> TypeRegistry | t.CPtr: # Returns: # 写入的字符数(不含 NUL),失败返回 -1 # ============================================================ -def TypeToLLVM(buf: t.CChar | t.CPtr, buf_size: t.CSizeT, +def TypeToLLVM(buf: str, buf_size: t.CSizeT, ti: TypeInfo | t.CPtr) -> int: if buf is None: return -1 diff --git a/App/lib/core/Handles/HandlesClassDef.vp b/App/lib/core/Handles/HandlesClassDef.vp index 6531f1b..cdc934d 100644 --- a/App/lib/core/Handles/HandlesClassDef.vp +++ b/App/lib/core/Handles/HandlesClassDef.vp @@ -946,8 +946,8 @@ VTBL_METHOD_MAX: t.CDefine = 32 # _vtable_strcat — 将 src 追加到 dst 末尾 -def _vtable_strcat(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, - src: t.CChar | t.CPtr): +def _vtable_strcat(dst: str, dst_size: t.CSizeT, + src: str): """将 src 追加到 dst 末尾(委托到 gen._vtable_strcat)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) @@ -970,7 +970,7 @@ def _vtable_name_needs_quote(name: str) -> int: # 格式: ret_ty (param1_ty, param2_ty, ...) # 例如: void ({i32, i32}*, i32) def _format_func_type_str(pool: memhub.MemBuddy | t.CPtr, - buf: t.CChar | t.CPtr, buf_size: t.CSizeT, + buf: str, buf_size: t.CSizeT, func: llvmlite.Function | t.CPtr) -> int: """从 Function 对象生成函数类型字符串(委托到 gen._format_func_type_str)""" import lib.core.Gen.Generator as Generator @@ -1056,16 +1056,18 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr, cd: ast.ClassDef | t.CPtr, struct_ty: llvmlite.LLVMType | t.CPtr, class_name: str, - mark_only: int = 0) -> int: + mark_only: int = 0, + reemit: int = 0) -> int: """扫描 class body 中的方法并翻译,生成 __before_init__ mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) + reemit: 1=补译模式(泛型特化 Phase B 补译调用,强制发射方法体) (委托到 gen._translate_oop_methods) """ import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) if g is not None: - return g._translate_oop_methods(trans, cd, struct_ty, class_name, mark_only) + return g._translate_oop_methods(trans, cd, struct_ty, class_name, mark_only, reemit) return 0 diff --git a/App/lib/core/Handles/HandlesEnum.vp b/App/lib/core/Handles/HandlesEnum.vp index 1086d8b..2b4b978 100644 --- a/App/lib/core/Handles/HandlesEnum.vp +++ b/App/lib/core/Handles/HandlesEnum.vp @@ -35,7 +35,7 @@ ENUM_MEMBER_MAX: t.CDefine = 128 # ============================================================ @t.NoVTable class EnumMember: - Name: t.CChar | t.CPtr # 成员名(字符串) + Name: str # 成员名(字符串) Value: t.CInt64T # 成员的整数值 Ty: llvmlite.LLVMType | t.CPtr # 成员的 LLVM 类型(用于混用类型场景) @@ -45,7 +45,7 @@ class EnumMember: # ============================================================ @t.NoVTable class EnumEntry: - Name: t.CChar | t.CPtr # 枚举类名 + Name: str # 枚举类名 BaseTy: llvmlite.LLVMType | t.CPtr # 基准类型(所有成员类型中最大的) MemberCount: int # 成员数量 Members: EnumMember | t.CPtr # 成员数组(ENUM_MEMBER_MAX 个槽位) diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index 07ababe..595dfa3 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -76,7 +76,7 @@ def get_func_name(func_node: ast.AST | t.CPtr) -> str: # 转义 LLVM IR 字符串字面量 # ============================================================ def escape_llvm_string(pool: memhub.MemBuddy | t.CPtr, - src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + src: str) -> str: """将字符串转换为 LLVM IR 字符串字面量 c"...\\00"(委托到 gen.escape_llvm_string)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 5a6a37d..ef9ec3d 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -388,8 +388,8 @@ class AsmOperand: # ============================================================ # _asm_append_cstr — 将 C 字符串 src 追加到 dst 末尾 # ============================================================ -def _asm_append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, - src: t.CChar | t.CPtr): +def _asm_append_cstr(dst: str, dst_size: t.CSizeT, + src: str): """将 C 字符串 src 追加到 dst 末尾(委托到 gen._asm_append_cstr)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) @@ -402,7 +402,7 @@ def _asm_append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, # \n → \0A, " → \22, \ → \5C # ============================================================ def _asm_escape_for_ir(pool: memhub.MemBuddy | t.CPtr, - src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + src: str) -> str: """转义汇编文本用于 LLVM IR 字符串字面量(委托到 gen._asm_escape_for_ir)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) @@ -704,7 +704,7 @@ def _ensure_method_declare(pool: memhub.MemBuddy | t.CPtr, # _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型 # # 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc → -# "t.CChar | t.CPtr")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 +# "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 # 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。 # 无需硬编码白名单——返回类型始终来自方法定义处。 # ============================================================ @@ -1018,7 +1018,7 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, # 跳过 % 前缀后逐字符比较 # ============================================================ def _kwarg_name_matches(kw_arg: str, - param_name: t.CChar | t.CPtr) -> int: + param_name: str) -> int: """检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)(委托到 gen._kwarg_name_matches)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) @@ -1516,7 +1516,7 @@ class FuncEntry: # TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全) # 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后, # vtable 生成 find_func_global 读类型改用此文本,避免悬空。 - TypeStr: t.CChar | t.CPtr + TypeStr: str # ============================================================ # 初始化函数表 @@ -1587,7 +1587,7 @@ def _init_global_func_table() -> int: # 用 stdlib.malloc 分配返回,跨文件永久存活(1b reset 不回收)。 # 返回 None 表示失败。 def _build_func_type_str(pool: memhub.MemBuddy | t.CPtr, - func: llvmlite.Function | t.CPtr) -> t.CChar | t.CPtr: + func: llvmlite.Function | t.CPtr) -> str: """生成函数类型文本(stdlib 分配)(委托到 gen._build_func_type_str)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) diff --git a/App/lib/core/Handles/HandlesFor.vp b/App/lib/core/Handles/HandlesFor.vp index be269de..5be7e2d 100644 --- a/App/lib/core/Handles/HandlesFor.vp +++ b/App/lib/core/Handles/HandlesFor.vp @@ -123,7 +123,7 @@ class ForHandle(HandlesBase.Mixin): elif string.strcmp(fn_pre, "enumerate") == 0 or string.strcmp(fn_pre, "zip") == 0: pass # 多变量迭代,在下方非 range 分支处理 else: - err_msg: t.CChar | t.CPtr = pool.alloc(256) + err_msg: str = pool.alloc(256) if err_msg is not None: viperlib.snprintf(err_msg, 256, "仅支持 range()/enumerate()/zip() 或指针迭代,got call '%s'", fn_pre) HandlesType.fatal_error(iter_node, err_msg) @@ -215,28 +215,36 @@ class ForHandle(HandlesBase.Mixin): stop_val: llvmlite.Value | t.CPtr = None step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - if arg_count == 1: + if arg_count == 0: + # fail-fast: range 无参数,立即终止 + HandlesType.fatal_error(call, "range 需要至少一个参数", "SyntaxError") + elif arg_count == 1: stop_val = HandlesExpr.translate_value( builder, pool, trans.Module, args.get(0), trans._funcs, trans._func_count, trans) + if stop_val is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") elif arg_count >= 2: start_val = HandlesExpr.translate_value( builder, pool, trans.Module, args.get(0), trans._funcs, trans._func_count, trans) + if start_val is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") stop_val = HandlesExpr.translate_value( builder, pool, trans.Module, args.get(1), trans._funcs, trans._func_count, trans) + if stop_val is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(args.get(1), "range 参数翻译失败", "TypeError") if arg_count >= 3: step_val = HandlesExpr.translate_value( builder, pool, trans.Module, args.get(2), trans._funcs, trans._func_count, trans) - - if stop_val is None: - stop_val = llvmlite.const_int32(pool, 0) - if start_val is None: - start_val = llvmlite.const_int32(pool, 0) - if step_val is None: - step_val = llvmlite.const_int32(pool, 1) + if step_val is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(args.get(2), "range 参数翻译失败", "TypeError") # 4. 创建/查找循环变量 alloca var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( @@ -274,7 +282,7 @@ class ForHandle(HandlesBase.Mixin): cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt) cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) @@ -436,7 +444,7 @@ class ForHandle(HandlesBase.Mixin): cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt) cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) @@ -571,7 +579,7 @@ class ForHandle(HandlesBase.Mixin): cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt) cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) @@ -759,7 +767,7 @@ class ForHandle(HandlesBase.Mixin): cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "lst.cond.%d", cnt) cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) @@ -870,7 +878,7 @@ class ForHandle(HandlesBase.Mixin): cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "dict.cond.%d", cnt) cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) @@ -1009,7 +1017,8 @@ class ForHandle(HandlesBase.Mixin): call: ast.Call | t.CPtr) -> int: """zip 迭代: for a, b in zip(x, y)""" if call is None or call.args is None: - return 0 + # fail-fast: zip 参数缺失 + HandlesType.fatal_error(call, "zip 参数缺失", "SyntaxError") cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args if len(cargs) < 2: HandlesType.fatal_error(for_node, "zip 需要至少两个参数") @@ -1061,20 +1070,26 @@ class ForHandle(HandlesBase.Mixin): sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, trans.Module, cargs1.get(0), trans._funcs, trans._func_count, trans) - if sv is not None: - r1_stop = HandlesExpr.coerce_to_type(builder, sv, i64_ty, cargs1.get(0)) + if sv is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError") + r1_stop = HandlesExpr.coerce_to_type(builder, sv, i64_ty, cargs1.get(0)) if n1 >= 2: sv2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, trans.Module, cargs1.get(1), trans._funcs, trans._func_count, trans) - if sv2 is not None: - r1_start = HandlesExpr.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1)) + if sv2 is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError") + r1_start = HandlesExpr.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1)) if n1 >= 3: sv3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, trans.Module, cargs1.get(2), trans._funcs, trans._func_count, trans) - if sv3 is not None: - r1_step = HandlesExpr.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2)) + if sv3 is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError") + r1_step = HandlesExpr.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2)) elif kind1 == SEQ_KIND_STR: elem1_ty = i8_ty s1_ptr = HandlesExpr.translate_value( @@ -1125,20 +1140,26 @@ class ForHandle(HandlesBase.Mixin): svz: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, trans.Module, cargs2.get(0), trans._funcs, trans._func_count, trans) - if svz is not None: - r2_stop = HandlesExpr.coerce_to_type(builder, svz, i64_ty, cargs2.get(0)) + if svz is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError") + r2_stop = HandlesExpr.coerce_to_type(builder, svz, i64_ty, cargs2.get(0)) if n2 >= 2: svz2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, trans.Module, cargs2.get(1), trans._funcs, trans._func_count, trans) - if svz2 is not None: - r2_start = HandlesExpr.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1)) + if svz2 is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError") + r2_start = HandlesExpr.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1)) if n2 >= 3: svz3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, trans.Module, cargs2.get(2), trans._funcs, trans._func_count, trans) - if svz3 is not None: - r2_step = HandlesExpr.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2)) + if svz3 is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError") + r2_step = HandlesExpr.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2)) elif kind2 == SEQ_KIND_STR: elem2_ty = i8_ty s2_ptr = HandlesExpr.translate_value( @@ -1189,7 +1210,7 @@ class ForHandle(HandlesBase.Mixin): cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "seq.cond.%d", cnt) cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) diff --git a/App/lib/core/Handles/HandlesFunctions.vp b/App/lib/core/Handles/HandlesFunctions.vp index cfddff8..ecbd981 100644 --- a/App/lib/core/Handles/HandlesFunctions.vp +++ b/App/lib/core/Handles/HandlesFunctions.vp @@ -57,7 +57,7 @@ SCOPE_FUNCTION: t.CDefine = 1 def extract_func_attrs(pool: memhub.MemBuddy | t.CPtr, decorator_list: list[ast.AST | t.CPtr] | t.CPtr, - imported_modules: str) -> t.CChar | t.CPtr: + imported_modules: str) -> str: """从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串(委托到 gen.extract_func_attrs)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) @@ -75,7 +75,7 @@ def _get_attr_name_from_node(node: ast.AST | t.CPtr) -> str: return None -def _append_llvm_attr(attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int: +def _append_llvm_attr(attrs_buf: str, attr_name: str) -> int: """将属性名映射到 LLVM 属性名并追加到缓冲区(委托到 gen._append_llvm_attr)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) @@ -84,7 +84,7 @@ def _append_llvm_attr(attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int: return 0 -def _append_str(buf: t.CChar | t.CPtr, s: str) -> None: +def _append_str(buf: str, s: str) -> None: """将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat)(委托到 gen._append_str)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) diff --git a/App/lib/core/Handles/HandlesIf.vp b/App/lib/core/Handles/HandlesIf.vp index 1267d0c..dbd66fd 100644 --- a/App/lib/core/Handles/HandlesIf.vp +++ b/App/lib/core/Handles/HandlesIf.vp @@ -245,7 +245,8 @@ class IfHandle(HandlesBase.Mixin): # 2. 转换为 i1 条件 # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 if cond_val is None: - cond_val = llvmlite.const_int32(pool, 0) + # fail-fast: if 条件表达式翻译失败 + HandlesType.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError") cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) if cond_bits == 1: cond_i1: llvmlite.Value | t.CPtr = cond_val @@ -263,7 +264,7 @@ class IfHandle(HandlesBase.Mixin): cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "if.then.%d", cnt) then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) diff --git a/App/lib/core/Handles/HandlesImports.vp b/App/lib/core/Handles/HandlesImports.vp index fd705d8..43f0f1c 100644 --- a/App/lib/core/Handles/HandlesImports.vp +++ b/App/lib/core/Handles/HandlesImports.vp @@ -19,7 +19,7 @@ import lib.core.StubMerger as StubMerger # HandlesImports - 导入语句处理(P6-D 对象化后的委托层) # # 管理 _imported_modules 和 _from_imports 字符串 -# 注意:str = bytes = t.CChar | t.CPtr = i8* +# 注意:str = bytes = str = i8* # # P6-D 对象化重构(wiki/14-oo-refactor.md): # 全部模块级函数已迁移为 lib.core.Gen.ImportsGenMixin 的方法 diff --git a/App/lib/core/Handles/HandlesMain.vp b/App/lib/core/Handles/HandlesMain.vp index 9d5a142..1583b74 100644 --- a/App/lib/core/Handles/HandlesMain.vp +++ b/App/lib/core/Handles/HandlesMain.vp @@ -26,7 +26,7 @@ import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign # 2. translate_children() - 遍历 AST 子节点并分派翻译 # # trans 单参模式:所有共享状态从 trans 获取,无需 11 个参数 -# 注意: str = bytes = t.CChar | t.CPtr = i8* +# 注意: str = bytes = str = i8* # # P6-E 对象化重构:全部函数已迁移为 lib.core.Gen.TranslatorGenMixin # 的方法,本模块保留同名模块级函数作为"一行委托"(同 P2-P5 模式): diff --git a/App/lib/core/Handles/HandlesMatch.vp b/App/lib/core/Handles/HandlesMatch.vp index 66213e5..bb4200b 100644 --- a/App/lib/core/Handles/HandlesMatch.vp +++ b/App/lib/core/Handles/HandlesMatch.vp @@ -12,6 +12,7 @@ import lib.core.Handles.HandlesBody as HandlesBody import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesClassDef as HandlesClassDef import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesType as HandlesType # ============================================================ @@ -89,7 +90,8 @@ class MatchHandle(HandlesBase.Mixin): builder, pool, trans.Module, subject_node, trans._funcs, trans._func_count, trans) if subject_val is None: - return 0 + # fail-fast: match subject 翻译失败 + HandlesType.fatal_error(subject_node, "match subject 翻译失败", "TypeError") # 2. 检测是否 REnum match is_renum: int = 0 @@ -274,8 +276,11 @@ class MatchHandle(HandlesBase.Mixin): if renum_se is not None: renum_sty = renum_se.Ty if renum_sty is None: - # 找不到结构体类型时无法构造,直接放弃 REnum 路径 - return 0 + # fail-fast: REnum 结构体未注册,无法构造 + HandlesType.fatal_error( + node, + f"REnum 结构体 '{renum_name}' 未注册", + "NameError") i64_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) int_val: llvmlite.Value | t.CPtr = subject_ptr # 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽) @@ -298,18 +303,21 @@ class MatchHandle(HandlesBase.Mixin): tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( builder, subject_ptr, i32_ptr_ty) if tag_ptr is None: - return 0 + # fail-fast: REnum tag 指针转换失败 + HandlesType.fatal_error(node, "REnum tag 指针转换失败", "TypeError") tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, i32_ty, tag_ptr) if tag_val is None: - return 0 + # fail-fast: REnum tag 读取失败 + HandlesType.fatal_error(node, "REnum tag 读取失败", "TypeError") # 2. 创建 default/end BB cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) if name_buf is None: - return 0 + # fail-fast: 标签缓冲区分配失败 + HandlesType.fatal_error(node, "标签缓冲区分配失败", "TypeError") viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( pool, func, name_buf) @@ -320,7 +328,8 @@ class MatchHandle(HandlesBase.Mixin): # 3. 准备收集数组(用 CSizeT 数组存指针) cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases if cases_list is None: - return 0 + # fail-fast: match cases 缺失 + HandlesType.fatal_error(node, "match cases 缺失", "TypeError") case_count: t.CSizeT = len(cases_list) # BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组 @@ -329,7 +338,8 @@ class MatchHandle(HandlesBase.Mixin): def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: - return 0 + # fail-fast: match 分派数组分配失败 + HandlesType.fatal_error(node, "match 分派数组分配失败", "TypeError") collected: int = 0 has_default: int = 0 @@ -363,7 +373,7 @@ class MatchHandle(HandlesBase.Mixin): tag: int = HandlesClassDef._lookup_renum_variant_in_class( renum_name, vnm) if tag >= 0: - tag_buf: t.CChar | t.CPtr = pool.alloc(32) + tag_buf: str = pool.alloc(32) if tag_buf is not None: viperlib.snprintf(tag_buf, 32, "%d", tag) cv = llvmlite.ConstInt(pool, i32_ty, tag, @@ -574,8 +584,11 @@ class MatchHandle(HandlesBase.Mixin): if alt_idx >= 1: payload_idx = alt_idx else: - j = j + 1 - continue + # fail-fast: payload 越界且别名查找失败 + HandlesType.fatal_error( + node, + f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", + "TypeError") # 获取字段类型 fe: HandlesStruct.FieldEntry | t.CPtr = ( HandlesStruct._get_field_entry( @@ -584,15 +597,24 @@ class MatchHandle(HandlesBase.Mixin): if fe is not None: field_ty = fe.Ty if field_ty is None: - field_ty = llvmlite.Int8(pool) + # fail-fast: 变体字段类型缺失,禁止兜底 i8 + HandlesType.fatal_error( + sub_pat, + f"REnum 变体字段类型缺失: {bind_name}", + "TypeError") # GEP 取字段地址 elem_ptr: llvmlite.Value | t.CPtr = ( llvmlite.build_gep_struct( builder, renum_ty, field_ty, casted_ptr, payload_idx)) - if elem_ptr is not None: - HandlesVar.define_var( - trans.SymTab, bind_name, elem_ptr) + if elem_ptr is None: + # fail-fast: 变体字段地址计算失败 + HandlesType.fatal_error( + sub_pat, + f"REnum 变体字段 '{bind_name}' 地址计算失败", + "TypeError") + HandlesVar.define_var( + trans.SymTab, bind_name, elem_ptr) j = j + 1 # ============================================================ @@ -621,14 +643,16 @@ class MatchHandle(HandlesBase.Mixin): # 未知类型,尝试 ptrtoint subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) if subj_val is None: - return 0 + # fail-fast: subject 转 i32 失败 + HandlesType.fatal_error(node, "match subject 转换为 i32 失败", "TypeError") # 2. 创建 default/end BB cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) if name_buf is None: - return 0 + # fail-fast: 标签缓冲区分配失败 + HandlesType.fatal_error(node, "标签缓冲区分配失败", "TypeError") viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( pool, func, name_buf) @@ -639,7 +663,8 @@ class MatchHandle(HandlesBase.Mixin): # 3. 收集 case 信息 cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases if cases_list is None: - return 0 + # fail-fast: match cases 缺失 + HandlesType.fatal_error(node, "match cases 缺失", "TypeError") case_count: t.CSizeT = len(cases_list) bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) @@ -647,7 +672,8 @@ class MatchHandle(HandlesBase.Mixin): def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: - return 0 + # fail-fast: match 分派数组分配失败 + HandlesType.fatal_error(node, "match 分派数组分配失败", "TypeError") collected: int = 0 has_default: int = 0 diff --git a/App/lib/core/Handles/HandlesReturn.vp b/App/lib/core/Handles/HandlesReturn.vp index 33af9df..cbd8750 100644 --- a/App/lib/core/Handles/HandlesReturn.vp +++ b/App/lib/core/Handles/HandlesReturn.vp @@ -8,6 +8,7 @@ import lib.core.Handles.HandlesBase as HandlesBase import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType # ============================================================ @@ -175,7 +176,13 @@ class ReturnHandle(HandlesBase.Mixin): zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0) llvmlite.build_ret(builder, zero_f) return 0 - val = llvmlite.const_int32(pool, 0) + if ret_ty is None: + # fail-fast: 裸 return 无法确定函数返回类型,禁止硬编码 i32 零值兜底 + HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError") + val = llvmlite.ConstZero(pool, ret_ty) + if val is None: + # fail-fast: 无法按返回类型构造零值 + HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError") # 类型转换:确保 val 类型与函数返回类型匹配 # 处理 i1(bool 比较结果)→ i8(t.CBool)等情况 diff --git a/App/lib/core/Handles/HandlesStruct.vp b/App/lib/core/Handles/HandlesStruct.vp index ca452eb..154e31e 100644 --- a/App/lib/core/Handles/HandlesStruct.vp +++ b/App/lib/core/Handles/HandlesStruct.vp @@ -41,11 +41,11 @@ MRO_MAX: t.CDefine = 16 # ============================================================ @t.NoVTable class FieldEntry: - Name: t.CChar | t.CPtr # 字段名(字符串) + Name: str # 字段名(字符串) Index: int # 字段在结构体中的索引 Ty: llvmlite.LLVMType | t.CPtr # 字段的 LLVM 类型 DefaultVal: ast.AST | t.CPtr # 默认值 AST 节点(None=无默认值) - AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) + AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) # ============================================================ @@ -53,7 +53,7 @@ class FieldEntry: # ============================================================ @t.NoVTable class StructEntry: - Name: t.CChar | t.CPtr # 类名 + Name: str # 类名 Ty: llvmlite.LLVMType | t.CPtr # LLVM StructType FieldCount: int # 字段数量 Fields: FieldEntry | t.CPtr # 字段数组(FIELD_MAX 个槽位) @@ -63,12 +63,12 @@ class StructEntry: HasNew: int # 1=有__new__方法 / 0=无 HasVTable: int # 1=有虚表 / 0=无虚表 IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记 - ParentName: t.CChar | t.CPtr # 父类名(None=无父类,多继承时为第一个父类,兼容旧调用) + ParentName: str # 父类名(None=无父类,多继承时为第一个父类,兼容旧调用) ParentNames: t.CSizeT | t.CPtr # 多继承父类名数组(每元素 str 指针,ParentCount 个;stdlib 深拷贝) ParentCount: t.CInt # 父类数量(0=无父类,1=单继承,>1=多继承) VTableMethodCount: int # 虚表中的方法数量 - VTableMethods: t.CChar | t.CPtr # 虚表方法名数组(每个方法名 str,VTableMethodCount 个) - ModuleSha1: t.CChar | t.CPtr # 定义该类的模块 SHA1(None=无 SHA1) + VTableMethods: str # 虚表方法名数组(每个方法名 str,VTableMethodCount 个) + ModuleSha1: str # 定义该类的模块 SHA1(None=无 SHA1) MethodsEmitted: int # 1=方法体已翻译 / 0=未译(Phase 1a mark_only 未译,Phase B 据此补译) @@ -200,7 +200,7 @@ def add_field(pool: memhub.MemBuddy | t.CPtr, field_name: str, field_ty: llvmlite.LLVMType | t.CPtr, default_val: ast.AST | t.CPtr = None, - annot_class_name: t.CChar | t.CPtr = None) -> int: + annot_class_name: str = None) -> int: """向结构体添加字段,返回字段索引(-1 失败,委托到 gen.add_field)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) @@ -496,7 +496,7 @@ def get_parent_name(name: str) -> str: return None -def set_vtable_methods(name: str, methods: t.CChar | t.CPtr, count: int) -> int: +def set_vtable_methods(name: str, methods: str, count: int) -> int: """设置虚表方法名数组,返回 1=成功 / 0=失败(委托到 gen.set_vtable_methods)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) diff --git a/App/lib/core/Handles/HandlesTranslator.vp b/App/lib/core/Handles/HandlesTranslator.vp index e51085c..9a2a480 100644 --- a/App/lib/core/Handles/HandlesTranslator.vp +++ b/App/lib/core/Handles/HandlesTranslator.vp @@ -94,6 +94,14 @@ class Translator: # i8* Deref 固定读 1 字节 + sext 截断)。 CurAssignAnnot: ast.AST | t.CPtr + # 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。 + # 供 c.Deref 判定"是否为赋值直接 RHS":仅 v: int = c.Deref(p) 时用 + # CurAssignAnnot 推断读取宽度;嵌套在 while 条件/比较/binop/类型转换 + # 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p)))不推断, + # 否则 i8* 会被残留 CurAssignAnnot 误判为 i32* 读 4 字节(对齐 TPC + # _infer_deref_target_type 的直接 RHS 检查)。 + CurAssignNode: ast.AST | t.CPtr + # 循环控制流目标(break/continue) _break_bb: llvmlite.BasicBlock | t.CPtr _continue_bb: llvmlite.BasicBlock | t.CPtr diff --git a/App/lib/core/Handles/HandlesType.vp b/App/lib/core/Handles/HandlesType.vp index d73cee7..572ef74 100644 --- a/App/lib/core/Handles/HandlesType.vp +++ b/App/lib/core/Handles/HandlesType.vp @@ -573,7 +573,7 @@ def build_param_types_str(pool: memhub.MemBuddy | t.CPtr, return None -def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): +def _strappend(dst: str, dst_size: t.CSizeT, src: str): """将 src 追加到 dst 末尾(委托到 gen._strappend)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) diff --git a/App/lib/core/Handles/HandlesVar.vp b/App/lib/core/Handles/HandlesVar.vp index 5155962..ee3d6dc 100644 --- a/App/lib/core/Handles/HandlesVar.vp +++ b/App/lib/core/Handles/HandlesVar.vp @@ -40,10 +40,10 @@ MAX_VARS: t.CDefine = 256 @t.NoVTable class VarEntry: """变量表条目""" - Name: t.CChar | t.CPtr + Name: str Alloca: llvmlite.Value | t.CPtr Used: t.CInt - AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) + AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) IsPtrElement: t.CInt # 标志: 1=注解为 bytes|t.CPtr 或 str|t.CPtr, 下标按 8 字节步长 diff --git a/App/lib/core/Handles/HandlesWhile.vp b/App/lib/core/Handles/HandlesWhile.vp index 3515811..5c9da60 100644 --- a/App/lib/core/Handles/HandlesWhile.vp +++ b/App/lib/core/Handles/HandlesWhile.vp @@ -10,6 +10,7 @@ import lib.core.Handles.HandlesBase as HandlesBase import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesBody as HandlesBody +import lib.core.Handles.HandlesType as HandlesType # ============================================================ @@ -77,7 +78,7 @@ class WhileHandle(HandlesBase.Mixin): cnt: int = trans._label_counter trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) + name_buf: str = pool.alloc(32) viperlib.snprintf(name_buf, 32, "while.cond.%d", cnt) cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) @@ -96,7 +97,8 @@ class WhileHandle(HandlesBase.Mixin): builder, pool, trans.Module, while_node.test, trans._funcs, trans._func_count, trans) if cond_val is None: - cond_val = llvmlite.const_int32(pool, 0) + # fail-fast: while 条件表达式翻译失败 + HandlesType.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError") # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) diff --git a/App/lib/core/IncludesScanner.vp b/App/lib/core/IncludesScanner.vp index ef4651a..c405765 100644 --- a/App/lib/core/IncludesScanner.vp +++ b/App/lib/core/IncludesScanner.vp @@ -210,6 +210,8 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr, """递归扫描目录,收集 .vp/.py 文件(inc_dir 为所属 includes 根目录)""" if pool is None or root_dir is None or result is None: return 1 + # 子目录递归失败计数(不静默忽略,汇总处 fail-fast 终止) + subdir_failed: int = 0 # 构造搜索模式: root_dir/* root_len: t.CSizeT = string.strlen(root_dir) @@ -275,7 +277,8 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr, if is_dir != 0: # 递归扫描子目录 - scan_directory_recursive(pool, full_path, rel_path, result, inc_dir) + if scan_directory_recursive(pool, full_path, rel_path, result, inc_dir) != 0: + subdir_failed += 1 else: # 检查是否为 .vp 或 .py 文件(.vp 为 Viper 源,.py 向后兼容) is_py: int = 0 @@ -294,16 +297,26 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr, sha1: str = compute_file_sha1(pool, full_path) if sha1 is not None: add_file_entry(result, pool, full_path, rel_path, sha1, inc_dir) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "扫描: %s -> %s", rel_path, sha1) VLogger.debug(fb, "scan") + else: + fb_sha: str = VLogger.fmt_buf() + if fb_sha is not None: + viperlib.snprintf(fb_sha, 1024, "SHA1 计算失败: %s", full_path) + VLogger.warning(fb_sha, "scan") # 继续搜索下一个文件 if win32file.FindNextFileA(handle, find_data) == 0: break win32file.FindClose(handle) + if subdir_failed > 0: + fb_sdf: str = VLogger.fmt_buf() + if fb_sdf is not None: + viperlib.snprintf(fb_sdf, 1024, "子目录扫描失败 %d 个", subdir_failed) + VLogger.error(fb_sdf, "scan") return 0 @@ -338,7 +351,7 @@ def scan_includes(pool: memhub.MemBuddy | t.CPtr, continue dir_buf: bytes = stdlib.malloc(d_len + 1) if dir_buf is None: - continue + VLogger.error("includes 目录分配失败,终止扫描", "scan") string.strncpy(dir_buf, includes_dirs + d_start, d_len) dir_buf[d_len] = '\0' scan_directory_recursive(pool, dir_buf, None, result, dir_buf) diff --git a/App/lib/core/Phase1.vp b/App/lib/core/Phase1.vp index 337e021..5e3c61a 100644 --- a/App/lib/core/Phase1.vp +++ b/App/lib/core/Phase1.vp @@ -496,7 +496,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, log: VLogger.Logger | t.CPtr) -> int: """Phase1: 扫描 includes 目录,按需翻译并生成 stub""" if includes_dir is None or temp_dir is None: - VLogger.warning("includes_dir 或 temp_dir 为空,跳过", "Phase1") + VLogger.error("includes_dir 或 temp_dir 为空,无法运行 Phase1", "Phase1") return 1 # 设置全局 temp_dir(供跨模块 CDefine 查找使用) @@ -666,6 +666,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, stdlib.free(src_buf_a) + if p1a_failed > 0: + fb_p1apre: str = VLogger.fmt_buf() + if fb_p1apre is not None: + viperlib.snprintf(fb_p1apre, 1024, "Phase 1a-pre 有 %d 个文件扫描失败", p1a_failed) + VLogger.error(fb_p1apre, "Phase1") + return 1 + # ============================================================ # 依赖图按需翻译:构建可达 SHA1 集合 # @@ -682,6 +689,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, if reachable_set is not None: string.memset(reachable_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) reachable_count = StubMerger._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set) + if reachable_count < 0: + VLogger.error("可达集合构建失败,终止", "Phase1") + return 1 if reachable_count > 0: use_reachable = 1 # 用可达集合重新生成 _sha1_map.txt(按图求索的最终产物) @@ -691,6 +701,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) set_count = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set) else: + VLogger.warning("可达集合为空,回退全量扫描", "Phase1") stdlib.free(reachable_set) reachable_set = None @@ -750,15 +761,15 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, tc_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(topo_count_box, t.CPtr)) if tc_ptr is not None: topo_count = tc_ptr[0] - fb_topo: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_topo: str = VLogger.fmt_buf() if fb_topo is not None: viperlib.snprintf(fb_topo, 1024, "拓扑排序: %d 个类, %d 个文件按依赖顺序处理", class_count_scanned, topo_count) VLogger.info(fb_topo, "Phase1") else: - VLogger.warning("拓扑排序失败,回退到字母序", "Phase1") - topo_count = 0 + VLogger.error("拓扑排序失败(类继承依赖无法解析),终止编译", "Phase1") + return 1 else: VLogger.warning("类继承预扫描无结果,回退到字母序", "Phase1") topo_count = 0 @@ -777,7 +788,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, generic_file_count = gfc_box_ptr[0] if generic_file_count > 0 and generic_file_indices is not None: - fb_gpre: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_gpre: str = VLogger.fmt_buf() if fb_gpre is not None: viperlib.snprintf(fb_gpre, 1024, "预注册 %d 个泛型类模板文件", generic_file_count) VLogger.info(fb_gpre, "Phase1") @@ -946,6 +957,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, stdlib.free(tr_r._nonlocal_names) stdlib.free(src_buf_r) + if p1a_fl > 0: + fb_p1ar: str = VLogger.fmt_buf() + if fb_p1ar is not None: + viperlib.snprintf(fb_p1ar, 1024, "Phase 1a 有 %d 个文件 struct 注册失败", p1a_fl) + VLogger.error(fb_p1ar, "Phase1") + return 1 + # 释放拓扑排序资源 if class_names_buf is not None: mb.free(class_names_buf) @@ -984,11 +1002,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # 返回类型推断错误(如 HashTable.__getitem__ 被推断为 Ptr(HashTable) # 而 define 返回 i8*)→ 运行时返回值截断崩溃。 # ============================================================ + p1bpre_failed: int = 0 dir_len_pv: t.CSizeT = string.strlen(temp_dir) for i_pv in range(result.Count): entry_addr_pv: t.CUInt64T = t.CUInt64T(result.Entries) + i_pv * entry_size entry_pv: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pv, t.CPtr)) if entry_pv is None or entry_pv.Sha1 is None: + p1bpre_failed += 1 continue sha1_pv: str = entry_pv.Sha1 in_set_pv: int = 0 @@ -1001,6 +1021,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # vpi 已存在则跳过 vpi_path_pv: str = StubMerger._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi") if vpi_path_pv is None: + p1bpre_failed += 1 continue vf_pv: fileio.File | t.CPtr = fileio.File(vpi_path_pv, fileio.MODE.R) if not vf_pv.closed: @@ -1012,15 +1033,18 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, file_path_pv: str = entry_pv.Path f_pv: fileio.File | t.CPtr = fileio.File(file_path_pv, fileio.MODE.R) if f_pv.closed: + p1bpre_failed += 1 continue src_buf_pv: bytes = stdlib.malloc(SRC_BUF_SIZE) if src_buf_pv is None: f_pv.close() + p1bpre_failed += 1 continue bytes_read_pv: LONG = f_pv.read_all(src_buf_pv, SRC_BUF_SIZE) f_pv.close() if bytes_read_pv <= 0: stdlib.free(src_buf_pv) + p1bpre_failed += 1 continue if bytes_read_pv < SRC_BUF_SIZE: src_buf_pv[bytes_read_pv] = 0 @@ -1029,12 +1053,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, lx_pv: ast.Lexer | t.CPtr = ast.new_lexer(mb) if lx_pv is None: stdlib.free(src_buf_pv) + p1bpre_failed += 1 continue ast._lexer_init(lx_pv, src_buf_pv, mb) tokens_pv: ast.Token | t.CPtr = ast.tokenize(lx_pv) tree_pv: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_pv) if tree_pv is None: stdlib.free(src_buf_pv) + p1bpre_failed += 1 continue pyi_buf_pv: bytes = stdlib.malloc(PYI_BUF_SIZE) if pyi_buf_pv is not None: @@ -1048,8 +1074,17 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, pf_pv.close() stdlib.free(pyi_path_pv) stdlib.free(pyi_buf_pv) + else: + p1bpre_failed += 1 stdlib.free(src_buf_pv) + if p1bpre_failed > 0: + fb_p1bpre: str = VLogger.fmt_buf() + if fb_p1bpre is not None: + viperlib.snprintf(fb_p1bpre, 1024, "Phase 1b-pre 有 %d 个文件 vpi 预生成失败", p1bpre_failed) + VLogger.error(fb_p1bpre, "Phase1") + return 1 + # 遍历每个文件 translated: int = 0 skipped: int = 0 @@ -1102,14 +1137,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, stdlib.free(text_path) # text.ll 不存在,需要重新翻译 rp: str = entry.RelPath - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "text.ll 不存在,重新翻译: %s (sha1=%s)", rp, sha1) VLogger.info(fb, "Phase1") else: # stub 不存在,需要翻译 rp: str = entry.RelPath - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "翻译: %s (sha1=%s)", rp, sha1) VLogger.info(fb, "Phase1") @@ -1120,14 +1155,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, file_path: str = entry.Path f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) if f is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "无法打开(None): %s", file_path) VLogger.error(fb, "Phase1") failed += 1 continue if f.closed: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "无法打开: %s", file_path) VLogger.error(fb, "Phase1") @@ -1143,7 +1178,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE) f.close() if bytes_read <= 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "读取失败: %s", file_path) VLogger.error(fb, "Phase1") @@ -1165,7 +1200,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, tokens: ast.Token | t.CPtr = ast.tokenize(lx) tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) if tree is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "AST 解析失败: %s", file_path) VLogger.error(fb, "Phase1") @@ -1207,7 +1242,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # (崩溃点漂移排查:把"翻译过程中随机崩"变成确定性定位) pre_rc: t.CInt = mb.check_alive_blocks(mark1) if pre_rc != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "内存损坏(翻译前存活块, rc=%d): %s", pre_rc, file_path) @@ -1218,12 +1253,12 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # 诊断:translate 正常返回(若挂起在 translate 内部,此行不会打印, # 用于区分"translate 内部挂起"与"后续 dump 挂起") if ret == 0: - fb_done: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_done: str = VLogger.fmt_buf() if fb_done is not None: viperlib.snprintf(fb_done, 1024, "翻译完成(translate返回): %s", file_path) VLogger.info(fb_done, "Phase1") if ret != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "翻译失败: %s", file_path) VLogger.error(fb, "Phase1") @@ -1318,7 +1353,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # rc 语义(self_check):1/2=越界,3=对齐错,4=free list 成环/超步数 chk_rc: t.CInt = mb.check_alive_blocks(mark1) if chk_rc != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "内存损坏(存活块 header, rc=%d): %s", chk_rc, file_path) @@ -1330,18 +1365,25 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, mb.reset_to(mark1) sc_rc: t.CInt = mb.self_check() if sc_rc != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "内存损坏(free list, rc=%d): %s", sc_rc, file_path) VLogger.error(fb, "Phase1") stdlib.exit(1) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "完成: 翻译=%d 跳过=%d 失败=%d", translated, skipped, failed) VLogger.info(fb, "Phase1") + if failed > 0: + fb_fail: str = VLogger.fmt_buf() + if fb_fail is not None: + viperlib.snprintf(fb_fail, 1024, "Phase1 有 %d 个文件翻译失败", failed) + VLogger.error(fb_fail, "Phase1") + return 1 + # 释放可达 SHA1 集合(如果分配了) if reachable_set is not None: stdlib.free(reachable_set) diff --git a/App/lib/core/Phase2.vp b/App/lib/core/Phase2.vp index d491b96..3e0dd37 100644 --- a/App/lib/core/Phase2.vp +++ b/App/lib/core/Phase2.vp @@ -149,7 +149,7 @@ def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr, ent.Path = full_path ent.Sha1 = sha1_val file_count += 1 - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "%s (sha1=%s)", fname, sha1_val) VLogger.info(fb, "project") @@ -186,7 +186,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, global _g_canary _g_canary = 305419896 - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "多文件项目编译: %s", source_dir) VLogger.info(fb, "project") @@ -199,7 +199,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, string.memset(entries, 0, MAX_SRC_FILES * entry_size) file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "共 %d 个源文件", file_count) VLogger.info(fb, "project") @@ -221,9 +221,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, if includes_dir is not None: if StubMerger.GetSha1StoreCount() == 0: inc_scan_result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir) + if inc_scan_result is None: + VLogger.error("includes 扫描失败,无法填充 Sha1Store", "project") if inc_scan_result is not None: inc_filled: int = StubMerger.PopulateSha1MapStore(inc_scan_result) - fb_inc: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_inc: str = VLogger.fmt_buf() if fb_inc is not None: viperlib.snprintf(fb_inc, 1024, "Phase2 自主填充 includes Sha1Store: %d 个", inc_filled) VLogger.info(fb_inc, "project") @@ -254,8 +256,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, rel_path_am = p_str + src_dir_len_am + 1 # 同步追加到内存存储器(供跨模块 CDefine 查找) # rel_path_am 格式如 "lib/core/StubMerger.vp",与 _sha1_map.txt 一致 - if StubMerger.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) == 0: - app_filled += 1 + if StubMerger.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) != 0: + fb_apf: str = VLogger.fmt_buf() + if fb_apf is not None: + viperlib.snprintf(fb_apf, 1024, "AppendToSha1MapStore 失败: %s", rel_path_am) + VLogger.error(fb_apf, "project") + app_filled += 1 # 写入 _sha1_map.txt(人类可读输出) if not mf.closed and line_am is not None: viperlib.snprintf(line_am, 512, "%s:%s\n", ent_am.Sha1, rel_path_am) @@ -265,7 +271,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, stdlib.free(line_am) if not mf.closed: mf.close() - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "已追加 %d 个 App 文件到 _sha1_map.txt 和内存存储器", app_filled) VLogger.info(fb, "project") @@ -368,7 +374,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, for si_inc_f in range(store_count_inc_pre): if inc_fail_flags[si_inc_f] != 0: rel_f: str = store_rel_inc_pre + t.CSizeT(si_inc_f) * StubMerger.MAX_REL_PATH_LEN - fb_inc_f: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_inc_f: str = VLogger.fmt_buf() if fb_inc_f is not None: viperlib.snprintf(fb_inc_f, 1024, "includes 预注册失败: %s(文件无法翻译,可能是语法/解析/编译错误),终止编译", @@ -376,7 +382,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, VLogger.error(fb_inc_f, "prePhaseA") sys.exit(1) stdlib.free(inc_fail_flags) - fb_inc_pre: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_inc_pre: str = VLogger.fmt_buf() if fb_inc_pre is not None: viperlib.snprintf(fb_inc_pre, 1024, "includes 预注册 + 依赖填充: %d/%d", deps_filled_pre, store_count_inc_pre) VLogger.info(fb_inc_pre, "prePhaseA") @@ -402,10 +408,10 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, pkg_pre = HandlesImports.compute_package_from_relpath(mb, rel_path_pre) tr_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1) if tr_pre is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "预注册失败: %s", ent_pre.Path) - VLogger.warning(fb, "PhaseA") + VLogger.error(fb, "PhaseA") struct_count_after: int = HandlesStruct.get_struct_count() # 收敛检查:本遍没有新结构体注册 → 所有类已注册 if struct_count_after == struct_count_before: @@ -473,7 +479,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, app_deps_buf[app_deps_len] = '\0' if tr_a._deps_pending != 0: # 依赖模块 text.ll 未生成(同项目文件顺序),不写盘,下遍重试 - fb_dp: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_dp: str = VLogger.fmt_buf() if fb_dp is not None: viperlib.snprintf(fb_dp, 1024, "Phase A 依赖未就绪,下遍重试: %s", ent.Path) @@ -483,7 +489,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, # dump stub IR (declarations only) stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE) if stub_buf_a is None: - continue + VLogger.error("stub 缓冲区分配失败", "PhaseA") tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB) stub_len_a: t.CSizeT = string.strlen(stub_buf_a) @@ -500,7 +506,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, # dump text IR (definitions only) text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE) if text_buf_a is None: - continue + VLogger.error("text 缓冲区分配失败", "PhaseA") tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT) text_len_a: t.CSizeT = string.strlen(text_buf_a) @@ -542,7 +548,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, ea_err: t.CUInt64T = t.CUInt64T(entries) + i_err * entry_size ent_err: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_err, t.CPtr)) if ent_err is not None and ent_err.Path is not None: - fb_err: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_err: str = VLogger.fmt_buf() if fb_err is not None: viperlib.snprintf(fb_err, 1024, "Phase A 无法完成翻译: %s(请检查依赖模块是否已编译/注册)", ent_err.Path) @@ -594,14 +600,14 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, # 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE) if combined_ir is None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "combined_ir 分配失败: %s", ent.Path) VLogger.error(fb, "PhaseB") continue combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE) if combined_len == 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", ent.Path) VLogger.error(fb, "PhaseB") @@ -614,7 +620,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, cc_cmd, cc_flags) stdlib.free(combined_ir) if cret != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", ent.Path) VLogger.error(fb, "PhaseB") @@ -622,7 +628,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, compiled_count += 1 # 显示编译完成的文件 - fb_comp: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_comp: str = VLogger.fmt_buf() if fb_comp is not None: viperlib.snprintf(fb_comp, 1024, "[%d/%d] 编译完成: %s", i + 1, file_count, ent.Path) VLogger.info(fb_comp, "PhaseB") @@ -643,7 +649,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, if op_sliced_len < 512: string.strcpy(main_obj_path, obj_path_sliced) else: - VLogger.warning("main_obj_path 缓冲区不足", "PhaseB") + VLogger.error("main_obj_path 缓冲区不足,终止编译", "PhaseB") else: # 其他模块: 追加到 obj_paths if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE: @@ -654,9 +660,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, obj_pos += op_sliced_len obj_paths[obj_pos] = '\0' else: - VLogger.warning(".obj 路径缓冲区不足", "PhaseB") + VLogger.error(".obj 路径缓冲区不足", "PhaseB") stdlib.free(obj_path_sliced) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "编译完成: %d/%d", compiled_count, file_count) VLogger.success(fb, "PhaseB") @@ -674,7 +680,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, td_len_mi: t.CSizeT = string.strlen(temp_dir) # 诊断日志:确认 Phase B+ 入口和 Sha1Store 状态 - fb_pbp_enter: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_pbp_enter: str = VLogger.fmt_buf() if fb_pbp_enter is not None: viperlib.snprintf(fb_pbp_enter, 1024, "PhaseB+ 入口: store_count=%d includes_binary_dir=%s", @@ -697,7 +703,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, string.memset(reachable_set, 0, REACHABLE_SET_SIZE) reachable_count = StubMerger._BuildReachableSha1Set( mb, source_dir, temp_dir, reachable_set, app_deps_buf) - fb_reach: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_reach: str = VLogger.fmt_buf() if fb_reach is not None: viperlib.snprintf(fb_reach, 1024, "可达 includes SHA1: %d 个", reachable_count) VLogger.info(fb_reach, "PhaseB+") @@ -760,7 +766,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, stdlib.free(check_pat_mi) if check_fd_mi is not None: stdlib.free(check_fd_mi) - continue + VLogger.error("includes 源路径分配失败,终止编译", "PhaseB+") viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1, "%s/%s", incdir_mi, inc_rel_mi) @@ -874,7 +880,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, diag_text_ex = 1 df_diag_t.close() stdlib.free(diag_text) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s (stub=%d text=%d is_decl=%d)", @@ -895,7 +901,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, stdlib.free(inc_combined_mi) if inc_cret_mi != 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", src_fp_mi) VLogger.error(fb, "PhaseB+") @@ -903,7 +909,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, inc_compiled += 1 # 显示编译完成的 includes 文件 - fb_inc_comp: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_inc_comp: str = VLogger.fmt_buf() if fb_inc_comp is not None: viperlib.snprintf(fb_inc_comp, 1024, "[includes %d] 编译完成: %s", inc_compiled, src_fp_mi) VLogger.info(fb_inc_comp, "PhaseB+") @@ -921,6 +927,8 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, string.strcpy(obj_paths + obj_pos, inc_obj_sliced) obj_pos += inc_obj_len obj_paths[obj_pos] = '\0' + else: + VLogger.error("includes .obj 路径缓冲区溢出,终止编译", "PhaseB+") stdlib.free(inc_obj_sliced) # 释放本次迭代的临时内存 @@ -932,7 +940,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, stdlib.free(src_fp_mi) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "编译缺失 includes: %d 个", inc_compiled) VLogger.info(fb, "PhaseB+") @@ -953,6 +961,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, viperlib.snprintf(exe_path, od_len2 + lo_len + 2, "%s/%s", output_dir, linker_output) else: exe_path = linker_output + VLogger.error("exe_path 分配失败,终止编译", "PhaseC") # 构造最终 .obj 路径列表:main_obj_path 在前,reachable .obj 在后 final_obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE + 512) @@ -991,6 +1000,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, string.strcpy(final_obj_paths + fop_pos, obj_path_pc) fop_pos += op_len_pc final_obj_paths[fop_pos] = '\0' + else: + fb_pc: str = VLogger.fmt_buf() + if fb_pc is not None: + viperlib.snprintf(fb_pc, 1024, "可达模块 .obj 缺失: %s", obj_path_pc) + VLogger.error(fb_pc, "PhaseC") stdlib.free(obj_path_pc) final_obj_paths[fop_pos] = '\0' @@ -1008,18 +1022,18 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, None) if lret == 0: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "输出: %s", exe_path) VLogger.success(fb, "PhaseC") if args.get_bool("run"): - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "执行: %s", exe_path) VLogger.info(fb, "run") rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False) if rp is not None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "退出码: %d", rp.returncode) VLogger.info(fb, "run") diff --git a/App/lib/core/StubMerger.vp b/App/lib/core/StubMerger.vp index 9a1e44a..41a1c9a 100644 --- a/App/lib/core/StubMerger.vp +++ b/App/lib/core/StubMerger.vp @@ -281,7 +281,7 @@ def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int: # ============================================================ def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str, scan_result: IncludesScanner.ScanResult | t.CPtr, - filter_set: t.CChar | t.CPtr, + filter_set: str, filter_count: int) -> int: """将 includes 扫描结果写入 _sha1_map.txt(人类可读输出,程序内部使用内存存储器) @@ -371,18 +371,21 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in string.memset(_sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN) string.memset(_sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN) _sha1_store_count = 0 + p_bad: int = 0 entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() for i in range(scan_result.Count): if _sha1_store_count >= MAX_INCLUDES: - break + VLogger.error("includes SHA1 存储超上限,终止", "StubMerger") ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) if ent is None or ent.Sha1 is None or ent.RelPath is None: + p_bad += 1 continue # 构建完整路径 includes/{RelPath}(_PathToModuleName 需要) rp_len: t.CSizeT = string.strlen(ent.RelPath) full_path_buf: bytes = stdlib.malloc(rp_len + 10) if full_path_buf is None: + p_bad += 1 continue viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath) mod_name: str = Utils.PathToModuleName(full_path_buf, 1) @@ -415,6 +418,11 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in string.strncpy(_sha1_store_incdir + idx_inc, ent.IncDir, MAX_INC_DIR_LEN - 1) _sha1_store_incdir[idx_inc + MAX_INC_DIR_LEN - 1] = '\0' _sha1_store_count += 1 + if p_bad > 0: + fb_pbad: str = VLogger.fmt_buf() + if fb_pbad is not None: + viperlib.snprintf(fb_pbad, 1024, "includes SHA1 存储有 %d 个条目失败", p_bad) + VLogger.error(fb_pbad, "StubMerger") return _sha1_store_count @@ -948,11 +956,23 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, df_ls: fileio.File | t.CPtr = fileio.File(dep_path, fileio.MODE.R) if df_ls.closed: stdlib.free(dep_path) + # 依赖 stub 缺失:includes 映射内的模块缺失属编译错误(fail-fast), + # 非映射模块(如 t/c 内部库、用户文件)按设计跳过 + if LookupSha1RelPath(dep_sha1) is not None: + fb_ls: str = VLogger.fmt_buf() + if fb_ls is not None: + viperlib.snprintf(fb_ls, 1024, "依赖 stub 缺失: %s", dep_sha1) + VLogger.error(fb_ls, "StubMerger") return out_pos dep_br_ls: t.CInt64T = df_ls.read_all(dep_buf, STUB_READ_BUF_SIZE) df_ls.close() stdlib.free(dep_path) if dep_br_ls <= 0: + if LookupSha1RelPath(dep_sha1) is not None: + fb_ls2: str = VLogger.fmt_buf() + if fb_ls2 is not None: + viperlib.snprintf(fb_ls2, 1024, "依赖 stub 为空: %s", dep_sha1) + VLogger.error(fb_ls2, "StubMerger") return out_pos if dep_br_ls < STUB_READ_BUF_SIZE: dep_buf[dep_br_ls] = '\0' @@ -1106,11 +1126,23 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, tf_lt: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) if tf_lt.closed: stdlib.free(text_path) + # 依赖 text 缺失:includes 映射内的模块缺失属编译错误(fail-fast), + # 非映射模块(如 t/c 内部库、用户文件)按设计跳过 + if LookupSha1RelPath(dep_sha1) is not None: + fb_lt: str = VLogger.fmt_buf() + if fb_lt is not None: + viperlib.snprintf(fb_lt, 1024, "依赖 text 缺失: %s", dep_sha1) + VLogger.error(fb_lt, "StubMerger") return out_pos text_br: t.CInt64T = tf_lt.read_all(dep_buf, STUB_READ_BUF_SIZE) tf_lt.close() stdlib.free(text_path) if text_br <= 0: + if LookupSha1RelPath(dep_sha1) is not None: + fb_lt2: str = VLogger.fmt_buf() + if fb_lt2 is not None: + viperlib.snprintf(fb_lt2, 1024, "依赖 text 为空: %s", dep_sha1) + VLogger.error(fb_lt2, "StubMerger") return out_pos if text_br < STUB_READ_BUF_SIZE: dep_buf[text_br] = '\0' @@ -1302,8 +1334,8 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, # 所有内存由 stdlib.malloc 分配,调用者负责释放。 # ============================================================ def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT, - sha1_list: t.CChar | t.CPtr, - mod_list: t.CChar | t.CPtr) -> int: + sha1_list: str, + mod_list: str) -> int: """从全局内存存储器复制 sha1→module_name 映射到调用者数组 temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。 @@ -1340,7 +1372,7 @@ def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT, # Returns: # SHA1 字符串指针(指向 sha1_arr 内部,无需释放),未找到返回 None # ============================================================ -def _FindSha1ByModName(sha1_arr: t.CChar | t.CPtr, mod_arr: t.CChar | t.CPtr, +def _FindSha1ByModName(sha1_arr: str, mod_arr: str, count: int, mod_name: str) -> str: """从模块名查找 SHA1(精确匹配 + 包名回退) @@ -1385,7 +1417,7 @@ def _FindSha1ByModName(sha1_arr: t.CChar | t.CPtr, mod_arr: t.CChar | t.CPtr, # Returns: # 新的 count(如果已存在则不变) # ============================================================ -def _AddSha1ToSet(set_buf: t.CChar | t.CPtr, count: int, sha1: str) -> int: +def _AddSha1ToSet(set_buf: str, count: int, sha1: str) -> int: """将 SHA1 加入集合,返回新 count""" if set_buf is None or sha1 is None: return count @@ -1423,7 +1455,7 @@ def _AddSha1ToSet(set_buf: t.CChar | t.CPtr, count: int, sha1: str) -> int: # ============================================================ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, temp_dir: str, - reachable_set: t.CChar | t.CPtr, + reachable_set: str, app_deps: str = None) -> int: """构建可达 SHA1 集合(依赖图按需翻译) @@ -1450,7 +1482,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, stdlib.free(sha1_arr) stdlib.free(mod_arr) return -1 - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "SHA1 映射: %d 个", map_count) VLogger.debug(fb, "Reachable") @@ -1473,7 +1505,12 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, if ad_len > 0 and ad_len < 8192: string.strcpy(worklist, app_deps) wl_len = ad_len + else: + VLogger.error("app_deps 过长,无法构建可达集合", "StubMerger") else: + # app_deps 缺失:Phase1 场景(未翻译 App 源文件)为设计性回退, + # 显式 warning 暴露回退,不再静默 + VLogger.warning("app_deps 缺失,回退非递归扫描 source_dir", "Reachable") # 回退到自己的非递归扫描 dir_len: t.CSizeT = string.strlen(source_dir) pattern: bytes = stdlib.malloc(dir_len + 8) @@ -1496,7 +1533,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data) if handle == win32base.INVALID_HANDLE_VALUE: - fb_fd: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_fd: str = VLogger.fmt_buf() if fb_fd is not None: viperlib.snprintf(fb_fd, 1024, "未找到源文件(.vp/.py): %s", pattern) VLogger.warning(fb_fd, "Reachable") @@ -1573,7 +1610,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, worklist[wl_len - 1] = '\0' wl_len -= 1 - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "源文件直接依赖: '%s'", worklist) VLogger.debug(fb, "Reachable") @@ -1636,7 +1673,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, worklist[wl_len] = ' ' wl_len += 1 worklist[wl_len] = '\0' - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "预加入容器模块后: '%s'", worklist) VLogger.debug(fb, "Reachable") @@ -1685,6 +1722,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, processed[proc_len] = ' ' proc_len = proc_len + 1 processed[proc_len] = '\0' + else: + VLogger.error("依赖 worklist 溢出", "StubMerger") # 查找 SHA1 found_sha1: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, mod_buf) @@ -1707,6 +1746,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, worklist[wl_len] = ' ' wl_len = wl_len + 1 worklist[wl_len] = '\0' + else: + VLogger.error("依赖 worklist 溢出", "StubMerger") # deps_str 为空字符串视为无依赖(合法情况,如叶子模块) else: # 依赖未在内存中找到 @@ -1733,7 +1774,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, stdlib.free(app_mod_path) if is_app_src == 0: # fast-fail: includes 文件依赖未在内存中找到,Phase 1a-pre 未正确填充 - fb_ff: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_ff: str = VLogger.fmt_buf() if fb_ff is not None: viperlib.snprintf(fb_ff, 1024, "依赖未找到 fast-fail: 模块 %s (sha1=%s) 的依赖未在内存中注册", mod_buf, found_sha1) VLogger.error(fb_ff, "Reachable") @@ -1749,7 +1790,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, stdlib.free(worklist) stdlib.free(processed) - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "可达 SHA1: %d 个", reachable_count) VLogger.debug(fb, "Reachable") @@ -1856,6 +1897,10 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, df_deps.close() stdlib.free(deps_path) + # deps.txt 缺失但存在 includes 映射:依赖无法按需过滤,fail-fast 终止 + if deps_loaded == 0 and inc_count > 0: + VLogger.error("依赖文件 deps.txt 缺失,无法合并 includes stub", "StubMerger") + # 2c. 递归扫描 temp_dir 中所有 .stub.ll,按需加载 all_sha1_arr: str = stdlib.malloc(MAX_INCLUDES_SHA1 * 17) all_count: int = 0 @@ -1946,7 +1991,7 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, if chk_path is not None: chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R) if chk_f.closed: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译", mod_nm, found_s, chk_path) VLogger.error(fb, "BuildCombinedIR") @@ -1960,8 +2005,12 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, return out_pos tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) if tf.closed: + # 本地 text.ll 缺失:合并 IR 无法生成定义块,fail-fast 终止 + fb_tlp: str = VLogger.fmt_buf() + if fb_tlp is not None: + viperlib.snprintf(fb_tlp, 1024, "本地 text.ll 缺失: %s", text_path) + VLogger.error(fb_tlp, "StubMerger") stdlib.free(text_path) - # text.ll 不存在的情况,继续 else: text_content: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) if text_content is None: diff --git a/App/lib/core/VLogger.vp b/App/lib/core/VLogger.vp index 316115c..43078b3 100644 --- a/App/lib/core/VLogger.vp +++ b/App/lib/core/VLogger.vp @@ -194,14 +194,14 @@ _mbuddy: memhub.MemBuddy | t.CPtr _g_logger: Logger | t.CPtr # 全局格式化缓冲区(用于带变量的日志消息,1024 字节) -_fmt_buf: t.CChar | t.CPtr +_fmt_buf: str -def fmt_buf() -> t.CChar | t.CPtr: +def fmt_buf() -> str: """获取全局格式化缓冲区(1024 字节)。 用法: - buf: t.CChar | t.CPtr = VLogger.fmt_buf() + buf: str = VLogger.fmt_buf() if buf is not None: viperlib.snprintf(buf, 1024, "翻译: %s (sha1=%s)", rp, sha1) log.info(buf, "Phase1") diff --git a/App/main.vp b/App/main.vp index 5bb9175..c3d5491 100644 --- a/App/main.vp +++ b/App/main.vp @@ -249,7 +249,7 @@ def main() -> int: if mf_inc_bin_asan is not None: n_asan: int = Utils.CleanDir(mf_inc_bin_asan) if log is not None: - fb_asan: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_asan: str = VLogger.fmt_buf() if fb_asan is not None: viperlib.snprintf(fb_asan, 1024, "ASan 模式清理 includes 缓存: %d 个文件(将重建 asan obj)", n_asan) log.info(fb_asan, "asan") @@ -308,14 +308,14 @@ def main() -> int: if Config.TempDir is not None: n: int = Utils.CleanDir(Config.TempDir) if log is not None: - fb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb: str = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "%s: 删除 %d 个文件", Config.TempDir, n) log.info(fb, "clean") if Config.OutputDir is not None: n2: int = Utils.CleanDir(Config.OutputDir) if log is not None: - fb2: t.CChar | t.CPtr = VLogger.fmt_buf() + fb2: str = VLogger.fmt_buf() if fb2 is not None: viperlib.snprintf(fb2, 1024, "%s: 删除 %d 个文件", Config.OutputDir, n2) log.info(fb2, "clean") @@ -324,7 +324,7 @@ def main() -> int: if mf_inc_bin_clean is not None: n3: int = Utils.CleanDir(mf_inc_bin_clean) if log is not None: - fb3: t.CChar | t.CPtr = VLogger.fmt_buf() + fb3: str = VLogger.fmt_buf() if fb3 is not None: viperlib.snprintf(fb3, 1024, "%s: 删除 %d 个文件", mf_inc_bin_clean, n3) log.info(fb3, "clean") @@ -338,7 +338,7 @@ def main() -> int: if mf_inc_bin_rb is not None: n_rb: int = Utils.CleanDir(mf_inc_bin_rb) if log is not None: - fb_rb: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_rb: str = VLogger.fmt_buf() if fb_rb is not None: viperlib.snprintf(fb_rb, 1024, "%s: 删除 %d 个文件(includes 将重新编译)", mf_inc_bin_rb, n_rb) log.info(fb_rb, "rebuild-includes") @@ -351,7 +351,7 @@ def main() -> int: if Config.TempDir is not None: n_cc: int = Utils.CleanDir(Config.TempDir) if log is not None: - fb_cc: t.CChar | t.CPtr = VLogger.fmt_buf() + fb_cc: str = VLogger.fmt_buf() if fb_cc is not None: viperlib.snprintf(fb_cc, 1024, "%s: 删除 %d 个文件(.vpi/.stub.ll 缓存)", Config.TempDir, n_cc) log.info(fb_cc, "clear-cache") @@ -371,7 +371,7 @@ def main() -> int: if string.strcmp(phase_mode, "2") == 0 or string.strcmp(phase_mode, "all") == 0: do_phase2 = 1 if log is not None: - fb3: t.CChar | t.CPtr = VLogger.fmt_buf() + fb3: str = VLogger.fmt_buf() if fb3 is not None: viperlib.snprintf(fb3, 1024, "模式: %s (phase1=%d phase2=%d)", phase_mode, do_phase1, do_phase2) log.info(fb3, "phase") @@ -382,7 +382,9 @@ def main() -> int: ph1_temp: str = Config.TempDir if ph1_temp is None: ph1_temp = "." - Phase1.RunPhase1(mb, Config.IncludesDirs, ph1_temp, log) + if Phase1.RunPhase1(mb, Config.IncludesDirs, ph1_temp, log) != 0: + VLogger.error("Phase1 失败,终止编译", "Phase1") + return 1 # 如果仅 Phase1(不执行 Phase2),直接退出 if do_phase2 == 0: if log is not None: @@ -440,7 +442,7 @@ def main() -> int: ef.close() src_path = path_buf if log is not None: - fb4: t.CChar | t.CPtr = VLogger.fmt_buf() + fb4: str = VLogger.fmt_buf() if fb4 is not None: viperlib.snprintf(fb4, 1024, "入口文件: %s", src_path) log.info(fb4, "project") @@ -451,7 +453,7 @@ def main() -> int: f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R) if f.closed: if log is not None: - fb5: t.CChar | t.CPtr = VLogger.fmt_buf() + fb5: str = VLogger.fmt_buf() if fb5 is not None: viperlib.snprintf(fb5, 1024, "无法打开文件: %s", src_path) log.error(fb5, "fileio") @@ -470,7 +472,7 @@ def main() -> int: f.close() if bytes_read < 0: if log is not None: - fb6: t.CChar | t.CPtr = VLogger.fmt_buf() + fb6: str = VLogger.fmt_buf() if fb6 is not None: viperlib.snprintf(fb6, 1024, "读取文件失败 (错误码: %d)", bytes_read) log.error(fb6, "fileio") @@ -483,7 +485,7 @@ def main() -> int: src_buf[SRC_BUF_SIZE - 1] = 0 if log is not None: log.info("文件读取完成", "fileio") - fb7: t.CChar | t.CPtr = VLogger.fmt_buf() + fb7: str = VLogger.fmt_buf() if fb7 is not None: viperlib.snprintf(fb7, 1024, "读取 %d 字节", bytes_read) log.info(fb7, "fileio") @@ -518,7 +520,7 @@ def main() -> int: # output_name 从文件名推导(如 test.vp -> test.exe),保持可读性 module_name: str = Utils.compute_sha1(mb, src_buf) if module_name is None: - module_name = "main" + VLogger.error("SHA1 计算失败", "main") output_name: str = "test_prog.exe" # 从文件名提取 output_name(去掉路径和 .vp/.py 扩展名) src_len: t.CSizeT = string.strlen(src_path) @@ -632,9 +634,8 @@ def main() -> int: final_ir = combined_buf final_ir_len = combined_len else: - if log is not None: - log.warning("BuildCombinedIR 失败,使用原始 IR", "stub") stdlib.free(combined_buf) + VLogger.error("BuildCombinedIR 失败,终止编译", "stub") br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline( final_ir, final_ir_len, temp_dir, output_dir, module_name, @@ -644,7 +645,7 @@ def main() -> int: if br is not None and br.Success == 1: if log is not None: log.success("编译管线完成") - fb8: t.CChar | t.CPtr = VLogger.fmt_buf() + fb8: str = VLogger.fmt_buf() if fb8 is not None: viperlib.snprintf(fb8, 1024, "输出: %s/%s", output_dir, linker_output) log.info(fb8) @@ -654,14 +655,14 @@ def main() -> int: if exe_path is not None: viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output) if log is not None: - fb9: t.CChar | t.CPtr = VLogger.fmt_buf() + fb9: str = VLogger.fmt_buf() if fb9 is not None: viperlib.snprintf(fb9, 1024, "执行: %s", exe_path) log.info(fb9, "run") r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False) if r is not None: if log is not None: - fb10: t.CChar | t.CPtr = VLogger.fmt_buf() + fb10: str = VLogger.fmt_buf() if fb10 is not None: viperlib.snprintf(fb10, 1024, "退出码: %d", r.returncode) log.info(fb10, "run") @@ -669,7 +670,7 @@ def main() -> int: if log is not None: log.error("编译管线失败", "pipeline") if br is not None and br.ErrorMsg is not None: - fb11: t.CChar | t.CPtr = VLogger.fmt_buf() + fb11: str = VLogger.fmt_buf() if fb11 is not None: viperlib.snprintf(fb11, 1024, "编译管线失败: %s", br.ErrorMsg) log.error(fb11, "FATAL")