fix(tpc): 跨模块模块级变量类登记与 Mod.Var.Field 链解析;并停止跟踪 __pycache__/*.pyc

This commit is contained in:
TermiNexus committed 2026-09-12 11:51:42 +08:00
1 parent 9257dd841f
commit 015fbf17cf
100 files changed
+237 -1

No files matched your search

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+22
View File
@@ -639,6 +639,28 @@ class BaseHandle:
struct_keys: list[str] = [k for k in (getattr(Gen, 'structs', {}) or {})
if _short(k) == _short(cn)]
seg.append(f"structs_keys={struct_keys or 'NONE'}")
# 模块别名链(Mod.Var.Field,如 CompilerFactory.factory.PermPool):
# 最内层 Name 是**模块名**,上面的登记 dump(var_struct_class 等)对它
# 恒为 None、无法定位断点。补逐跳诊断:Mod 的 sha1、`Mod.Var` 在全局量表
# 里的候选键命中与类型,直接指出断在哪一跳。
_chain: list[str] = []
_cur: ast.AST = Node
while isinstance(_cur, ast.Attribute):
_chain.append(_cur.attr)
_cur = _cur.value
_chain.reverse()
if _chain:
_sha1_map2: Any = getattr(Gen, 'ModuleSha1Map', {}) or {}
_gmap: Any = getattr(getattr(Gen, 'module', None), 'globals', {}) or {}
_mod_sha: Any = _sha1_map2.get(var)
seg.append(f"chain={var}.{'.'.join(_chain)} ModuleSha1Map[{var}]={_mod_sha!r}")
_hop: str = _chain[0]
_keys: list[str] = [f"{var}.{_hop}", _hop]
if _mod_sha:
_keys.append(f"{_mod_sha}.{_hop}")
for _k in _keys:
if _k in _gmap:
seg.append(f"globals[{_k}]={_ty_str(_gmap[_k])}")
return '\n'.join(seg)
except Exception:
return ''
+35 -1
View File
@@ -891,7 +891,41 @@ class ExprCallHandle(BaseHandle):
if ModulePath and IsKnown:
raise Exception(f"Undefined symbol: '{ModulePath}.{FuncAttr}'")
if ModulePath and ModulePath not in {'t', 'c'} and not IsKnown:
raise Exception(f"Unknown module: '{ModulePath}' (undefined symbol: '{ModulePath}.{FuncAttr}')")
# 诊断增强:这条 raise 会把「接收者链上方法分派失败」误报成
# "Unknown module",掩盖真因(factory.PermPool.alloc 排查现场)。
# 附接收者链的类名解析结果 + 该类是否有目标成员/函数,一次定位:
# receiver_class=None → 链的类名解析仍断(见 _get_var_class)
# has_func/field_member=False → 类名对了但方法符号不存在
_rc_cls: str | None = None
try:
_rc_cls = self.Trans.ExprHandler._get_var_class(Node.func.value, Gen)
except Exception:
_rc_cls = None
_rc_note: str = f", receiver_class={_rc_cls!r}"
if _rc_cls:
_rc_bare: str = _rc_cls.split('.')[-1]
_rc_note += f", has_func={Gen._has_function(f'{_rc_cls}.{FuncAttr}')}"
_rc_note += (", field_member="
f"{bool([m for m, _ in (Gen.class_members.get(_rc_bare) or []) if m == FuncAttr])}")
# receiver_class=None 时,把第一跳(Mod.Var 的 Var)登记现场打出来
_hops: list = []
_cn: ast.AST = Node.func.value
while isinstance(_cn, ast.Attribute):
_hops.append(_cn.attr)
_cn = _cn.value
if isinstance(_cn, ast.Name):
_hops.append(_cn.id)
_hops.reverse()
if len(_hops) >= 2:
_h1 = _hops[1]
_vsc2 = getattr(Gen, 'var_struct_class', {}) or {}
_gsc2 = getattr(Gen, 'global_struct_class', {}) or {}
_gmap2 = getattr(getattr(Gen, 'module', None), 'globals', {}) or {}
_rc_note += (f", chain={'.'.join(_hops)}, hop1={_h1!r}"
f", vsc={_vsc2.get(_h1)!r}, gsc={_gsc2.get(_h1)!r}"
f", globals_suffix={[k for k in _gmap2 if k.endswith('.' + _h1)]}")
raise Exception(f"Unknown module: '{ModulePath}' (undefined symbol: "
f"'{ModulePath}.{FuncAttr}'){_rc_note}")
if not ModulePath and FuncAttr:
raise Exception(f"Undefined method: '{FuncAttr}'")
return MethodResult if MethodResult is not None else ir.Constant(ir.IntType(32), 0)
+90
View File
@@ -48,6 +48,12 @@ class ExprUtils:
BaseClass: str | None = self._get_var_class(node.value, Gen)
if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self':
BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
if not BaseClass:
# 【模块别名 + 模块级变量】`Mod.Var` 形态(如 CompilerFactory.factory):
# var_struct_class 只登记**当前模块**变量,跨模块量不在其中 → 递归到此
# 返回 None → 整条链 `Mod.Var.Field` 解析为空 → 赋值/调用 fail-fast
# ("属性访问未能解析出目标类型/成员",StructGenMixin.vp:139 根因)。
BaseClass = self._resolve_module_var_class(Gen, node.value, AttrName)
if BaseClass:
# 对齐 _HandleLenLlvm L3445-3454:class_member_element_class /
# class_members 的键是裸类名,而 var_struct_class 可能带 sha1 前缀
@@ -86,6 +92,90 @@ class ExprUtils:
return None
return None
def _resolve_module_var_class(self, Gen: LlvmCodeGenerator, ModNode: ast.AST,
AttrName: str) -> str | None:
"""`模块别名.模块级变量` 的类名解析(如 CompilerFactory.factory)
背景:`CompilerFactory.factory.PermPool` 这类链的第一跳既不在
`var_struct_class`(只含当前模块变量)也不在 `global_struct_class`
(只含按变量名登记的项),于是 `_get_var_class` 递归到底返回 None →
整条链解析为空 → 赋值/调用 fail-fast("属性访问未能解析出目标类型/成员")。
这里按模块别名把 `Mod.Var` 落到其 LLVM 全局量,再从全局量类型反推结构体
类名;候选键形态对齐 `_lookup_module_global`(裸名 / {mod}.{var} /
{sha1}.{var})。仅当 ModNode 确为 import 模块(含别名)时生效。
"""
if not isinstance(ModNode, ast.Name):
return None
Mod: str = ModNode.id
imported: Any = getattr(self.Trans, '_ImportedModules', None) or []
sha1_map: Any = getattr(Gen, 'ModuleSha1Map', {}) or {}
try:
resolved_mod: str = self.Trans.SymbolTable.resolve_alias(Mod)
except Exception:
resolved_mod = Mod
aliases: Any = getattr(self.Trans.SymbolTable, 'import_aliases', {}) or {}
_is_mod: bool = (Mod in imported or resolved_mod in imported
or Mod in sha1_map or resolved_mod in sha1_map
or Mod in aliases or resolved_mod in aliases)
if not _is_mod:
# 兜底:ModuleSha1Map 的键多为全路径(lib.core.CompilerFactory),
# 用后缀扫描判定「Mod 是否确实是某个已导入模块(含别名)」。
for _k in sha1_map:
if _k == Mod or _k.endswith(f'.{Mod}'):
_is_mod = True
break
if not _is_mod:
return None
# 1) 变量名侧已有登记(stub 解析时跨模块量常以**裸变量名**登记)
gsc: Any = getattr(Gen, 'global_struct_class', {}) or {}
vsc: Any = getattr(Gen, 'var_struct_class', {}) or {}
for key in (f"{Mod}.{AttrName}", f"{resolved_mod}.{AttrName}", AttrName):
if key in gsc:
return gsc[key]
if key in vsc:
return vsc[key]
# 2) 借属性侧既有解析器(覆盖 module.globals/variables 与前缀形态)
try:
_via_attr: str | None = self.Trans.ExprAttrHandle._resolve_var_classname(Gen, AttrName)
except Exception:
_via_attr = None
if _via_attr:
return _via_attr
# 3) 从 LLVM 全局量类型反推结构体类名
cands: list[str] = [f"{Mod}.{AttrName}", AttrName]
for m in imported:
if m == Mod or m.endswith(f".{Mod}"):
k: str = f"{m}.{AttrName}"
if k not in cands:
cands.append(k)
for cand in (Mod, resolved_mod):
sha1: str | None = sha1_map.get(cand)
if sha1:
k2: str = f"{sha1}.{AttrName}"
if k2 not in cands:
cands.append(k2)
globals_map: Any = getattr(getattr(Gen, 'module', None), 'globals', {}) or {}
# 3b) 后缀扫描:全局量键常为 "{sha1}.{var}",sha1 不一定能从 Mod 反查到
for _gk in globals_map:
if _gk.endswith(f".{AttrName}") and _gk not in cands:
cands.append(_gk)
for key in cands:
gv: Any = globals_map.get(key)
if gv is None:
continue
ty: Any = getattr(gv, 'type', None)
if not isinstance(ty, ir.PointerType):
continue
pointee: Any = ty.pointee
# 全局量本身是指针变量(值类型 X*,LLVM 全局类型 X**)→ 再剥一层
if isinstance(pointee, ir.PointerType):
pointee = pointee.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found: Any = Gen.find_struct_by_pointee(pointee)
if found:
return found[0]
return None
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
FullMethodName: str = f'{ClassName}.{op_name}'
if not Gen._has_function(FullMethodName):
+90
View File
@@ -17,6 +17,15 @@ from lib.includes.t import CTypeRegistry
from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName, FindStructNameInAnnotation
# 注解里的存储类 / 限定符标记:这些名字**不是类名**(联合注解里与指针类混写,
# 如 `t.CExtern | rowptr[CompilerFactory]`),提取"指针指向的类"时必须滤掉。
_MARKER_ANNOT_NAMES: frozenset[str] = frozenset({
'CExtern', 'CExport', 'CStatic', 'CInline', 'CConst', 'CVolatile', 'CRegister',
'CAuto', 'CDefine', 'CTypedef', 'CPostdefinition', 'CPtr', 'CArrayPtr', 'CVoid',
'State', 'TLS',
})
class ImportHandle(BaseHandle):
_struct_Load_cache = {}
_pyi_cache = {}
@@ -848,6 +857,67 @@ class ImportHandle(BaseHandle):
if module_name:
self._LoadDeclarationsFromStubLlvm(module_name, Gen)
def _AnnotationStructName(self, annotation: ast.AST) -> str | None:
"""从注解里提取「指针指向的类」短名(递归,0 判定返回 None)
覆盖形态:`X` / `mod.X` / `rowptr[X]` / `t.CPtr[X]` / 联合 `A | B`(两翼都试)。
存储类与限定符标记(`t.CExtern` / `t.CExport` / `t.CPtr` 等)不算类名,
由 `_MARKER_ANNOT_NAMES` 过滤;返回的是**短名**,调用方再解析成
`Gen.structs` 真实键。
"""
if annotation is None:
return None
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
_left: str | None = self._AnnotationStructName(annotation.left)
if _left:
return _left
return self._AnnotationStructName(annotation.right)
if isinstance(annotation, ast.Subscript):
_base: ast.AST = annotation.value
_bn: str = ''
if isinstance(_base, ast.Name):
_bn = _base.id
elif isinstance(_base, ast.Attribute):
_bn = _base.attr
if _bn in ('rowptr', 'CPtr', 'CArrayPtr'):
_sl: ast.AST = annotation.slice
if hasattr(ast, 'Index') and isinstance(_sl, ast.Index):
_sl = _sl.value
return self._AnnotationStructName(_sl)
return None
if isinstance(annotation, ast.Name):
if annotation.id in _MARKER_ANNOT_NAMES:
return None
return annotation.id
if isinstance(annotation, ast.Attribute):
# `mod.Class`:mod 为 t/c 时是内建标记/内建类型名,不作为类的键
if isinstance(annotation.value, ast.Name) and annotation.value.id in ('t', 'c'):
return None
if annotation.attr in _MARKER_ANNOT_NAMES:
return None
return annotation.attr
return None
def _ResolveAnnotationStructKey(self, Gen: LlvmGeneratorMixin, name: str) -> str | None:
"""把注解里的类短名解析为 `Gen.structs` 的真实键(0 命中返回 None)
三条路径与类字段侧的 `rowptr[裸结构]` 登记保持一致:裸名直查 /
`class_sha1_map` 加前缀 / 全量短名模糊扫描(跨模块类在
`class_sha1_map` 尚未登记该短名时靠这条兜住)。
"""
if not name:
return None
if name in Gen.structs:
return name
_sha: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(name)
if _sha and f'{_sha}.{name}' in Gen.structs:
return f'{_sha}.{name}'
for _k in Gen.structs:
_short: str = _k.split('.')[-1] if '.' in _k else _k
if _short == name:
return _k
return None
def _EmitExternalGlobalDeclLlvm(self, Node: ast.AnnAssign | ast.Assign, Gen: LlvmGeneratorMixin, module_name: str | None = None, ModulePath: str | None = None) -> None:
"""Emit external global variable declaration from imported module"""
if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name):
@@ -857,6 +927,26 @@ class ImportHandle(BaseHandle):
IsPtr = False
is_string_val = False
TypeInfo = None
# 【跨模块模块级变量的**类登记**】`CTypeInfo.FromNode` 对
# `X | t.CPtr` / `rowptr[X]` 注解只给出指针占位(rowptr[X] 折叠成 i8*),
# 且本函数**只算类型、不登记变量类** → 消费侧 `Mod.Var.Field` 链在
# `_get_var_class` 里解析为空:StructGenMixin.vp:139 "属性访问未能解析出
# 目标类型/成员"、CallGenLeafKit.vp:589 / ClassGenVTable.vp:99 误报
# Unknown module(factory.PermPool.alloc)。这里对齐 HandlesAnnAssign
# 变量侧补偿:从注解找回真实结构体键并登记;仅当缺失或指针占位时覆盖。
# 注意:必须放在下面的「已存在则 return」**之前**,否则全局量先由别的
# 路径声明(如 stub 文本 i8*)时这里永远不执行。
_eg_tn: str | None = self._AnnotationStructName(Node.annotation)
if _eg_tn:
# 只在能落到 Gen.structs 真实键时登记(避免把 sizet/CPtr 等标量名当类)
_eg_tk: str | None = self._ResolveAnnotationStructKey(Gen, _eg_tn)
if _eg_tk:
_eg_cur: str | None = Gen.var_struct_class.get(VarName)
if (not _eg_cur or _eg_cur == 'rowptr' or _eg_cur.endswith('.rowptr')
or _eg_cur.startswith('rowptr[')):
Gen.var_struct_class[VarName] = _eg_tk
if getattr(Gen, 'global_struct_class', None) is not None:
Gen.global_struct_class[VarName] = _eg_tk
if VarName in Gen.module.globals:
existing = Gen.module.globals[VarName]
if isinstance(existing, ir.GlobalVariable):
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.