import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator import lib.core.Gen.Expr.ExprGenCls as ExprGenCls import lib.core.Gen.Expr.ExprGenName as ExprGenName import t, c from stdint import * import ast import llvmlite import memhub import string import stdlib import sys import viperlib import w32.fileio as fileio import lib.core.VLogger as VLogger import lib.core.Gen.Translator as HT import lib.core.Gen.Type.TypeSpec as TSpec import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory from . import CallGenBase import lib.core.Gen.GenApi as GenApi # ============================================================ # CallGenDispatch - CallGenMixin 拆分(阶段 C):translate_call 检测段 # ============================================================ novirtual class CallGenDispatch(CallGenBase.CallGenBase): """translate_call 前置检测 helper(继承 Base)""" def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*, mod: llvmlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: t.CPtr = None) -> llvmlite.Value*: """super()/ctraits 编译期检测(未命中返回 None) hit_box: 命中标志字节([0]=1 表示被本 helper 拦截处理)。 super().method() 命中后 _translate_super_call 对 void 方法(如 __init__)经 build_call 返回 None 属预期(void call 无 SSA 值), 必须用 hit_box 与"未命中"区分,否则 translate_call 会误判继续 主路径 → 把内层 Call(super) 当裸名调用报"super 未定义"。 """ # super() 语义(2026-08-10):super().method(args) → 静态调用父类方法 # 形态: Call(func=Attribute(value=Call(func=Name('super')), attr=method)) # 必须在 Attribute 分派前拦截——否则 value 的 Call(super) 被 translate_value # 当作普通函数调用报错,且走普通属性调用会命中自身/虚分派而非父类实现。 if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: sup_at: ast.Attribute* = ast.Attribute*(cl.func) if sup_at.value is not None and sup_at.value.kind() == ast.ASTKind.Call: sup_cl: ast.Call* = ast.Call*(sup_at.value) if sup_cl.func is not None and sup_cl.func.kind() == ast.ASTKind.Name: sup_nm: ast.Name* = ast.Name*(sup_cl.func) if sup_nm.id is not None and string.strcmp(sup_nm.id, "super") == 0: if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_super_call(pool, builder, mod, cl, func_name, trans) # ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用, # 直接按变量存储类型返回编译期常量(CIf 求值失败回退或非 CIf 上下文时兜底, # 避免生成跨模块调用 ctraits.isptr 触发"模块未注册 SHA1"误导性报错) if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: ct_at: ast.Attribute* = ast.Attribute*(cl.func) if ct_at.value is not None and ct_at.value.kind() == ast.ASTKind.Name: ct_nm: ast.Name* = ast.Name*(ct_at.value) if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 and string.strcmp(func_name, "isptr") == 0: ct_args: list[ast.AST*]* = cl.args if ct_args is not None and len(ct_args) >= 1: ct_arg0: ast.AST* = ct_args.get(0) if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name: ct_nm0: ast.Name* = ast.Name*(ct_arg0) if ct_nm0.id is not None and trans is not None: ct_r: int = self.Gen.StmtGenCif._eval_ctraits_isptr(trans.SymTab, ct_nm0.id) if ct_r > 0: return llvmlite.const_int32(pool, 1) return llvmlite.const_int32(pool, 0) return None def _tc_h2_c_special(self, pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*, mod: llvmlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: t.CPtr = None) -> llvmlite.Value*: """c.Deref/Asm/LLVMIR 等特殊调用(未命中返回 None) hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为 c.* 特殊调用)。 仅对 c.Asm/c.LLVMIR 等返回 None(void,无返回值)的调用置位—— translate_c_asm/translate_c_llvmir 成功处理 void 时返回 None, 若不加 hit_box 会被 translate_call 误判为"未命中"继续走外部函数路径。 """ # __asm__(...) / __llvmir__(...) 语法糖:裸名调用等价 c.Asm(...) / c.LLVMIR(...) # (无 c. 前缀,无需 import c)。必须在 c.* Attribute 分支之前拦截: # 裸名 cl.func 是 Name 而非 Attribute。 if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: bare_nm: ast.Name* = ast.Name*(cl.func) if bare_nm.id is not None and string.strcmp(bare_nm.id, "__asm__") == 0: # 无输出(void)时 translate_c_asm 返回 None:置命中标记, # 避免 translate_call 误判未命中继续走外部函数路径。 if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCBuiltin.translate_c_asm(pool, builder, mod, cl, trans) if bare_nm.id is not None and string.strcmp(bare_nm.id, "__llvmir__") == 0: # c.LLVMIR 总是无返回值(返回 None):置命中标记 if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCBuiltin.translate_c_llvmir(pool, builder, mod, cl, trans) if bare_nm.id is not None and (string.strcmp(bare_nm.id, "irinp") == 0 or string.strcmp(bare_nm.id, "irout") == 0): # irinp/irout 独立调用时返回 0(仅在 __llvmir__ 的 f-string 内有意义) return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) # 及 coro.* 协程库拦截(coro.coro_run 内联翻译,TPV-M1) if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: at_node: ast.Attribute* = ast.Attribute*(cl.func) if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name: mod_nm: ast.Name* = ast.Name*(at_node.value) is_coro_mod: int = 0 if mod_nm.id is not None and string.strcmp(mod_nm.id, "coro") == 0: is_coro_mod = 1 if mod_nm.id is not None and (string.strcmp(mod_nm.id, "c") == 0 or is_coro_mod != 0): if string.strcmp(func_name, "Deref") == 0: return self.Gen.CallGenCBuiltin.translate_c_deref(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "DerefAs") == 0: return self.Gen.CallGenCBuiltin.translate_c_derefas(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Addr") == 0: return self.Gen.CallGenCBuiltin.translate_c_addr(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Set") == 0: # c.Set(a, b) = a = b(赋值语义,非指针解引用)。 # 若当普通函数调用会生成 @Set 引用导致链接失败(undefined reference to `Set')。 return self.Gen.CallGenCBuiltin.translate_c_set(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Load") == 0: return self.Gen.CallGenCBuiltin.translate_c_load(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Asm") == 0: # c.Asm 无输出(void)时 translate_c_asm 返回 None: # 置命中标记,避免 translate_call 误判未命中继续走外部函数 if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCBuiltin.translate_c_asm(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "LLVMIR") == 0: # c.LLVMIR 总是无返回值(返回 None):置命中标记 if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCBuiltin.translate_c_llvmir(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0: # c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义) return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") elif string.strcmp(func_name, "CIf") == 0: # 运行时 c.CIf(expr)(编译期求值失败回退):expr 与 0 比较得到 i1 # 对齐 TPC HandlesExprCall.py L2434-2444 cif_args: list[ast.AST*]* = cl.args if cif_args is not None and len(cif_args) >= 1: cif_arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cif_args.get(0), funcs_ptr, func_count, trans) if cif_arg_val is not None: cif_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cif_arg_val.Ty) if cif_bits == 1: return cif_arg_val if self.Gen.ExprGenBase.is_ptr_type(cif_arg_val.Ty) != 0: cif_null: llvmlite.Value* = llvmlite.ConstNull(pool, cif_arg_val.Ty, "null") return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cif_arg_val, cif_null) cif_zero: llvmlite.Value* = llvmlite.const_int32(pool, 0) return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cif_arg_val, cif_zero) return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "0") elif string.strcmp(func_name, "CIfdef") == 0 or string.strcmp(func_name, "CIfndef") == 0: # 运行时 c.CIfdef/c.CIfndef(编译期求值失败回退):恒真 # 对齐 TPC HandlesExprCall.py L2445-2446 return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 1, "1") elif is_coro_mod != 0 and string.strcmp(func_name, "coro_run") == 0: # coro.coro_run(帧):内联翻译(resume 循环到 done,返回帧 ret 槽) # 对齐 TPC HandlesAsyncFunctions._HandleCoroRunLlvm # 注意:coro.* 系列 translate_coro_* 签名统一是 # (builder, pool, mod, cl, trans),与本文件其它 c.* 分支的 # (pool, builder, ...) 顺序不同,勿混用。 return self.Gen.AsyncGen.translate_coro_run(builder, pool, mod, cl, trans) elif is_coro_mod != 0 and string.strcmp(func_name, "coro_destroy") == 0: # coro.coro_destroy(帧):帧回池(M7 free-list) return self.Gen.AsyncGen.translate_coro_destroy(builder, pool, mod, cl, trans) elif is_coro_mod != 0 and string.strcmp(func_name, "coro_exception") == 0: # coro.coro_exception(帧):返回帧 exc 槽(M4) return self.Gen.AsyncGen.translate_coro_exception(builder, pool, mod, cl, trans) elif is_coro_mod != 0 and string.strcmp(func_name, "coro_exception_msg") == 0: # coro.coro_exception_msg(帧):返回帧 msg 槽(M7) return self.Gen.AsyncGen.translate_coro_exception_msg(builder, pool, mod, cl, trans) elif is_coro_mod != 0 and string.strcmp(func_name, "coro_gather") == 0: # coro.coro_gather(帧...):并发推进全部协程(M4) return self.Gen.AsyncGen.translate_coro_gather(builder, pool, mod, cl, trans) return None def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*, mod: llvmlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> llvmlite.Value*: """stdarg 糖 + str/int/bool 内置强转(未命中返回 None)""" # stdarg 糖函数处理: va_arg / arg / va_start / va_end # 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理: # va_arg(ap, type) → %N = va_arg , (LLVM 指令) # va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32) # arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr) # va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic) # va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic) # ============================================================ if func_name is not None and trans is not None: if string.strcmp(func_name, "va_arg") == 0: return self.Gen.CallGenVa._translate_va_arg_sugar(pool, builder, mod, cl, cargs, can, funcs_ptr, func_count, trans) elif string.strcmp(func_name, "arg") == 0: return self.Gen.CallGenVa._translate_arg_sugar(pool, builder, mod, cl, cargs, can, funcs_ptr, func_count, trans) elif string.strcmp(func_name, "va_start") == 0: return self.Gen.CallGenVa._translate_va_start_sugar(pool, builder, mod, cargs, can, funcs_ptr, func_count, trans) elif string.strcmp(func_name, "va_end") == 0: return self.Gen.CallGenVa._translate_va_end_sugar(pool, builder, mod, cargs, can, funcs_ptr, func_count, trans) # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 # 等价于 (str)(x) / (int32)(x) # 单参数:str(val) → bitcast val to i8* # int(val) → trunc/sext val to i32 # 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名 # (如 "int")再按内建强转处理(Box[int].__init__ 的 self.value = T(v)、 # combine[T1,T2] 的 T1(b) 依赖此路径) if func_name is not None and can == 1: cast_fn_name: str = self.Gen.TypeGenBase.resolve_generic_type_name(func_name) if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0: # str(x) / bytes(x) → i8* (bitcast) cast_arg: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if cast_arg is not None: i8_ptr_ty_builtin: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin) return None elif string.strcmp(cast_fn_name, "int") == 0: # int(x) → i32 cast_arg_int: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if cast_arg_int is not None: i32_ty_builtin: llvmlite.LLVMType* = llvmlite.Int32(pool) return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin) return None elif string.strcmp(cast_fn_name, "bool") == 0: # bool(x) → i1(严格 != 0 归一化) # 整数: icmp ne x, 0 → i1 # 浮点: fcmp one x, 0.0 → i1 # 指针: icmp ne x, null → i1 cast_arg_bool: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if cast_arg_bool is not None: arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cast_arg_bool.Ty) arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(cast_arg_bool.Ty) # 整数: icmp ne x, 0 if arg_bits != 0: zero_int: llvmlite.Value* = llvmlite.const_int(pool, arg_bits, 0) if zero_int is not None: return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int) return None # 浮点: fcmp one x, 0.0 if arg_fbits != 0: zero_ty: llvmlite.LLVMType* = cast_arg_bool.Ty zero_flt: llvmlite.Value* = llvmlite.ConstFloat(pool, zero_ty, 0.0) if zero_flt is not None: return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt) return None # 指针: icmp ne x, null ptr_null: llvmlite.Value* = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null") if ptr_null is not None: return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null) return None return None return None def _tc_h4_type_casts(self, pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*, mod: llvmlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> llvmlite.Value*: """t.XXX / typedef 类型转换(未命中返回 None)""" # 检测 t.XXX 类型转换: uint64(ptr), t.CPtr(val), int(val) 等 # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) # 支持: # 单参数: int(val) → 目标类型 = map_t_type(func_name) # 双参数: int(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: tc_at: ast.Attribute* = ast.Attribute*(cl.func) if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: tc_mod_nm: ast.Name* = ast.Name*(tc_at.value) if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: # t.CType 特殊形式:t.CType(value, TypeName, t.CPtr) → # 把 value 转为 TypeName|t.CPtr(TypeName* 指针)。TypeName # 是类型名(Name/Attribute),不是值表达式——此前被当普通 # 参数翻译 → NameError: 未定义名称 'memory_block' # (VKernel mm.vp merge_blocks 根因)。CType 不是 map_t_type # 的具名类型,须在此显式处理,否则跌落到跨模块 FATAL。 if string.strcmp(func_name, "CType") == 0 and can >= 2: cty_node: ast.AST* = cargs.get(1) ctype_target: llvmlite.LLVMType* = None if cty_node is not None: cti_imp: str = None cti_fi: str = None if trans is not None: cti_imp = trans._imported_modules cti_fi = trans._from_imports ctype_target = self.Gen.TypeGenResolve.resolve_annotation_type(pool, cty_node, cti_imp, cti_fi, trans, 0) if ctype_target is not None: if can == 3: cty_arg3: ast.AST* = cargs.get(2) cty_is_cptr: int = 0 if cty_arg3 is not None: # 形式 1: t.CPtr(Attribute) if cty_arg3.kind() == ast.ASTKind.Attribute: cty_at3: ast.Attribute* = ast.Attribute*(cty_arg3) if cty_at3.attr is not None and string.strcmp(cty_at3.attr, "CPtr") == 0: if cty_at3.value is not None and cty_at3.value.kind() == ast.ASTKind.Name: cty_nm3: ast.Name* = ast.Name*(cty_at3.value) if cty_nm3.id is not None and string.strcmp(cty_nm3.id, "t") == 0: cty_is_cptr = 1 # 形式 2: 裸名 CPtr elif cty_arg3.kind() == ast.ASTKind.Name: cty_bn3: ast.Name* = ast.Name*(cty_arg3) if cty_bn3.id is not None and string.strcmp(cty_bn3.id, "CPtr") == 0: cty_is_cptr = 1 if cty_is_cptr != 0: # CVoid* → i8*(LLVM 中 void* 表示为 i8*) match ctype_target: case llvmlite.LLVMType.Void(): ctype_target = llvmlite.Int8(pool) case _: pass ctype_target = llvmlite.Ptr(pool, ctype_target) cty_arg0: ast.AST* = cargs.get(0) if cty_arg0 is not None: cty_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cty_arg0, funcs_ptr, func_count, trans) if cty_val is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cty_val, ctype_target, cty_arg0, trans) # t.CType 语法已确认:即使类型解析失败也不跌落到跨模块 FATAL return None # CConst const 标记:CConst(val, t.CPtr) → Ptr(i8)(const void*)。 # CConst 不是 map_t_type 具名类型——t.CConst|char|t.CPtr 注解 = # const char*(i8*),显式调用 t.CConst(addr, t.CPtr) 把整数地址转 # const 指针。此前 map_t_type 失败 → 跌落跨模块函数调用 → 生成 # call @CConst(裸名,无 obj 定义)→ ld.lld undefined symbol: # CConst(elf.vp L650 t.CConst(uint64(strtab_ptr)+sym.st_name, # t.CPtr) 根因)。单参 CConst(x) 仅 const 限定,LLVM 类型不变, # 直接返回原值。 if string.strcmp(func_name, "CConst") == 0: if can >= 2: cconst_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) cconst_arg: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if cconst_arg is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cconst_arg, cconst_ptr_ty, cargs.get(0), trans) elif can == 1: return self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) return None target_ty: llvmlite.LLVMType* = self.Gen.TypeGenResolve.map_t_type(pool, func_name) if target_ty is not None: tc_effective_can: sizet = can # 双参数形式: int(val, t.CPtr) → Ptr(target_ty) # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* if can == 2: tc_arg2_node: ast.AST* = cargs.get(1) tc_arg2_is_cptr: int = 0 if tc_arg2_node is not None: # 形式 1: t.CPtr(Attribute 形式) if tc_arg2_node.kind() == ast.ASTKind.Attribute: tc_arg2_at: ast.Attribute* = ast.Attribute*(tc_arg2_node) if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: tc_arg2_nm: ast.Name* = ast.Name*(tc_arg2_at.value) if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: tc_arg2_is_cptr = 1 # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用,如 t.CXXX(x, CPtr)) elif tc_arg2_node.kind() == ast.ASTKind.Name: tc_arg2_bn: ast.Name* = ast.Name*(tc_arg2_node) if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0: tc_arg2_is_cptr = 1 if tc_arg2_is_cptr != 0: # CVoid* → i8*(LLVM 中 void* 表示为 i8*) match target_ty: case llvmlite.LLVMType.Void(): target_ty = llvmlite.Int8(pool) case _: pass target_ty = llvmlite.Ptr(pool, target_ty) tc_effective_can = 1 if tc_effective_can == 1: tc_arg_node: ast.AST* = cargs.get(0) if tc_arg_node is not None: # 第 8 参 target_ty 必须下传:否则常量在 # translate_constant 里按「是否超出 i32 范围」选位宽, # `uint64(0xFFFFFFFFFFFFFFFF)`(词法回绕为 -1)被 # 物化成 i32 -1 再 zext → 0x00000000FFFFFFFF(N1)。 tc_arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, tc_arg_node, None, 0, trans, target_ty) if tc_arg_val is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, tc_arg_val, target_ty, tc_arg_node, trans) # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL return None # 模块限定 typedef 转换: posix.mode_t(mode), w32.win32base.HANDLE(v) 等 # func = Attribute(value=Name(模块), attr=typedef名),此前被误当跨模块函数调用 # → "跨模块函数 'sha1.mode_t' 返回类型无法精确获取"(SysLibTest os/_posix.vp # L130 posix.mode_t(mode) 根因)。typedef 名做类型转换(与裸名 BYTEPTR(x) # 对齐);非 typedef 名继续走模块函数调用。 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: mt_at: ast.Attribute* = ast.Attribute*(cl.func) if mt_at.value is not None and mt_at.value.kind() == ast.ASTKind.Name: mt_mod_nm: ast.Name* = ast.Name*(mt_at.value) if mt_mod_nm.id is not None and string.strcmp(mt_mod_nm.id, "t") != 0 and string.strcmp(mt_mod_nm.id, "c") != 0: mod_td_ty: llvmlite.LLVMType* = self.Gen.TypeGenResolve.map_t_type(pool, func_name) if mod_td_ty is None: mod_td_str: str = self.Gen.TypeGenCType.lookup_ctypedef(func_name) if mod_td_str is not None and self.Gen.TypeGenCType.is_ctypedef_found() != 0: mod_td_ast: ast.AST* = self.Gen.TypeGenResolve._parse_type_string(pool, mod_td_str, 0) if mod_td_ast is not None: mod_imp_td: str = None mod_fi_td: str = None if trans is not None: mod_imp_td = trans._imported_modules mod_fi_td = trans._from_imports mod_td_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, mod_td_ast, mod_imp_td, mod_fi_td, trans, 0) if mod_td_ty is not None and can == 1: mt_arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans, mod_td_ty) if mt_arg_val is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, mt_arg_val, mod_td_ty, cargs.get(0), trans) # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 # 统一口径:所有 CTypedef 名与 t/c 库原始类型的 call 都具备强转功能 # (BYTEPTR/HANDLE/size_t 等库 typedef + CInt/CBool 等 t/c 核心原语)。 # 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体 # 类型名(如 "int")再走 resolve_typedef_or_map(Box[int].__init__ 的 # self.value = T(v)、combine[T1,T2] 的 T1(b) 依赖此路径) if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: bare_fn_name: str = self.Gen.TypeGenBase.resolve_generic_type_name(func_name) bare_ty: llvmlite.LLVMType* = None # 泛型上下文解析出的内建名(如 T→"double"/"float"):map_t_type 只认 t.CDouble, # 且 float 必须映射 t.CFloat(f32)而非 f64(与注解语义一致) if string.strcmp(bare_fn_name, "double") == 0: bare_ty = llvmlite.Double(pool) elif string.strcmp(bare_fn_name, "float") == 0: bare_ty = llvmlite.Float(pool) else: # 统一口径:CTypedef 动态表优先(BYTEPTR 等库 typedef 强转), # miss 回退 map_t_type(t/c 核心原语强转,阶段2 收敛后 map_t_type # 不再含 stdint 别名,故必须走动态表)。 bare_imp_c: str = None bare_fi_c: str = None if trans is not None: bare_imp_c = trans._imported_modules bare_fi_c = trans._from_imports bare_ty = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, bare_fn_name, bare_imp_c, bare_fi_c) # 泛型上下文替换出的类型名(如 T→"int")map_t_type 不识别(只认无前缀名), # 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。 # GenericTest4 Box[int].__init__ 的 self.value = T(v) 依赖此路径。 if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0: gp_ast: ast.AST* = self.Gen.TypeGenResolve._parse_type_string(pool, bare_fn_name, 0) if gp_ast is not None: imp_gp: str = None fi_gp: str = None if trans is not None: imp_gp = trans._imported_modules fi_gp = trans._from_imports bare_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, gp_ast, imp_gp, fi_gp, trans, 0) # 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T) # (与 int(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的 # typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进 # can==1 单参数分支 → 跌落到"裸名调用未定义"误报) if bare_ty is not None and can == 2: bare_arg2_node: ast.AST* = cargs.get(1) bare_arg2_is_cptr: int = 0 if bare_arg2_node is not None: # 形式 1: t.CPtr(Attribute 形式) if bare_arg2_node.kind() == ast.ASTKind.Attribute: bare_arg2_at: ast.Attribute* = ast.Attribute*(bare_arg2_node) if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0: if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name: bare_arg2_nm: ast.Name* = ast.Name*(bare_arg2_at.value) if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0: bare_arg2_is_cptr = 1 # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用) elif bare_arg2_node.kind() == ast.ASTKind.Name: bare_arg2_bn: ast.Name* = ast.Name*(bare_arg2_node) if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0: bare_arg2_is_cptr = 1 if bare_arg2_is_cptr != 0: # CVoid* → i8*(LLVM 中 void* 表示为 i8*) match bare_ty: case llvmlite.LLVMType.Void(): bare_ty = llvmlite.Int8(pool) case _: pass bare_ty = llvmlite.Ptr(pool, bare_ty) bare_arg_node: ast.AST* = cargs.get(0) if bare_arg_node is not None: bare_arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, bare_arg_node, None, 0, trans, bare_ty) if bare_arg_val is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, bare_arg_val, bare_ty, bare_arg_node, trans) if bare_ty is not None and can == 1: bare_arg_node: ast.AST* = cargs.get(0) if bare_arg_node is not None: # 第 8 参 target_ty 下传:裸名 typedef 强转(如 uint64(x))的 # 目标位宽必须参与常量物化(N1)。 bare_arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, bare_arg_node, None, 0, trans, bare_ty) if bare_arg_val is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, bare_arg_val, bare_ty, bare_arg_node, trans) return None def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*, mod: llvmlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> llvmlite.Value*: """__sizeof__/len/isinstance 内置(未命中返回 None)""" # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) # __sizeof__ 是内置方法,不走跨模块调用路径 # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: sz_at: ast.Attribute* = ast.Attribute*(cl.func) if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: if sz_at.value is not None and can == 0: sz_cls_name: str = None sz_vk: int = sz_at.value.kind() if sz_vk == ast.ASTKind.Name: sz_cls_nm2: ast.Name* = ast.Name*(sz_at.value) sz_cls_name = sz_cls_nm2.id elif sz_vk == ast.ASTKind.Attribute: sz_inner_at: ast.Attribute* = ast.Attribute*(sz_at.value) sz_cls_name = sz_inner_at.attr # 保留完整模块路径(w32.win32base.SECURITY_ATTRIBUTES): # 仅取 attr 会在后续 get_struct_type 裸名全局匹配时误命中 # 跨模块同名类(SECURITY_ATTRIBUTES FieldCount=0 根因)。 if sz_inner_at.value is not None and sz_inner_at.attr is not None: if sz_inner_at.value.kind() == ast.ASTKind.Name: sz_inner_nm: ast.Name* = ast.Name*(sz_inner_at.value) if sz_inner_nm.id is not None: sz_full_len: sizet = string.strlen(sz_inner_nm.id) + 1 + string.strlen(sz_inner_at.attr) + 1 sz_full_buf: str = pool.alloc(sz_full_len) if sz_full_buf is not None: sz_full_buf[0] = '\0' string.strcat(sz_full_buf, sz_inner_nm.id) string.strcat(sz_full_buf, ".") string.strcat(sz_full_buf, sz_inner_at.attr) sz_cls_name = sz_full_buf elif sz_inner_at.value.kind() == ast.ASTKind.Attribute: sz_mod_path: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, sz_inner_at.value) if sz_mod_path is not None: sz_full_len2: sizet = string.strlen(sz_mod_path) + 1 + string.strlen(sz_inner_at.attr) + 1 sz_full_buf2: str = pool.alloc(sz_full_len2) if sz_full_buf2 is not None: sz_full_buf2[0] = '\0' string.strcat(sz_full_buf2, sz_mod_path) string.strcat(sz_full_buf2, ".") string.strcat(sz_full_buf2, sz_inner_at.attr) sz_cls_name = sz_full_buf2 # 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj) sz_resolved_ty: llvmlite.LLVMType* = None sz_resolved_name: str = sz_cls_name if sz_cls_name is not None: # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() sz_orig: str = sz_cls_name sz_cls_name = self.Gen.TypeGenBase.resolve_generic_type_name(sz_cls_name) # 兜底:TypeGenBase 上下文为空时(模板 tp_names 跨 phase 失效), # 直接用 trans 的泛型映射替换 T(list[int] 单态化 _list.vp # T.__sizeof__ 根因)。 if string.strcmp(sz_cls_name, sz_orig) == 0 and trans is not None and trans.GenericTypeParamNames is not None and trans.GenericTypeArgs is not None: gp_n: sizet = len(trans.GenericTypeParamNames) gp_i: sizet for gp_i in range(gp_n): gpn: str = trans.GenericTypeParamNames.get(gp_i) if gpn is not None and string.strcmp(sz_orig, gpn) == 0: gta: str = trans.GenericTypeArgs.get(gp_i) if gta is not None: sz_cls_name = gta break sz_resolved_name = sz_cls_name # 指针包装类型检查必须在 dot-strip 之前:类型实参可能带 sha1 # 前缀内嵌点号(rawptr[7565e081d88517ac.AST]、f4679...AST|t.CPtr), # strrchr('.') 会把括号内 ".AST"/".CPtr" 剥掉 → "AST]"/"CPtr", # 前缀/联合判断永远失配 → 落回把接收者 Name(T) 当实例翻译 → # NameError: 未定义名称 'T'(SlotsBugTest rawptr[list[rawptr[AST]]] 根因)。 # 联合类型(X | t.CPtr)与新一代指针包装 rawptr[X] 均按指针大小 8。 if string.strstr(sz_cls_name, "|") is not None: return llvmlite.const_int64(pool, 8) if string.strncmp(sz_cls_name, "rawptr[", 7) == 0: return llvmlite.const_int64(pool, 8) # 归一后的指针唯一规范形 `T*`(TypeGenResolve._norm_type_arg_name # 的指针书写归一:rawptr[T] ≡ t.CPtr[T] ≡ T|t.CPtr ≡ T*) # ⇒ **尾随** '*' 一律按指针大小 8(多级 `**` 同为 8)。 # 判据必须是"尾随",不能用 strrchr:接收者是 # `list[{sha}.AST*]`(元素为指针的容器)时串内也含 '*', # strrchr 会把它误判成指针并返回 8(容器大小 ≠ 8)。 # 缺本判据时 `T.__sizeof__()` 的实参串 `{sha}.AST*` 既不命中 # '|' 也不命中 'rawptr[',落回把接收者 Name(T) 当实例翻译 → # NameError: 未定义名称 'T'(现场 Test/AstTest/App/main.vp:21 # 特化 list[ast.AST|t.CPtr] → includes/_list.vp:36)。 _sz_len_s: sizet = string.strlen(sz_cls_name) while _sz_len_s > 0 and sz_cls_name[_sz_len_s - 1] == ' ': _sz_len_s -= 1 if _sz_len_s > 0 and sz_cls_name[_sz_len_s - 1] == '*': return llvmlite.const_int64(pool, 8) # 保存完整名(含模块前缀)供模块归属精确匹配:去前缀后 # get_struct_type 裸名全局匹配会误命中跨模块同名类 # (w32.win32base.SECURITY_ATTRIBUTES 根因)。 sz_full_name: str = sz_cls_name # 去除模块前缀: Viper 解析器将 int 解析为 Name(id="int") # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 # "int" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" dot_pos: str = string.strrchr(sz_cls_name, '.') if dot_pos is not None: sz_cls_name = dot_pos + 1 # [阶段3] 统一尺寸口径:库 typedef(BYTE/DWORD 等)先经正常 # 库分析解析(resolve_typedef_or_map → 位宽/8),miss 才走 # 下方硬编码尺寸表(t/c 核心原语)。 # 必须传入 trans 的 from_imports/imported_modules:本模块 typedef # 值可能引用 from-import 别名(MyWord: t.CTypedef = MyInt, # MyInt 来自 from t import CInt as MyInt),不传则别名链解析失败 # → get_type_size_bytes 返回 0 → 落到"回退 2"把 Name 当值翻译 # → NameError: 未定义名称 'MyWord'(T8 根因)。 dyn_sz_c: int = self.Gen.TypeGenResolve.get_type_size_bytes(pool, sz_cls_name, trans._imported_modules if trans is not None else None, trans._from_imports if trans is not None else None) if dyn_sz_c > 0: return llvmlite.const_int64(pool, dyn_sz_c) # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) sz_builtin: int = -1 if string.strcmp(sz_cls_name, "int") == 0: sz_builtin = 4 elif string.strcmp(sz_cls_name, "str") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "bytes") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CInt") == 0: sz_builtin = 4 elif string.strcmp(sz_cls_name, "CInt8T") == 0: sz_builtin = 1 elif string.strcmp(sz_cls_name, "CInt16T") == 0: sz_builtin = 2 elif string.strcmp(sz_cls_name, "CInt32T") == 0: sz_builtin = 4 elif string.strcmp(sz_cls_name, "CInt64T") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CChar") == 0: sz_builtin = 1 elif string.strcmp(sz_cls_name, "CDouble") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CFloat") == 0: sz_builtin = 4 elif string.strcmp(sz_cls_name, "CPtr") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CSizeT") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CBool") == 0: sz_builtin = 1 elif string.strcmp(sz_cls_name, "bool") == 0: sz_builtin = 1 # 泛型 T 解析出的裸内建名(resolve_generic_type_name 返回 # _infer_generic_ctor_type_arg 的输出,如 T→"double"/"float"): # 缺省会让 sz_builtin=-1 → 落到"回退 2"把 Name(T) 当值翻译 → # NameError(VectorGenericTest Vector[double].__init__ 回归根因) elif string.strcmp(sz_cls_name, "double") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "float") == 0: sz_builtin = 4 elif string.strcmp(sz_cls_name, "char") == 0: sz_builtin = 1 if sz_builtin >= 0: # 注意: 必须用 const_int64 而非 ConstInt(...,"0") # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 return llvmlite.const_int64(pool, sz_builtin) sz_resolved_ty = None # 模块限定类(w32.win32base.SECURITY_ATTRIBUTES):模块归属 # 精确匹配定义侧结构体,防裸名全局匹配误命中跨模块同名类 # (SECURITY_ATTRIBUTES 注册于 e710 但期望 a335 根因)。 if sz_full_name is not None: szf_dot: str = string.strrchr(sz_full_name, '.') if szf_dot is not None: szf_mod_len: sizet = sizet(uint64(szf_dot) - uint64(sz_full_name)) szf_mod: str = pool.alloc(szf_mod_len + 1) if szf_mod is not None: string.strncpy(szf_mod, sz_full_name, szf_mod_len) szf_mod[szf_mod_len] = '\0' # t/c 内置库豁免(int 等已由内建/尺寸表处理) if string.strcmp(szf_mod, "t") != 0 and string.strcmp(szf_mod, "c") != 0: szf_sha1: str = self.Gen.StructGen._resolve_module_sha1(szf_mod, trans._from_imports if trans is not None else None) if szf_sha1 is not None: szf_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(sz_cls_name, szf_sha1) if szf_entry is not None and szf_entry.Ty is not None: sz_resolved_ty = szf_entry.Ty if sz_resolved_ty is None: sz_resolved_ty = self.Gen.StructGen.get_struct_type(sz_cls_name) # 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小 # (GenericTest2 Stack.type_size 依赖此路径) if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript: sub_sz: ast.Subscript* = ast.Subscript*(sz_at.value) if sub_sz.value is not None and sub_sz.value.kind() == ast.ASTKind.Name: gen_nm_sz: ast.Name* = ast.Name*(sub_sz.value) if gen_nm_sz.id is not None: gen_args_sz: list[str]* = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_sz.slice, trans._from_imports) if gen_args_sz is not None and len(gen_args_sz) > 0: gargs_resolved: list[str]* = list[str](pool, 8) if gargs_resolved is not None: gai_sz: sizet = len(gen_args_sz) gai2_sz: sizet = 0 for gai2_sz in range(gai_sz): gres_sz: str = self.Gen.TypeGenBase.resolve_generic_type_name(gen_args_sz.get(gai2_sz)) gargs_resolved.append(gres_sz) spec_sz: str = self.Gen.ClassGenGeneric._specialize_generic_class(trans, gen_nm_sz.id, gargs_resolved) if spec_sz is not None: sz_resolved_name = spec_sz sz_resolved_ty = self.Gen.StructGen.get_struct_type(spec_sz) # 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型 # (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int])) # 数组变量接收者 bl_count.__sizeof__()(t.CArray[T, N] 变量)→ alloca # 指针 Ptr([N x T]),算 N*elem_size(TPC _HandleSizeofLlvm 数组分支; # zhuff.vp memset(bl_count, 0, bl_count.__sizeof__()) 依赖) if sz_resolved_ty is None: inst_sz_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sz_at.value, None, 0, trans) if inst_sz_val is not None and inst_sz_val.Ty is not None: match inst_sz_val.Ty: case llvmlite.LLVMType.Ptr(inst_inner_sz): match inst_inner_sz: case llvmlite.LLVMType.Struct(_, _, _): sz_resolved_ty = inst_inner_sz case llvmlite.LLVMType.Array(_, _): sz_resolved_ty = inst_inner_sz case _: pass case llvmlite.LLVMType.Struct(_, _, _): sz_resolved_ty = inst_sz_val.Ty case llvmlite.LLVMType.Array(_, _): # 全局数组变量(模块级 t.CArray[T,N])translate_value # 返回数组值 [N x T](非指针);局部数组返回 alloca # 指针 Ptr([N x T]) 走上方 Ptr(Array) 分支。 # pyzlib_error_msg.__sizeof__() 依赖(全局字符缓冲)。 sz_resolved_ty = inst_sz_val.Ty case _: pass if sz_resolved_ty is not None: sz_val: int = self.Gen.ClassGenEnum._get_type_size(sz_resolved_ty) if sz_val > 0: return llvmlite.const_int64(pool, sz_val) # 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止 self.Gen.TypeGenErr.fatal_error(sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小", "TypeError") # 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) if sz_resolved_name is None: sz_resolved_name = "(unknown)" self.Gen.TypeGenErr.fatal_error(sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小", "TypeError") # 检测 len(obj) — 返回 list 对象的 __count__ 字段(偏移 8,i64) # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: len_at: ast.Attribute* = ast.Attribute*(cl.func) if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: if len_at.value is not None and can == 0: obj_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) if obj_val is not None and obj_val.Ty is not None: # 防御性类型检查: obj_val 必须是指针类型才能做 GEP # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, # 导致 llc 报错 "base of getelementptr must be a pointer" if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0: # 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误 self.Gen.TypeGenErr.fatal_error(len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError") i64_ty_len: llvmlite.LLVMType* = llvmlite.Int64(pool) # 注意: 必须用 const_int64 而非 ConstInt(...,"0") # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) idx_one: llvmlite.Value* = llvmlite.const_int64(pool, 1) count_ptr: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty_len, obj_val, idx_one) if count_ptr is not None: return llvmlite.build_load(builder, i64_ty_len, count_ptr) # 检测 len() 内置函数调用 — 结构体对象走 __len__ 方法,字符串走 strlen # len(s) 对 str 类型调用 strlen,返回 i64 if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: if func_name is not None and string.strcmp(func_name, "len") == 0: if can == 1: len_arg_node: ast.AST* = cargs.get(0) if len_arg_node is not None: len_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, len_arg_node, None, 0, trans) if len_val is not None: # len(数组):t.CArray[T, N] → 常量 N(对齐 TPC # _HandleLenLlvm 的 ArrayType.count 分支)。数组变量 # translate_value 可能返回 Ptr([N x T])(alloca 指针) # 或 [N x T] 值,两种都识别;否则会误走 strlen 把 # 数组首元素当字符串读 → 垃圾长度。 len_is_arr: int = 0 len_arr_n: int = 0 if len_val.Ty is not None: if self.Gen.ExprGenBase.is_ptr_type(len_val.Ty) != 0: len_ap: llvmlite.LLVMType* = len_val.Ty.Pointee if len_ap is not None: match len_ap: case llvmlite.LLVMType.Array(_, len_arr_cnt): len_is_arr = 1 len_arr_n = len_arr_cnt case _: pass else: match len_val.Ty: case llvmlite.LLVMType.Array(_, len_arr_cnt): len_is_arr = 1 len_arr_n = len_arr_cnt case _: pass if len_is_arr != 0: return llvmlite.const_int64(pool, len_arr_n) # len(对象):有 __len__ 就调用,没有就编译期报错 # (用户要求 2026-08-15,不再静默 strlen 读对象首字段): # - list 泛型内置容器:__len__ 由 list 内置分支内联 # (读 __count__,偏移 1),不生成方法函数 # (_is_list_builtin_method,通用判断非特判) # - 普通类:调用 {Class}.__len__ 函数 # - 都没有:fatal_error # str(Ptr(Int8))保持 strlen(内建语义)。 len_struct_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(len_val) if len_struct_ty is not None: len_cls_nm: str = self.Gen.StructGen.get_class_name_by_type(pool, len_struct_ty) if len_cls_nm is None: self.Gen.TypeGenErr.fatal_error(len_arg_node, "len() 参数类型推断失败(结构体类名未知)", "TypeError") # list 内置 __len__:读 __count__(GEP 偏移 1,i64) # 判据优先取接收者实际类型(_is_list_builtin_receiver) # 目标类型已由 can==1(len 的实参存在)确定为表达式节点 # ⇒ 在此显式窄化:形参是 ast.Call*(仅用于 fail-fast # 定位节点),而 len_arg_node 声明为基类 ast.AST*; # 基类指针传派生类形参属向下转型,严格指针规则下禁止。 len_arg_cl: ast.Call* = ast.Call*(len_arg_node) if self.Gen.CallGenProp._is_list_builtin_receiver(pool, len_val, len_cls_nm, "__len__", len_arg_cl) != 0: i64_ty_lb: llvmlite.LLVMType* = llvmlite.Int64(pool) idx_one_lb: llvmlite.Value* = llvmlite.const_int64(pool, 1) cnt_ptr_lb: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty_lb, len_val, idx_one_lb) if cnt_ptr_lb is not None: return llvmlite.build_load(builder, i64_ty_lb, cnt_ptr_lb) 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* = self.find_func_in_module(mod, len_lookup) if len_fn2 is not None: len_ret_ty2: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(len_fn2) 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) len_self_arg2: llvmlite.Value* = len_val len_first_param2: llvmlite.Param* = llvmlite.function_get_param_head(len_fn2) if len_first_param2 is not None: len_self_ty2: llvmlite.LLVMType* = llvmlite.param_get_ty(len_first_param2) if len_self_ty2 is not None and len_val.Ty is not None: len_self_arg2 = llvmlite.build_bitcast(builder, len_val, len_self_ty2) len_self_arg2.Next = None return llvmlite.build_call(builder, len_fn_name2, len_self_arg2, 1, len_ret_ty2, 0) # len_fn2 未命中(跨模块方法):如 ndarray[t.CDouble].__len__ # 定义在 numpy——泛型特化方法无 stub declare,find_func_in_module # 后缀匹配查不到。用结构体所属模块 sha1 构造 # {sha1}.{cls}.__len__ 精确调用名(对齐 _translate_method_call # 跨模块调用名构造),返回类型从 text.ll/vpi 精确解析, # _ensure_method_declare 建 declare 后调用。 len_cls_sha1_x: str = self.Gen.StructGen.get_struct_sha1(len_cls_nm) if len_cls_sha1_x is not None: # 缓冲区需容纳 "{sha1}.{cls}.__len__": # 2 个点 + "__len__"(7) + NUL = 10;+8 会截断 # 末两位 → 符号变 ".__len" 链接 undefined # (NumpyTest test_len 链接错误根因) len_ml_x: sizet = string.strlen(len_cls_sha1_x) + string.strlen(len_cls_nm) + 10 len_mangled_x: str = pool.alloc(len_ml_x) if len_mangled_x is not None: viperlib.snprintf(len_mangled_x, len_ml_x, "%s.%s.__len__", len_cls_sha1_x, len_cls_nm) len_ret_x: llvmlite.LLVMType* = self._LookupMethodRetTyFromTextLL(pool, len_cls_sha1_x, len_cls_nm, "__len__") if len_ret_x is None: len_ret_x = self._lookup_method_ret_ty_via_vpi(pool, len_cls_sha1_x, len_cls_nm, "__len__") if len_ret_x is not None: # self 参数按对象实际类型 Ptr(len_struct_ty)(与定义侧 # 同名类型链接匹配);len_val 已是 load 后的对象指针。 # Value 链直接作 param_head(同跨模块调用模式)。 len_self_x: llvmlite.Value* = len_val len_self_x.Next = None self._ensure_method_declare(pool, mod, len_mangled_x, len_ret_x, len_self_x, 1) return llvmlite.build_call(builder, len_mangled_x, len_self_x, 1, len_ret_x, 0) # fail-fast:类没有 __len__(用户要求编译期报错) # 报文措辞与 TPC HandlesExprBuiltin._FailFastLenUnsupported 逐字对齐 self.Gen.TypeGenErr.fatal_error(len_arg_node, f"len() 参数类型 '{len_cls_nm}' 没有 __len__ 方法。len() 只支持定长数组/数组指针(t.CArray[T, N])、i8*(str/bytes)或带 __len__ 的结构体;非 i8 裸指针/标量指针没有长度语义:字符串请用 str/bytes,需要元素个数请自行记录长度,或改用 t.CPtr[元素] 并显式维护元素计数", "TypeError") # 非结构体:str(Ptr(Int8))走 strlen;其它类型 fail-fast len_arg_ty: llvmlite.LLVMType* = llvmlite.value_get_ty(len_val) len_is_str: int = 0 if len_arg_ty is not None and self.Gen.ExprGenBase.is_ptr_type(len_arg_ty) != 0: match len_arg_ty: case llvmlite.LLVMType.Ptr(len_pt_ty): if len_pt_ty is not None: match len_pt_ty: case llvmlite.LLVMType.Int(len_pt_bits): if len_pt_bits == 8: len_is_str = 1 case _: pass case _: pass if len_is_str != 0: # 确保 strlen 在模块中有声明 strlen_fn: llvmlite.Function* = self.find_func_in_module(mod, "strlen") if strlen_fn is None: i64_ty_ln: llvmlite.LLVMType* = llvmlite.Int64(pool) i8_ptr_ty_ln: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) if strlen_fn is not None: llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") # 参数类型转换为 i8* i8_ptr_ty_ln2: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) len_coerced: llvmlite.Value* = len_val if self.Gen.ExprGenBase.is_ptr_type(len_arg_ty) != 0: len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) # 构建单参数链表并调用 strlen len_coerced.Next = None i64_ty_ln2: llvmlite.LLVMType* = llvmlite.Int64(pool) return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) # fail-fast:非字符串/数组/对象,无法求长度 # 报文措辞与 TPC HandlesExprBuiltin._FailFastLenUnsupported 逐字对齐 self.Gen.TypeGenErr.fatal_error(len_arg_node, "len() 参数类型不支持(非字符串/数组/对象)。len() 只支持定长数组/数组指针(t.CArray[T, N])、i8*(str/bytes)或带 __len__ 的结构体;非 i8 裸指针/标量指针没有长度语义:字符串请用 str/bytes,需要元素个数请自行记录长度,或改用 t.CPtr[元素] 并显式维护元素计数", "TypeError") # 检测 isinstance() 内置函数调用 — 运行时 vtable 子类集合比较 # isinstance(obj, Cls):obj 头部 vtable 指针 ∈ {Cls 及全部子类 vtable}; # NoVTable 目标类回退编译时静态判断(详见 _translate_isinstance)。 if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: if func_name is not None and string.strcmp(func_name, "isinstance") == 0: if can >= 2: is_res: llvmlite.Value* = self.Gen.CallGenLeafKit._translate_isinstance(pool, builder, mod, cargs.get(0), cargs.get(1), trans) if is_res is not None: return is_res return None def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*, mod: llvmlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: t.CPtr = None) -> llvmlite.Value*: """静态类/方法调用/表达式接收者/self.field/list 内置(未命中返回 None) hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为方法调用路径)。 编译器生成方法(如 __before_init__/__init__)恒返回 void, _translate_method_call 处理后返回 None(无返回值)——若不标记, translate_call 会误判"未命中"继续走跨模块函数路径(把对象名 当模块名查 SHA1 → "跨模块调用 'buf.__before_init__' 找不到模块 SHA1")。 """ # REnum.kind() 编译期转 __tag 读取(字段偏移 0;类型取 __tag 的字段声明类型): # REnum 无 kind 方法(源码无、编译器不生成),此前 .kind() 被方法查找 # 兜底误绑到 ast.AST.kind(this 偏移,语义错误)。此处直接翻译为 # bitcast obj 到 __tag* + load —— 零函数调用,返回变体 tag。 # REnum 判据四条并列(缺一即整条分支被跳过 ⇒ .kind() 掉进通用调用路径、 # 返回类型落空 ⇒ 报「指针隐式转整数」): # ① 变体表 _is_renum_class_name ② struct 带 __tag:_is_renum_by_entry # ③ pointee 结构体带 __tag(类型版,不需要类名) # ④ 接收者 `X.field` 时按 X 的注解 + 字段声明类型反推 pointee 类名 # ③④ 的存在理由:变体表是 per-Generator 实例字段(ClassGenEnum:811-816: # InitClassGen 每个 Generator 重置),跨模块 stub 路径又明确跳过 REnum 注册 # (VpiReader:2637-2643);且字段访问可能把类型整体退化掉。 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: rk_at: ast.Attribute* = ast.Attribute*(cl.func) if rk_at is not None and rk_at.attr is not None and string.strcmp(rk_at.attr, "kind") == 0: rk_obj: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, rk_at.value, None, 0, trans) if rk_obj is not None and rk_obj.Ty is not None: rk_ty: llvmlite.LLVMType* = rk_obj.Ty rk_load: int = 0 rk_cls: str = None rk_pointee: llvmlite.LLVMType* = None # rk_is_rn:是否已判定为 REnum。与 rk_cls 解耦——判据不再只依赖类名/变体表。 rk_is_rn: int = 0 # rk_tag_ty:kind() 的返回类型真源 = __tag 的**字段声明类型** # (FieldEntry.Ty)。默认先放 i32 只为"取不到字段条目"时的等效值 # ——__tag 全仓只有一处写入(ClassGenEnum:1009 # add_field(entry, "__tag", Int32)),故取不到时 i32 必等价; # 取到则以字段声明类型为准,将来 __tag 换宽度不会静默失配。 rk_tag_ty: llvmlite.LLVMType* = llvmlite.Int32(pool) if self.Gen.ExprGenBase.is_ptr_type(rk_ty) != 0: rk_pointee = rk_ty.Pointee # 联合简化双指针(Ptr(Ptr(Struct)))→ 解一层 + load if rk_pointee is not None and self.Gen.ExprGenBase.is_ptr_type(rk_pointee) != 0: rk_pointee = rk_pointee.Pointee rk_load = 1 rk_cls = self.Gen.StructGen.get_class_name_by_type(pool, rk_pointee) # 判据三条并列(此前只认变体表这一条): # 1) 变体表命中:_is_renum_class_name # 2) struct 带 __tag:_is_renum_by_entry(表缺失时的既有判据, # 与 CallGenMixin:426-427 同口径) # 3) 类名反查不到(跨模块 struct 未命名/名称退化)但 pointee 结构体 # 带 __tag ⇒ 必是 REnum(_is_renum_by_entry 的类型版,不需要类名) # 背景:变体表是 per-Generator 实例字段(ClassGenEnum:811-816 注释: # InitClassGen 每个 Generator 重置),跨模块 stub 路径又明确跳过 # REnum 注册(VpiReader:2637-2643)⇒「表里没有 LLVMType」是常态。 # 只认表会让整条 kind() 分支被跳过 ⇒ .kind() 掉进通用调用路径、返回 # 类型落空(实况:CallGenLib.vp:355 `vk_a: int = val.Ty.kind()` 报 # 「指针隐式转整数已禁止」)。 if rk_cls is not None: if self.Gen.ClassGenEnum._is_renum_class_name(rk_cls) != 0 or self.Gen.ClassGenEnum._is_renum_by_entry(rk_cls) != 0: rk_is_rn = 1 else: rk_cls = None # ③:类名反查不到也不要紧——直接看 pointee 结构体带不带 __tag。 # 顺带把 __tag 的字段声明类型记为 kind() 返回类型真源(第 2 层)。 rk_tag_fe: GenTypes.FieldEntry* = None if rk_pointee is not None: rk_tag_fe = self.Gen.StructGen.lookup_field(rk_pointee, "__tag") if rk_is_rn == 0 and rk_tag_fe is not None: rk_is_rn = 1 if rk_tag_fe is not None and rk_tag_fe.Ty is not None: rk_tag_ty = rk_tag_fe.Ty # 注解兜底:联合简化/退化后运行时类型丢失(如 # resolved: llvmlite.LLVMType* 存 i8*,pointee 非 # 结构体),用变量注解类名识别 REnum 类(kind() 语义: # 读 __tag,bitcast 对象到 i32* + load)。 if rk_is_rn == 0 and rk_at.value is not None and rk_at.value.kind() == ast.ASTKind.Name and trans is not None: rk_nm: ast.Name* = ast.Name*(rk_at.value) if rk_nm.id is not None: rk_ve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, rk_nm.id) rk_annot_raw: str = self.Gen.VarGen.var_annot_class_name(rk_ve) if rk_annot_raw is not None: # 截断联合/泛型后缀(" | t.CPtr" / "[...]") rk_ae: sizet = 0 while rk_annot_raw[rk_ae] != '\0' and rk_annot_raw[rk_ae] != ' ' and rk_annot_raw[rk_ae] != '|' and rk_annot_raw[rk_ae] != '[': rk_ae += 1 rk_ab: str = pool.alloc(rk_ae + 1) if rk_ab is not None: string.strncpy(rk_ab, rk_annot_raw, rk_ae) rk_ab[rk_ae] = '\0' # 去模块前缀("llvmlite.LLVMType" → "LLVMType") rk_ad: str = string.strrchr(rk_ab, '.') if rk_ad is not None and rk_ad[1] != '\0': rk_cls = rk_ad + 1 else: rk_cls = rk_ab # 判据同上(表 或 struct 带 __tag),不再只认变体表 if self.Gen.ClassGenEnum._is_renum_class_name(rk_cls) != 0 or self.Gen.ClassGenEnum._is_renum_by_entry(rk_cls) != 0: rk_is_rn = 1 # 第 2 层:按类名取 struct 的 __tag 声明类型 rk_st_b: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(rk_cls) if rk_st_b is not None: rk_fe_b: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(rk_st_b, "__tag") if rk_fe_b is not None and rk_fe_b.Ty is not None: rk_tag_ty = rk_fe_b.Ty else: rk_cls = None # 第 4 层兜底:接收者是 `X.field` 形状时,运行时类型可能整体退化 # (rk_ty 不是"指向 REnum 结构体"的指针 ⇒ 上面三条判据都拿不到 # struct,只能用**声明**信息判):X 的注解类名 → struct → 该字段的 # 声明类型 → 解一层(字段访问取地址形态为 Ptr(Ptr(T)),故必要时再解 # 一层)→ pointee 类名 → 再走 表/__tag 判据。 # CallGenLib.vp:355 `vk_a: int = val.Ty.kind()` 正是此形态: # Value.Ty 声明为 `rawptr[LLVMType]`(__values.vp:22)。 if rk_is_rn == 0 and rk_at.value is not None and rk_at.value.kind() == ast.ASTKind.Attribute and trans is not None: rk_bat: ast.Attribute* = ast.Attribute*(rk_at.value) if rk_bat is not None and rk_bat.attr is not None and rk_bat.value is not None and rk_bat.value.kind() == ast.ASTKind.Name: rk_bnm: ast.Name* = ast.Name*(rk_bat.value) if rk_bnm.id is not None: rk_bve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, rk_bnm.id) rk_bannot: str = self.Gen.VarGen.var_annot_class_name(rk_bve) if rk_bannot is not None: rk_blen: sizet = 0 while rk_bannot[rk_blen] != '\0' and rk_bannot[rk_blen] != ' ' and rk_bannot[rk_blen] != '|' and rk_bannot[rk_blen] != '[': rk_blen += 1 rk_bbuf: str = pool.alloc(rk_blen + 1) if rk_bbuf is not None: string.strncpy(rk_bbuf, rk_bannot, rk_blen) rk_bbuf[rk_blen] = '\0' # 去模块前缀("llvmlite.Value" → "Value") rk_bdot: str = string.strrchr(rk_bbuf, '.') rk_bcls: str = rk_bbuf if rk_bdot is not None and rk_bdot[1] != '\0': rk_bcls = rk_bdot + 1 rk_bst: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(rk_bcls) if rk_bst is not None: rk_bfe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(rk_bst, rk_bat.attr) if rk_bfe is not None and rk_bfe.Ty is not None: rk_fpt: llvmlite.LLVMType* = rk_bfe.Ty if self.Gen.ExprGenBase.is_ptr_type(rk_fpt) != 0: rk_fpt = rk_fpt.Pointee if rk_fpt is not None and self.Gen.ExprGenBase.is_ptr_type(rk_fpt) != 0: rk_fpt = rk_fpt.Pointee if rk_fpt is not None: rk_fcls: str = self.Gen.StructGen.get_class_name_by_type(pool, rk_fpt) if rk_fcls is not None: if self.Gen.ClassGenEnum._is_renum_class_name(rk_fcls) != 0 or self.Gen.ClassGenEnum._is_renum_by_entry(rk_fcls) != 0: rk_is_rn = 1 rk_cls = rk_fcls rk_ffe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(rk_fpt, "__tag") if rk_ffe is not None: if rk_is_rn == 0: rk_is_rn = 1 if rk_ffe.Ty is not None: rk_tag_ty = rk_ffe.Ty if rk_is_rn != 0: rk_val: llvmlite.Value* = rk_obj if rk_load != 0: # build_load(builder, ty, ptr):ty 是**载入值**的类型 # (生成 `load , `,返回值 Ty = ty)。 # rk_ty 是 Ptr(Ptr(X)),要取内层指针 ⇒ ty 必须是 rk_ty.Pointee; # 传 rk_ty 会生成 `load , %p` 且返回值 Ty 仍是指针。 rk_val = llvmlite.build_load(builder, rk_ty.Pointee, rk_obj) if rk_val is None: # fail-fast:已判定为 REnum(判据命中),双指针解一层 load 却拿不到 # 值——绝不静默跳过:跳过会让 .kind() 掉进通用调用路径、返回类型落空, # 报错点漂到几百行外的赋值处(如 CallGenLib.vp:355)。 self.Gen.TypeGenErr.fatal_error(cl, f"REnum.kind() 翻译失败:接收者已判定为 REnum(变体表/__tag 判据命中)," f"但接收者指针解一层 load 失败(rk_load={rk_load})", "TypeError") if hit_box is not None: hit_box[0] = 1 # 第 2 层:按 __tag 的**字段声明类型**取址并 load,不再硬编码 i32。 # 宽度口径交给赋值侧的隐式转换规则(coerce_to_type):整型↔整型 # (低向高无损 / 高向低可安全降级)自动提升降级,规则不覆盖的组合 # (如 tag 为浮点/指针)才由该规则 fail-fast。 rk_tag_p: llvmlite.LLVMType* = llvmlite.Ptr(pool, rk_tag_ty) rk_cast: llvmlite.Value* = llvmlite.build_bitcast(builder, rk_val, rk_tag_p) # 第一参数是**载入值**类型 rk_tag_ty(不是指针 rk_tag_p): # 传 rk_tag_p 会生成 `load i32*, i32* %p`,返回值 Ty = i32*, # 到赋值侧 coerce_to_type 就报「指针隐式转整数已禁止」 # (CallGenLib.vp:355 `vk_a: int = val.Ty.kind()` 根因)。 # 对照 MatchGenMixin.vp:327 读 __tag 的正确写法。 return llvmlite.build_load(builder, rk_tag_ty, rk_cast) # 检测类名静态/类方法调用: ClassName.method(args) # 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时, # 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: st_at: ast.Attribute* = ast.Attribute*(cl.func) if st_at is not None and st_at.value is not None and trans is not None: if st_at.value.kind() == ast.ASTKind.Name: st_nm: ast.Name* = ast.Name*(st_at.value) if st_nm.id is not None: st_var: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, st_nm.id) if st_var is None and self.Gen.StructGen.get_struct_type(st_nm.id) is not None and self.Gen.ImportsGen.is_module_imported(trans._imported_modules, st_nm.id) == 0: # REnum 变体构造优先于静态/类方法调用: if self.Gen.ClassGenEnum._is_renum_class_name(st_nm.id) != 0: rc_tag_sc: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(st_nm.id, func_name) if rc_tag_sc >= 0: return self.Gen.CallGenCtor._translate_renum_construct(pool, builder, mod, st_nm.id, func_name, rc_tag_sc, cargs, can, trans, cl.IsVolatile) st_res: llvmlite.Value* = self.Gen.CallGenProp._translate_static_class_call(pool, builder, mod, st_nm.id, func_name, cl, trans) if st_res is not None: return st_res # 实例方法经类名调用 ClassName.method(obj, args) → obj.method(args)(Python 语义,首参是 self 对象);但 st_nm.id == func_name(类名==方法名,如 CompilerFactory.CompilerFactory(...))是构造调用而非实例方法调用——本分支会误把模块限定类构造当 ClassName.method(obj,args) 且首实参当 self 传,导致返回类型查 "X.X" 永远落空 fail-fast。故跳过本分支,落到 translate_call 尾部的 ctor 检测 if can >= 1 and cargs is not None and string.strcmp(st_nm.id, func_name) != 0: im_self: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), None, 0, trans) if im_self is not None: im_rem: sizet* = None if can >= 2: im_rem = pool.alloc(sizet(can - 1) * 8) if im_rem is not None: ri_im: sizet for ri_im in range(can - 1): im_rv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(ri_im + 1), None, 0, trans) if im_rv is not None: im_rem[ri_im] = sizet(im_rv) im_res: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, st_nm.id, func_name, im_self, im_rem, can - 1, trans) if im_res is not None: return im_res elif st_at.value.kind() == ast.ASTKind.Attribute: # 模块限定静态调用: module.ClassName.static_method(args) # cl.func = Attribute(value=Attribute(value=Name(module), # attr=ClassName), attr=method_name) # 此前未检测 → 走通用路径把 method_name 当裸函数解析, # 生成 call i32 @from_long(无类名/SHA1 前缀)→ 链接 # undefined reference(CPythonTest PyLongObj.from_long 根因) st_at2: ast.Attribute* = ast.Attribute*(st_at.value) if st_at2 is not None and st_at2.attr is not None and st_at2.value is not None: if st_at2.value.kind() == ast.ASTKind.Name: # ClassName 是已注册结构体类名时尝试静态/类方法 if self.Gen.StructGen.get_struct_type(st_at2.attr) is not None: st_res2: llvmlite.Value* = self.Gen.CallGenProp._translate_static_class_call(pool, builder, mod, st_at2.attr, func_name, cl, trans) if st_res2 is not None: return st_res2 # [M4·REPL 专用分支] 会话变量接收者的方法调用:`obj.m(args)` 的 obj 是**会话 # 变量**时,其值在 ctx 槽里、不在 SymTab ⇒ 上面的 lookup_var 分支恒不命中 # (本次之前:整个分派都靠 SymTab,跨片段的 `p.get()` 直接落空)。此处按 # 会话表判定:命中即取接收者(PTR 条目取槽内指针值;STRUCT 条目取**槽地址** # = 对象自身地址,正是 self 需要的形态),再用接收者类型的类名走同一条 # `_translate_method_call`(符号 .<类>.<方法>、返回类型经 text.ll/vpi)。 # 守卫 trans.ReplCtx is not None ⇒ 非 REPL 编译路径一行不经过(逐字不变)。 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute and trans is not None and trans.ReplCtx is not None and pool is not None: rp_at: ast.Attribute* = ast.Attribute*(cl.func) if rp_at is not None and rp_at.value is not None and rp_at.attr is not None: if rp_at.value.kind() == ast.ASTKind.Name: rp_nm: ast.Name* = ast.Name*(rp_at.value) if rp_nm.id is not None: rp_ent: rawptr[GenTypes.ReplVarEntry] = self.Gen.VarGen.repl_find_entry(trans.ReplCtx, rp_nm.id) if rp_ent is not None: rp_val: llvmlite.Value* = None if rp_ent.TyTag == GenTypes.REPL_TY_STRUCT: # 结构体值内联在槽里:槽地址即对象地址(self) rp_val = self.Gen.VarGen.repl_try_addr(trans, rp_nm.id, cl) else: rp_val = self.Gen.VarGen.repl_try_read(trans, rp_nm.id, cl) rp_cls: str = None if rp_val is not None and rp_val.Ty is not None: rp_sty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(rp_val) if rp_sty is not None: rp_cls = self.Gen.StructGen.get_class_name_by_type(pool, rp_sty) if rp_cls is not None: rp_obj: llvmlite.Value* = rp_val if self.Gen.ExprGenBase.is_ptr_type(rp_val.Ty) != 0 and rp_val.Ty.Pointee != 0 and self.Gen.ExprGenBase.is_ptr_type(rp_val.Ty.Pointee) != 0: rp_obj = llvmlite.build_load(builder, rp_val.Ty, rp_val) if rp_obj is not None: if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, rp_cls, rp_at.attr, rp_obj, cl, trans) # 会话变量命中但接收者不是结构体类(如 int/str/其它指针): # 不拦截、不置 hit,交给下方既有分支(list 内置/FakeDuck 等) # 检测方法调用: obj.method(args) # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: method_at: ast.Attribute* = ast.Attribute*(cl.func) if method_at is not None and method_at.value is not None: # 链式方法调用: a.b().c() —— value 是内层 Call(如 gfx.vp 的 # eye.Sub(target).Norm())。此前未处理 → 外层 .Norm() 的 value # 非 Name 跳过方法分支 → 通用路径把 eye.Sub 当属性解析 → # "属性写入失败: .Sub"。先翻译内层调用得接收者,再方法调用。 if method_at.value.kind() == ast.ASTKind.Call and trans is not None: recv_val_c: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, method_at.value, None, 0, trans) if recv_val_c is not None and recv_val_c.Ty is not None: recv_ty_c: llvmlite.LLVMType* = recv_val_c.Ty if self.Gen.ExprGenBase.is_ptr_type(recv_ty_c) != 0: recv_ty_c = recv_ty_c.Pointee # 堆对象(@t.Object)双指针 → 再解一层取 struct if self.Gen.ExprGenBase.is_ptr_type(recv_ty_c) != 0: recv_ty_c = recv_ty_c.Pointee recv_cls_c: str = self.Gen.StructGen.get_class_name_by_type(pool, recv_ty_c) if recv_cls_c is not None: if self.Gen.CallGenProp._is_list_builtin_receiver(pool, recv_val_c, recv_cls_c, method_at.attr, cl) == 0: obj_ptr_c: llvmlite.Value* = recv_val_c if self.Gen.ExprGenBase.is_ptr_type(recv_val_c.Ty) != 0 and recv_val_c.Ty.Pointee != 0 and self.Gen.ExprGenBase.is_ptr_type(recv_val_c.Ty.Pointee) != 0: obj_ptr_c = llvmlite.build_load(builder, recv_val_c.Ty, recv_val_c) if obj_ptr_c is not None: if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, recv_cls_c, method_at.attr, obj_ptr_c, cl, trans) if method_at.value.kind() == ast.ASTKind.Name and trans is not None: method_obj_nm: ast.Name* = ast.Name*(method_at.value) if method_obj_nm.id is not None: # nonlocal 对象:提升函数内从 env 读对象指针(load_nonlocal_var), # 不能 lookup_var 跨函数命中父函数 alloca(SSA 编号错乱 → # llc "use of undefined value")。entry.get() 等方法调用的 # 基座对象经此路径解析(closure 隐式捕获场景)。 # 用 get_struct_type_from_value 递归解 Ptr,兼容 # Ptr(Struct)(load_nonlocal_var 已 load)与 # Ptr(Ptr(Struct))(联合简化未解引用)两种形态。 if GenApi.is_nonlocal_name(trans, method_obj_nm.id) != 0: nl_obj: llvmlite.Value* = self.Gen.StmtGenDecl.load_nonlocal_var(trans, method_obj_nm.id) if nl_obj is not None and nl_obj.Ty is not None: nl_deref: llvmlite.Value* = self.Gen.ExprGenBase._deref_if_ptr_ptr(builder, nl_obj) if nl_deref is None: nl_deref = nl_obj nl_struct: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(nl_deref) if nl_struct is not None: nl_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, nl_struct) if nl_cls is not None: if self.Gen.CallGenProp._is_list_builtin_receiver(pool, nl_deref, nl_cls, func_name, cl) == 0: if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, nl_cls, func_name, nl_deref, cl, trans) # 非 local 对象但分派未成功:绝不回退 lookup_var # (其 Alloca 是父函数存储,跨函数引用 → SSA 错乱), # 返回 None 让上层 fast-fail 暴露类型解析问题。 return None # 查找对象变量 obj_var: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, method_obj_nm.id) if obj_var is not None and obj_var.Ty is not None: # list 泛型容器注解先行识别(早期拦截,供下方各 class 分支共用):rawptr[list[rawptr[AST]]] 的 LLVM 形态为 Ptr(Ptr(Struct('list[sha.AST]'))),而 list 特化 struct 不注册为普通类,get_class_name_by_type 或返回 None、或后缀误命中内层元素类 ⇒ 下方两个 Ptr 分支的 list 内置拦截落空/错判。此处再兜底剥一次最外层 rawptr,内层以 'list' 开头且方法属 list 内置集合时置位 is_list_annot_builtin,交给本方法尾部 list 内置分支(内联 GEP)翻译 var_entry: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, method_obj_nm.id) is_list_annot_builtin: int = 0 la_buf: str = self.Gen.VarGen.var_annot_class_name(var_entry) if la_buf is not None: la_tail: str = la_buf if string.strncmp(la_buf, "rawptr[", 7) == 0: la_tail = la_buf + 7 if string.strncmp(la_tail, "list", 4) == 0: if self.Gen.CallGenProp._is_list_builtin_receiver(pool, obj_var, la_tail, func_name, cl) != 0: is_list_annot_builtin = 1 match obj_var.Ty: case llvmlite.LLVMType.Ptr(obj_struct_ty): class_nm: str = self.Gen.StructGen.get_class_name_by_type(pool, obj_struct_ty) if class_nm is not None: # list 泛型内置容器方法(append/get/set/pop/clear/__iter__/ # __len__/__getitem__/__setitem__)由下方 list 内置分支 # (L5848 起)内联 GEP 处理,不注册方法函数;若走 # _translate_method_call 会查 append 返回类型(函数/text.ll/ # vpi stub 均未命中)→ fail-fast。检测到 list 方法时 # 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。 # 注解兜底(is_list_annot_builtin=1)同跳过:class_nm # 可能被类型名后缀匹配错解为内层元素类,非 'list' 前缀 # 拦截会漏放 → 走 method_call/MRO fatal。 if self.Gen.CallGenProp._is_list_builtin_receiver(pool, obj_var, class_nm, func_name, cl) == 0 and is_list_annot_builtin == 0: if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, class_nm, func_name, obj_var, cl, trans) # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) # load 获取实际指针 Ptr(Struct) 后再查找 match obj_struct_ty: case llvmlite.LLVMType.Ptr(inner_struct_ty): inner_nm: str = self.Gen.StructGen.get_class_name_by_type(pool, inner_struct_ty) if inner_nm is not None: # list 内置方法同样跳过(同 Ptr(Struct) 分支); # 注解兜底(is_list_annot_builtin=1)同跳过: # inner_nm 也可能被后缀匹配错解为内层元素类。 if self.Gen.CallGenProp._is_list_builtin_receiver(pool, obj_var, inner_nm, func_name, cl) == 0 and is_list_annot_builtin == 0: obj_ptr: llvmlite.Value* = llvmlite.build_load(builder, obj_struct_ty, obj_var) if obj_ptr is not None: if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, inner_nm, func_name,obj_ptr, cl, trans) # FakeDuck: str/bytes 变量(Ptr(i8),AnnotClassName 为空) # 方法调用 → 扩展类 _Type/_str(a.type_id() / a.upper())。 # 前置拦截:常规结构体方法分支全落空时,尝试扩展类方法 # (find_func_in_module 未命中返回 None,不影响正常路径)。 # list 容器注解命中(is_list_annot_builtin=1)时跳过 FakeDuck: # 接收者非 str/bytes,此调用必须由尾部 list 内置分支翻译。 if is_list_annot_builtin == 0: fd_name_res: llvmlite.Value* = self.Gen.CallGenFd._translate_fakeduck_call(pool, builder, mod, None, func_name, cl, trans) if fd_name_res is not None: return fd_name_res # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, # 通过原始类型注解的类名查找结构体(var_entry 已在上方 # list 注解识别处查得,同一变量表项)。 # list 容器注解命中(is_list_annot_builtin=1)时跳过本回退: # 本回退的"剥模块前缀"会按内层元素 '.'(如 # list[rawptr[sha.AST]])把类名错切为 'AST]]' 垃圾 → 下方 # _is_list_builtin_method 前缀匹配不中 → 误走 FakeDuck/sha1 # 方法构造 → _translate_method_call MRO fatal。list 调用由 # 尾部 list 内置分支统一翻译。 annot_val: str = self.Gen.VarGen.var_annot_class_name(var_entry) if annot_val is not None and is_list_annot_builtin == 0: # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" dot_ptr: str = string.strrchr(annot_val, '.') cls_nm2: str = annot_val mod_nm2: str = None if dot_ptr is not None: cls_nm2 = dot_ptr + 1 total_len_av: sizet = string.strlen(annot_val) cls_len_av: sizet = string.strlen(cls_nm2) mod_len2: sizet = total_len_av - cls_len_av - 1 mod_nm2 = pool.alloc(mod_len2 + 1) if mod_nm2 is not None: string.strncpy(mod_nm2, annot_val, mod_len2) mod_nm2[mod_len2] = '\0' # 检查结构体是否已注册 if self.Gen.StructGen.get_struct_type(cls_nm2) is not None: # list 内置方法跳过 method_call(同 Ptr(Struct) 分支), # 落到下方 list 内置分支 if self.Gen.CallGenProp._is_list_builtin_receiver(pool, obj_var, cls_nm2, func_name, cl) == 0: # 结构体已注册:load obj_ptr 走方法调用 i8_ptr_ty2: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) obj_ptr2: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty2, obj_var) if obj_ptr2 is not None: if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, cls_nm2, func_name,obj_ptr2, cl, trans) else: # list 内置方法跳过(结构体未注册路径同样不能 # 构造 {sha1}.{cls}.append 调用名——list 方法无此函数) if self.Gen.CallGenProp._is_list_builtin_receiver(pool, obj_var, cls_nm2, func_name, cl) == 0: # FakeDuck: str 变量方法调用 → 扩展类 _Type/_str # a.type_id() / a.upper() / " ".isspace() 等 # AnnotClassName=="str" 且对象是 char* 时触发, # self 用影子结构体 {a}__meta__(或临时影子)。 fd_res: llvmlite.Value* = self.Gen.CallGenFd._translate_fakeduck_call(pool, builder, mod, cls_nm2, func_name, cl, trans) if fd_res is not None: return fd_res # 结构体未注册(跨模块依赖未翻译): # 用模块名查 SHA1 构造方法调用名 sha1_fc: str = None if mod_nm2 is not None: sha1_fc = self._lookup_module_sha1(mod_nm2) if sha1_fc is not None: # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 mlen3: sizet = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 mangled3: str = pool.alloc(mlen3) if mangled3 is not None: viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) # load obj_ptr (self) i8_ptr_ty3: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) obj_ptr3: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty3, obj_var) if obj_ptr3 is not None: # 构建参数链表: obj_ptr3 (self) → 其他参数 llvmlite.value_set_next(obj_ptr3, None) head3: llvmlite.Value* = obj_ptr3 tail3: llvmlite.Value* = obj_ptr3 for ai3 in range(can): arg3: ast.AST* = cargs.get(ai3) if arg3 is not None: arg_val3: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg3, None, 0, trans) if arg_val3 is not None: llvmlite.value_set_next(arg_val3, None) llvmlite.value_set_next(tail3, arg_val3) tail3 = arg_val3 total3: int = 1 + can ret_ty3: llvmlite.LLVMType* = self._special_method_ret_ty(pool, cls_nm2, func_name) if ret_ty3 is None: ret_ty3 = self._LookupMethodRetTyFromTextLL(pool, sha1_fc, cls_nm2, func_name) if ret_ty3 is None: # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) ret_ty3 = self._lookup_method_ret_ty_via_vpi(pool, sha1_fc, cls_nm2, func_name) if ret_ty3 is None: # 本分支仅在"注解类结构体未注册"时到达(L6932 else): # 类未注册 → 无法沿 MRO 解析 Mixin 方法定义模块。 # 例如 g 注解 Generator.Generator,但 _register_cdefine_from_value # 定义在 AssignGenMixin.vp——其 text.ll 的 define 名是 # {AssignGenMixin_sha1}.AssignGenMixin.xxx,查 # {Generator_sha1}.Generator.xxx 永远落空(追加80d 根因; # sha1_fc 存在 + text.ll 存在仍查不到,固定 256KB 截断 # 只是次要因素)。本遍保持默认类型,不在此 fail-fast。 # 依赖未就绪:保持默认 i32(build_call(Void) # 返回 None 破坏表达式翻译) ret_ty3 = llvmlite.Int32(pool) # 先按 vpi 定义侧形参 coerce 实参(宽度对齐),再建 declare head3 = self.Gen.CallGenLib._coerce_args_to_def_params(pool, builder, mangled3, head3, total3, cargs, 1, trans) self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) else: # 编译器生成特殊方法放行(__before_init__/__init__ 等): # 结构体未注册 + 模块 SHA1 均不可查(Phase A 依赖未就绪)时, # 方法返回类型由编译器确定性定义(_special_method_ret_ty), # 不依赖结构体注册即可精确解析。走 _translate_method_call 处理 # (内部含 _special_method_ret_ty + mc_entry/类型名 SHA1 提取), # 绝不掉出返回 None 让 translate_call 把对象名当模块名 # 报"跨模块调用 'buf.__before_init__' 找不到模块 SHA1" # (memhub.alloc_buf buf.__before_init__() 根因)。 sp_ty4: llvmlite.LLVMType* = self._special_method_ret_ty(pool, cls_nm2, func_name) if sp_ty4 is not None: i8_ptr_ty4: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) obj_ptr4: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty4, obj_var) if obj_ptr4 is not None: if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, cls_nm2, func_name, obj_ptr4, cl, trans) # ============================================================ # 检测表达式接收者方法调用: (expr).method(args) # # 当 method_at.value 是 BinOp/Subscript/Call 等非 Name/Attribute 表达式时 # (如 (a + b).dot(c)、(v1 + v2) * 3.0),先 translate_value 求值接收者, # 再从值的 LLVM 类型(Ptr(Struct))解析类名,走方法调用路径。 # ============================================================ if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: expr_method_at: ast.Attribute* = ast.Attribute*(cl.func) if expr_method_at is not None and expr_method_at.value is not None and trans is not None: evk: int = expr_method_at.value.kind() # Attribute 接收者区分两种形态: # 1. 模块限定路径(os._win32.exists / w32.fileio.fn)——根名是已导入 # 模块或 t/c,留给下方跨模块限定路径处理 # 2. 字段链表达式接收者(self.writer.write_bits / self.pool.alloc) # ——根名是对象(self/局部变量),必须走本方法调用路径; # 否则被模块限定路径误判 xmod_path="self.writer" → "找不到模块 # SHA1"(zdeflate.vp write_fixed_block 根因) is_mod_path_expr: int = 0 if evk == ast.ASTKind.Attribute: expr_root: ast.AST* = expr_method_at.value while expr_root is not None and expr_root.kind() == ast.ASTKind.Attribute: expr_root = ast.Attribute*(expr_root).value if expr_root is not None and expr_root.kind() == ast.ASTKind.Name: expr_root_nm: str = ast.Name*(expr_root).id if expr_root_nm is not None: if string.strcmp(expr_root_nm, "t") == 0 or string.strcmp(expr_root_nm, "c") == 0: is_mod_path_expr = 1 elif trans._imported_modules is not None: if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, expr_root_nm) != 0: is_mod_path_expr = 1 if evk != ast.ASTKind.Name and is_mod_path_expr == 0: # 翻译接收者表达式(求值结果应为 Ptr(Struct)) expr_obj: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans) if expr_obj is not None and expr_obj.Ty is not None: expr_cls_nm: str = None # 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct)) # (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法 # 调用被当裸函数 @dot 解析 → 链接 undefined symbol expr_struct_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(expr_obj) if expr_struct_ty is not None: expr_cls_nm = self.Gen.StructGen.get_class_name_by_type(pool, expr_struct_ty) # 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时, # 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...) # 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解) # 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例 if expr_cls_nm is None: expr_cls_nm = self.Gen.ExprGenCls.infer_expr_class(pool, mod, expr_method_at.value, trans) if expr_cls_nm is not None: # 值类型接收者(内嵌 struct 字段,如 zdeflate s.writer 值字段): # 方法调用 self 必须传字段地址(GEP)而非 load 出的结构体值, # 否则结构体值(40B)塞进 zbit_writer* 参数 → ABI 错配 → # 被调方把值当 this 指针解引用 → GEP 0x18 崩溃 # (s.writer.write_zlib_header 运行时 access-violation 根因; # 本路径 evk=Attribute 先于 self.field.method() 分支命中)。 expr_is_ptr: int = 0 match expr_obj.Ty: case llvmlite.LLVMType.Ptr(expr_ptr_inner): expr_is_ptr = 1 case _: expr_is_ptr = 0 if expr_is_ptr == 0: expr_addr: llvmlite.Value* = self.Gen.ExprGenAttr.get_attribute_ptr(builder, pool, mod, expr_method_at.value, trans) if expr_addr is not None: expr_obj = expr_addr if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, expr_cls_nm, func_name, expr_obj, cl, trans) # FakeDuck: 表达式接收者解析失败且对象是 char* 时 # (如 " ".isspace()),尝试扩展类 _Type/_str 方法 # (self 用临时影子,对齐 TPC L2858-2873) fd_expr_res: llvmlite.Value* = self.Gen.CallGenFd._translate_fakeduck_call(pool, builder, mod, None, func_name, cl, trans) if fd_expr_res is not None: return fd_expr_res # ============================================================ # 检测 self.field.method() 调用 # # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, # 翻译字段值获取对象指针,然后走方法调用路径。 # # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) # ============================================================ if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: attr_method_at: ast.Attribute* = ast.Attribute*(cl.func) if attr_method_at is not None and attr_method_at.value is not None: if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: inner_attr: ast.Attribute* = ast.Attribute*(attr_method_at.value) if inner_attr is not None and inner_attr.attr is not None: # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) field_obj: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) if field_obj is not None and field_obj.Ty is not None: field_cls_nm: str = None # 路径1: 从字段值的 LLVM 类型获取类名 match field_obj.Ty: case llvmlite.LLVMType.Ptr(field_struct_ty): field_cls_nm = self.Gen.StructGen.get_class_name_by_type(pool, field_struct_ty) # 路径2: 从字段注解类名回退查找 if field_cls_nm is None: if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: inner_name_node: ast.Name* = ast.Name*(inner_attr.value) if inner_name_node is not None and inner_name_node.id is not None: inner_var: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, inner_name_node.id) if inner_var is not None and inner_var.Ty is not None: match inner_var.Ty: case llvmlite.LLVMType.Ptr(field_owner_struct_ty): field_info: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(field_owner_struct_ty, inner_attr.attr) if field_info is not None: field_annot: str = self.Gen.StructGen.get_field_annot_class_name(field_info) if field_annot is not None: dot_p: str = string.strrchr(field_annot, 46) if dot_p is not None: field_cls_nm = dot_p + 1 else: field_cls_nm = field_annot if field_cls_nm is not None: # 值类型字段(内嵌 struct,如 zdeflate_stream.writer: zbit_writer) # 方法调用 self 必须传字段地址(GEP),而非 load 出的结构体值: # 传值给 stub 声明/define 的 zbit_writer* 参数 → ABI 错配, # 被调方把结构体值前 8 字节当 this 指针解引用 → GEP 0x18 崩溃 # (zdeflate s.writer.write_zlib_header 运行时 access-violation 根因)。 is_val_field: int = 0 match field_obj.Ty: case llvmlite.LLVMType.Ptr(field_ptr_inner): is_val_field = 0 case _: is_val_field = 1 if is_val_field != 0: field_addr: llvmlite.Value* = self.Gen.ExprGenAttr.get_attribute_ptr(builder, pool, mod, attr_method_at.value, trans) if field_addr is not None: field_obj = field_addr if hit_box is not None: hit_box[0] = 1 return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, field_cls_nm, func_name, field_obj, cl, trans) # ============================================================ # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, # 需要在此特殊处理。 # list 结构布局 (6 字段 × 8 字节): # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) # ============================================================ if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: lm_at: ast.Attribute* = ast.Attribute*(cl.func) if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: lm_name: str = lm_at.attr # 判断是否是 list 方法名 lm_is_list: int = 0 if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 if lm_is_list == 1 and trans is not None: # 翻译 list 对象 lm_obj: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) if lm_obj is not None: # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) # 可能返回 i32 0 (非指针),直接 GEP 会导致 # "base of getelementptr must be a pointer" 错误 if lm_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(lm_obj.Ty) == 0: # translate_value 类型推断失败(目标对象非指针): # fail-fast,绝不 VLogger.critical 后 return None 静默吞掉 self.Gen.TypeGenErr.fatal_error(lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError") # list 对象类型确认(额外搜索路径):list 内置分支仅按方法名 # 判断(get/set/__getitem__ 等非 list 专有),须确认对象确实 # 是 list——从对象结构体名匹配 "list"。明确非 list(如 dict / # 普通类未注册场景)跳过本分支,避免按 list 布局 GEP 生成 # 错误 IR(dict 的 get 被当 list.get 按 __data__/__elem_size__ # 偏移读写垃圾)。 lm_conf_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj) lm_conf_nm: str = None if lm_conf_ty is not None: lm_conf_nm = llvmlite.get_struct_name(lm_conf_ty) # [S4] 容器基名**精确**比较:此处读的是 LLVM 注册名,含模块 sha1 # 前缀(如 "e94ef9e139461915.list[ast.ASTptr]");SpecTypeNameBaseIs # 会去前缀、截断泛型实参后精确比 "list"(原 strstr 子串会误命中 # playlist 之类的类名)。 if lm_conf_nm is not None and TSpec.SpecTypeNameBaseIs(lm_conf_nm, "list") == 0: return None # list 内置分支命中标记:void 方法(set/clear)成功处理后返回 # None,必须置位 hit_box 区分"已识别为 list 方法路径",否则 # translate_call 误判未命中继续走跨模块函数路径,把对象名当 # 模块名查 SHA1 → "跨模块调用 'nums.set' 找不到模块 SHA1" # (ListTest main.vp nums.set(1,99) 根因;对齐 _translate_method_call # 调用点的 hit_box 置位模式)。 if hit_box is not None: hit_box[0] = 1 i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool) i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty) # 元素类型 T:从 list 特化类型名解析(list[int]→i32、 # list[str]→i8*、未知/指针元素→i8*)。此前 get/set/pop # 固定 i8*(8 字节)读写:set 的 8 字节 store 覆盖相邻元素 # (inttoptr 值,如 set(1,99) 把 data[8..11] 的 30 清 0), # pop 读回 0 → ListTest "pop FAILED expect 30" 根因。 # subscript 路径(list_getitem_inline 调用方)已用 # _list_elem_type_from_name 修正,方法调用路径漏改。 lm_esty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj) lm_ename: str = None if lm_esty is not None: lm_ename = llvmlite.get_struct_name(lm_esty) lm_elem_ty: llvmlite.LLVMType* = None if lm_ename is not None: lm_elem_ty = self.Gen.ExprGenName._list_elem_type_from_name(pool, lm_ename) if lm_elem_ty is None: lm_elem_ty = i8_ptr_ty # get / __getitem__: 返回 index 处的元素 if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: if can >= 1: # 加载 __data__ (偏移 0) g_idx0: llvmlite.Value* = llvmlite.const_int64(pool, 0) g_dpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) g_data: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) # 加载 __elem_size__ (偏移 32, index 4) g_idx4: llvmlite.Value* = llvmlite.const_int64(pool, 4) g_epp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) g_esize: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, g_epp) # 翻译 index g_idx_node: ast.AST* = cargs.get(0) g_idx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, g_idx_node, None, 0, trans) if g_data is not None and g_esize is not None and g_idx_val is not None: g_idx_i64: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, g_idx_val, i64_ty, g_idx_node) g_offset: llvmlite.Value* = llvmlite.build_mul(builder, g_idx_i64, g_esize) g_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) if g_addr is not None: g_ep: llvmlite.Value* = llvmlite.build_bitcast(builder, g_addr, llvmlite.Ptr(pool, lm_elem_ty)) if g_ep is not None: return llvmlite.build_load(builder, lm_elem_ty, g_ep) # set / __setitem__: 设置 index 处的元素 elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: if can >= 2: s_idx0: llvmlite.Value* = llvmlite.const_int64(pool, 0) s_dpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) s_data: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) s_idx4: llvmlite.Value* = llvmlite.const_int64(pool, 4) s_epp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) s_esize: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, s_epp) s_idx_node: ast.AST* = cargs.get(0) s_val_node: ast.AST* = cargs.get(1) s_idx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, s_idx_node, None, 0, trans) s_val_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, s_val_node, None, 0, trans) if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: s_idx_i64: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_idx_val, i64_ty, s_idx_node) s_offset: llvmlite.Value* = llvmlite.build_mul(builder, s_idx_i64, s_esize) s_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) if s_addr is not None: s_val_elem: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_val_val, lm_elem_ty, s_val_node) s_ep: llvmlite.Value* = llvmlite.build_bitcast(builder, s_addr, llvmlite.Ptr(pool, lm_elem_ty)) if s_ep is not None: llvmlite.build_store(builder, s_val_elem, s_ep) return None # pop: 返回最后一个元素,count-- elif string.strcmp(lm_name, "pop") == 0: p_idx1: llvmlite.Value* = llvmlite.const_int64(pool, 1) p_cpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) p_count: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, p_cpp) p_nc: llvmlite.Value* = llvmlite.build_sub(builder, p_count, llvmlite.const_int64(pool, 1)) llvmlite.build_store(builder, p_nc, p_cpp) p_idx0: llvmlite.Value* = llvmlite.const_int64(pool, 0) p_dpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) p_data: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) p_idx4: llvmlite.Value* = llvmlite.const_int64(pool, 4) p_epp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) p_esize: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, p_epp) if p_data is not None and p_esize is not None and p_nc is not None: p_offset: llvmlite.Value* = llvmlite.build_mul(builder, p_nc, p_esize) p_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) if p_addr is not None: p_ep: llvmlite.Value* = llvmlite.build_bitcast(builder, p_addr, llvmlite.Ptr(pool, lm_elem_ty)) if p_ep is not None: return llvmlite.build_load(builder, lm_elem_ty, p_ep) # clear: count = 0 elif string.strcmp(lm_name, "clear") == 0: c_idx1: llvmlite.Value* = llvmlite.const_int64(pool, 1) c_cpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp) return None # __iter__: iter_index = 0, return self elif string.strcmp(lm_name, "__iter__") == 0: it_idx5: llvmlite.Value* = llvmlite.const_int64(pool, 5) it_ipp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp) return lm_obj # append: 直接调用 list.append(self, item) # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 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(元素永远不会被加入列表) self.Gen.TypeGenErr.fatal_error(cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", "InternalCompilerError") if ap_sha1 is not None: # 特化类名提取:list.append 的符号名是 # {sha1}.list[AST|CPtr].append(带类型参数特化名), # 而非 {sha1}.list.append。lm_obj 类型即特化结构体 # Ptr(list[AST|CPtr]),从类型解析特化类名拼接调用名, # 否则 ld.lld undefined symbol(定义端是特化名)。 ap_spec_nm: str = None ap_struct_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj) if ap_struct_ty is not None: ap_spec_nm = self.Gen.StructGen.get_class_name_by_type(pool, ap_struct_ty) if ap_spec_nm is None: ap_spec_nm = "list" # 触发泛型特化翻译(幂等,MethodsEmitted 防重入): # list[AST|CPtr].append 的 define 方法体在特化类翻译时 # 生成。仅构造调用名不触发特化会导致定义缺失 # (ld.lld undefined symbol: list[AST|CPtr].append)。 if trans is not None and ap_spec_nm is not None: lbkt_ap: str = string.strchr(ap_spec_nm, '[') if lbkt_ap is not None: rbkt_ap: str = string.strrchr(ap_spec_nm, ']') if rbkt_ap is not None and rbkt_ap > lbkt_ap: base_len_ap: sizet = sizet(uint64(lbkt_ap) - uint64(ap_spec_nm)) arg_len_ap: sizet = sizet(uint64(rbkt_ap) - uint64(lbkt_ap) - 1) if base_len_ap > 0 and arg_len_ap > 0: base_buf_ap: str = pool.alloc(base_len_ap + 1) arg_buf_ap: str = pool.alloc(arg_len_ap + 1) if base_buf_ap is not None and arg_buf_ap is not None: string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap) base_buf_ap[base_len_ap] = '\0' string.strncpy(arg_buf_ap, lbkt_ap + 1, arg_len_ap) arg_buf_ap[arg_len_ap] = '\0' args_ap: list[str]* = list[str](pool, 8) if args_ap is not None: # 逗号分隔多类型实参(list[X] / dict[K, V]) cur_ap: str = arg_buf_ap while cur_ap is not None: comma_ap: str = string.strchr(cur_ap, ',') if comma_ap is None: args_ap.append(cur_ap) break seg_len_ap: sizet = sizet(uint64(comma_ap) - uint64(cur_ap)) seg_buf_ap: str = pool.alloc(seg_len_ap + 1) if seg_buf_ap is not None: string.strncpy(seg_buf_ap, cur_ap, seg_len_ap) seg_buf_ap[seg_len_ap] = '\0' args_ap.append(seg_buf_ap) cur_ap = comma_ap + 1 self.Gen.ClassGenGeneric._specialize_generic_class(trans, base_buf_ap, args_ap) # 调用名 "{sha1}.{spec}.append": # sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25。 # 此前 +8 少 1 字节,snprintf 截断末尾 'd' → # undefined symbol: ...list[AST|CPtr].appen(缺 d)。 ap_mlen: sizet = string.strlen(ap_sha1) + string.strlen(ap_spec_nm) + 26 ap_mangled: str = pool.alloc(ap_mlen) if ap_mangled is not None: viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append", ap_sha1, ap_spec_nm) ap_item_node: ast.AST* = cargs.get(0) ap_item_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, ap_item_node, None, 0, trans) if ap_item_val is not None: llvmlite.value_set_next(lm_obj, None) llvmlite.value_set_next(ap_item_val, None) llvmlite.value_set_next(lm_obj, ap_item_val) ap_ret_ty: llvmlite.LLVMType* = llvmlite.Int32(pool) self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2) return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) return None