diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index d3018e0..a88ad38 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -6102,7 +6102,38 @@ class CallGenMixin: if found_ret_ty is not None: call_ret_ty: llvmlite.LLVMType | t.CPtr = found_ret_ty else: - call_ret_ty = self._infer_external_func_ret_ty(pool, func_name) + # found_func=None(跨模块 stub 未注入):先从 vpi stub 返回注解 + # 缓存精确获取返回类型(含 tuple[T1,T2] → 匿名结构体,如 + # b2a_hqx -> tuple[str, t.CUnsignedShort] → {i8*, i16}), + # 未命中才回退 _infer_external_func_ret_ty 白名单推断。 + # 根因:_infer 白名单无 tuple 概念,未知函数默认 i32 会截断 + # 指针/i64;b2a_hqx 被推断为单值 i8*/i32 后调用侧返回值类型 + # 与定义侧 {i8*, i16} 不匹配 → HandlesAssign 的 tuple 解包 + # (依赖 rhs_val.Ty 是 Struct)静默跳过 → 目标变量从未赋值 → + # free 未初始化栈垃圾指针崩溃(HashLibTest hqx 段)。 + vpi_ret_ty: llvmlite.LLVMType | t.CPtr = None + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_ret: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_ret.value is not None and at_ret.value.kind() == ast.ASTKind.Name: + mod_ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_ret.value) + if mod_ret_nm.id is not None: + mod_ret_sha1: str = self._lookup_module_sha1(mod_ret_nm.id) + if mod_ret_sha1 is not None: + # 函数内懒 import:VpiReader imports HandlesExprCall, + # 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致) + import lib.StubGen.VpiReader as VpiReader + VpiReader._ensure_vpi_ret_annot_loaded(mod_ret_sha1, self.TempDir) + ret_annot_fc: str = VpiReader._lookup_vpi_ret_annot( + mod_ret_sha1, None, func_name) + if ret_annot_fc is not None: + vpi_ret_ty = VpiReader._resolve_vpi_ret_annot_str( + pool, ret_annot_fc, + llvmlite.Int32(pool), + llvmlite.Ptr(pool, llvmlite.Int8(pool))) + if vpi_ret_ty is not None: + call_ret_ty = vpi_ret_ty + else: + call_ret_ty = self._infer_external_func_ret_ty(pool, func_name) # 如果模块中找不到函数,检查是否是变量(函数指针 / 闭包调用) if found_func is None: diff --git a/App/lib/core/Gen/TypeGenMixin.vp b/App/lib/core/Gen/TypeGenMixin.vp index 902f5e6..bf050f2 100644 --- a/App/lib/core/Gen/TypeGenMixin.vp +++ b/App/lib/core/Gen/TypeGenMixin.vp @@ -1955,6 +1955,42 @@ class TypeGenMixin: if sub.value.kind() == ast.ASTKind.Name: gen_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) if gen_nm.id is not None: + # 裸名 CArray(from t import * 场景,如 core.vp 的 + # `__python_suffix__: CArray[str] = ["py", ...]`):与 t.CArray + # 语义等价。否则走泛型模板查找失败(CArray 不是泛型类模板)→ + # 字段类型退化 Ptr(i8) → __before_init__ 默认值 List 字面量误走 + # 动态 list 构造(list[str].__new__/append 符号未生成 → 链接 + # undefined reference,Termination4K3 链接失败根因)。 + if string.strcmp(gen_nm.id, "CArray") == 0: + # 单参数: CArray[elem_ty] → Ptr(elem_ty)(静态推导长度数组) + if sub.slice.kind() != ast.ASTKind.Tuple: + elem_n: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, sub.slice, imported_modules, from_imports, trans) + if elem_n is None: + return None + return llvmlite.Ptr(pool, elem_n) + # 双参数: CArray[elem_ty, count] → [count x elem_ty] + tup_n: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + if tup_n.elts is None or tup_n.elts.__len__() < 2: + return None + elem_node_n: ast.AST | t.CPtr = tup_n.elts.get(0) + count_node_n: ast.AST | t.CPtr = tup_n.elts.get(1) + if elem_node_n is None or count_node_n is None: + return None + elem_ty_n: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, elem_node_n, imported_modules, from_imports, trans) + if elem_ty_n is None: + return None + # count=None → Ptr(elem)(等价单参) + if count_node_n.kind() == ast.ASTKind.Constant: + cnt_n: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(count_node_n) + if cnt_n.const_kind == ast.CONST_NONE: + return llvmlite.Ptr(pool, elem_ty_n) + count_n: int = self._eval_const_int_expr( + count_node_n, pool, from_imports, imported_modules) + if self.ConstEvalOk == 0 or count_n <= 0: + return None + return llvmlite.Array(pool, elem_ty_n, count_n) return self._resolve_generic_subscript_ty(pool, sub, gen_nm.id, trans, imported_modules, from_imports) # 检查 value 是否是 Attribute(t.CArray / t.Callable / 模块限定泛型类如 numpy.ndarray[T]) diff --git a/App/lib/core/Handles/HandlesAnnAssign.vp b/App/lib/core/Handles/HandlesAnnAssign.vp index f73ff44..22c3ba3 100644 --- a/App/lib/core/Handles/HandlesAnnAssign.vp +++ b/App/lib/core/Handles/HandlesAnnAssign.vp @@ -171,23 +171,35 @@ def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int: # "单参数 list[type] → 指针,但如果有列表字面量初始化值则按数组 list[type, N] 处理")。 # ============================================================ def _is_single_param_carray_annot(annot: ast.AST | t.CPtr) -> int: - """检查注解是否为单参/None 长度 t.CArray[...],返回 1=是 0=否""" + """检查注解是否为单参/None 长度 t.CArray[...],返回 1=是 0=否 + + 支持两种书写形式: + 1. 模块限定 t.CArray[...](Attribute value) + 2. 裸名 CArray[...](from t import * 后使用,如 Termination4K3 core.vp + 的 `__python_suffix__: CArray[str] = ["py", ...]`) + """ if annot is None or annot.kind() != ast.ASTKind.Subscript: return 0 sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) if sub.value is None or sub.slice is None: return 0 - if sub.value.kind() != ast.ASTKind.Attribute: + if sub.value.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) + if at.attr is None or string.strcmp(at.attr, "CArray") != 0: + return 0 + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return 0 + mv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mv.id is None or string.strcmp(mv.id, "t") != 0: + return 0 + elif sub.value.kind() == ast.ASTKind.Name: + # 裸名 CArray(from t import *):与 t.CArray 等价 + bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if bn.id is None or string.strcmp(bn.id, "CArray") != 0: + return 0 + else: return 0 - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) - if at.attr is None or string.strcmp(at.attr, "CArray") != 0: - return 0 - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return 0 - mv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mv.id is None or string.strcmp(mv.id, "t") != 0: - return 0 - # 单参形式:slice 非 Tuple(如 t.CArray[u64]) + # 单参形式:slice 非 Tuple(如 t.CArray[u64] / CArray[str]) if sub.slice.kind() != ast.ASTKind.Tuple: return 1 # 双参形式:count=None(t.CArray[u64, None])→ 等价单参