fix(gentype): c.Deref 类型推断支持转换包裹与联合全 side

_infer_deref_target_type 仅在 Deref 为赋值直接 RHS 时推断加载类型,
被类型转换链包裹(如 (T | t.CPtr)(t.CPtr(c.Deref(p))))时返回 None →
回退 load 1 字节 → 读回垃圾指针(BuildPipeline run_llc_parallel 存
Thread* 后 join/is_alive 失效、llc 并行 5 秒误报失败的根因)。
增强:新增 _IsCastWrappingDeref 放行"转换链包裹 Deref"(ifexp/binop
仍不放行);联合注解(A | B)遍历全部 side,取第一个可解析类型。
This commit is contained in:
TermiNexus committed 2026-08-19 21:14:13 +08:00
1 parent 0db1ccd1bb
commit e82640ac94
1 file changed
+52 -25
+52 -25
View File
@@ -12,6 +12,30 @@ from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
def _IsTypeExpr(node: ast.AST | None) -> bool:
"""判断 AST 节点是否为类型表达式(类型转换的目标,如 Name/Attribute/Subscript/BinOp|)"""
return (
isinstance(node, ast.Name)
or isinstance(node, ast.Attribute)
or isinstance(node, ast.Subscript)
or (isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr))
)
def _IsCastWrappingDeref(rhs: ast.AST | None, deref_node: ast.Call) -> bool:
"""判断 rhs 是否为"类型转换链包裹 c.Deref"(如 (T | t.CPtr)(t.CPtr(c.Deref(p))))。
允许在 c.Deref 处于类型转换调用链中时仍从赋值注解推断加载类型;
ifexp/compare/binop 包裹(非转换调用)不放行,避免把 i8* 错 bitcast 成
其他位宽加载(见 _infer_deref_target_type 文档)。
"""
if rhs is deref_node:
return True
if isinstance(rhs, ast.Call) and len(rhs.args) == 1 and _IsTypeExpr(rhs.func):
return _IsCastWrappingDeref(rhs.args[0], deref_node)
return False
class CSpecialCallHandle(BaseHandle):
def _HandleCIfLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
@@ -261,46 +285,49 @@ class CSpecialCallHandle(BaseHandle):
def _infer_deref_target_type(self, Gen: LlvmGeneratorMixin, DerefNode: ast.Call | None = None) -> ir.Type | None:
"""从当前赋值上下文推断 c.Deref 的目标加载类型。
当用户写 v: int = c.Deref(ptr) 时,从赋值注解推断目标类型。
注意:仅当 c.Deref 是赋值的直接 RHS 时才推断;若 c.Deref 嵌套在
注意:仅当 c.Deref 是赋值的直接 RHS,或 RHS 是类型转换链包裹
(如 `(T | t.CPtr)(t.CPtr(c.Deref(p)))`)时才推断;若 c.Deref 嵌套在
ifexp/compare/binop 中(如 `a = 1 if c.Deref(p) == 65 else 0`),
不应推断,否则会把 i8* 错误 bitcast 为 i32* 加载 4 字节。"""
assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None)
if not assign_node:
return None
# 仅当 c.Deref 是赋值的直接 RHS 时才推断类型
if DerefNode is not None and getattr(assign_node, 'value', None) is not DerefNode:
return None
# 仅当 c.Deref 是赋值的直接 RHS 或处于类型转换链中时才推断类型
if DerefNode is not None:
rhs: ast.AST | None = getattr(assign_node, 'value', None)
if rhs is not DerefNode and not _IsCastWrappingDeref(rhs, DerefNode):
return None
ann: ast.AST | None = getattr(assign_node, 'annotation', None)
if not ann:
return None
ann_name: str | None = None
# 收集候选类型名:Name / Attribute / 联合 BinOp| 的所有 side。
# 逐个尝试解析,取第一个能解析为 LLVM 类型的(如
# `vthreading.Thread | t.CPtr` → 'Thread' 未注册 → 'CPtr' → i8*)。
candidates: list[str] = []
if isinstance(ann, ast.Name):
ann_name = ann.id
candidates.append(ann.id)
elif isinstance(ann, ast.Attribute):
ann_name = ann.attr
candidates.append(ann.attr)
elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
# 处理 int | t.CPtr 形式的联合类型注解
for side in (ann.left, ann.right):
if isinstance(side, ast.Name):
ann_name = side.id
break
candidates.append(side.id)
elif isinstance(side, ast.Attribute):
ann_name = side.attr
break
if not ann_name:
return None
# 使用 BuiltinTypeMap 统一查询(同时支持 Python 类名和字符串速记)
entry: tuple[type, int] | None = BuiltinTypeMap.Get(ann_name)
if entry is not None:
ctype_cls: type = entry[0]
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str:
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if resolved:
return resolved
# 检查是否是已注册的结构体类型
if ann_name in Gen.structs:
return Gen.structs[ann_name]
candidates.append(side.attr)
for ann_name in candidates:
# 使用 BuiltinTypeMap 统一查询(同时支持 Python 类名和字符串速记)
entry: tuple[type, int] | None = BuiltinTypeMap.Get(ann_name)
if entry is not None:
ctype_cls: type = entry[0]
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str:
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if resolved:
return resolved
# 检查是否是已注册的结构体类型
if ann_name in Gen.structs:
return Gen.structs[ann_name]
return None
def _HandleCPtrToIntLlvm(self, Node: ast.Call) -> ir.Value: