fix(tpc): 注解解析补齐「有类定义 ⇒ 是类」——模块别名占裸名导致类引用退化成 i8**

类别:a 编译器缺陷(根因修复)。

现场:TransPyV Generator.vp:200 `self.ExprGenFstr = SubExprGenFstr` 报
「指针隐式转换已禁止(层数不同):%\"a7b68c79f39cb4d3.ExprGenFstr\"* → i8**」,
成员槽来源明细显示:class_members[Generator] 下标 11 声明槽类型正确
(%\"a7b68c79f39cb4d3.ExprGenFstr\"*),但布局 struct
'47382dc8277c9d28.Generator' 的 elements[11]=i8**(set_body 只能设一次 →
错布局被永久冻结)。

已核对 temp/47382dc8277c9d28.stub.ll:declare 侧该槽逐字正确
(%"a7b68c79f39cb4d3.ExprGenFstr"*),Generator.vp 46 个字段全写作
`rawptr[X.X]`;.vpi 里注解文本也是 `rawptr[ExprGenFstr.ExprGenFstr]`。

真根因:`import lib.core.Gen.Expr.ExprGenFstr as ExprGenFstr` 的**模块别名**与
模块内 `class ExprGenFstr` 同名,平坦符号表(无前缀)一个名字只留一个条目 ⇒
TypeAnnotationResolver._from_node_attribute / _from_node_name 命中别名条目时
Copy 出「无基类型」的空 CTypeInfo ⇒ rawptr 下标分支按
`PtrCount = slice + rawptr(1)` 得 void 指针链(i8*/i8**),类身份尽失;
该值经成员提取(SymbolExtractor._collect_members → CTypeInfo.FromNode)
写进跨模块共享符号表,再由 FuncGen.setup_from_symbol_table 建出 struct body
→ 槽被冻结成 i8**。哪一字段中招取决于别名/类条目谁最后写入平坦表,
故三次构建分别命中 TypeGenCDef / ExprGenFstr(时变、非固定字段)。

修复:新增 TypeAnnotationResolver._RecoverTypeFromNamespaces —— 平坦条目
**不是类型**(模块别名/函数/变量/define/枚举成员占位)时,按 _namespaces
找回同名 typedef / 结构体(struct·renum·exception)/ 枚举条目,与
LLVMTypeMapper._resolve_name 既有「同名冲突找回类型」分支逐条同构(同一条
规则源)。挂接三处:_from_node_attribute 的条目分支与无条目分支、
_from_node_name 的条目分支。

口径细节:结构体表示与本文件既有 promotion 逐字一致
(BaseType=CStruct(name) + IsStruct + Name,**不加** PtrCount)——
rawptr[X] 的层数由 rawptr 分支自己 +1,此处再加会得 X**。
This commit is contained in:
TermiNexus committed 2026-09-29 12:44:03 +08:00
1 parent fd212b3ff8
commit 3bc3c48dee
1 file changed
+77
+77
View File
@@ -425,6 +425,54 @@ class TypeAnnotationResolver:
TypeName: str = Node.value
return TypeAnnotationResolver.from_type_name(TypeName)
@staticmethod
def _RecoverTypeFromNamespaces(TypeName: str, SymbolTable: dict | SymbolTable) -> CTypeInfo | None:
"""平坦条目不是"类型"时,按命名空间找回同名**类型**条目(找不到 → None)。
与 LLVMTypeMapper._resolve_name 的"同名冲突:平坦条目被 define / 枚举成员 /
函数占位时找回类型"逐分支同构(同一条规则源):优先 typedef,其次结构体
(struct / renum / exception 均置 IsStruct),再次枚举。
必要性:平坦表(无前缀)一个名字只留一个条目,而 `import path as X` 的**模块
别名**与模块内 `class X` 同名(TransPyV 的 Generator 47 个 `rawptr[X.X]` 字段
全是这种形态)。条目被别名占住时,本解析器返回"无基类型"的空 CTypeInfo ⇒
`rawptr[X.X]` 退化成 void 指针链(i8*/i8**),而 stub 声明侧是
`%"<sha>.X"*` ⇒ struct 布局里该槽被 set_body 冻结成 i8**(不可重设),
赋值时报"指针隐式转换已禁止(层数不同)"。
"""
_Namespaces: Any = getattr(SymbolTable, '_namespaces', None)
if not isinstance(_Namespaces, dict):
return None
for _NsSyms in _Namespaces.values():
if not isinstance(_NsSyms, dict):
continue
_Cand: Any = _NsSyms.get(TypeName)
if _Cand is None:
continue
if getattr(_Cand, 'IsTypedef', False):
_R: CTypeInfo = _Cand.Copy()
_R.IsTypedef = True
if _R.BaseType is None:
_R.BaseType = t._CTypedef(TypeName)
return _R
if getattr(_Cand, 'IsStruct', False) or getattr(_Cand, 'IsRenum', False):
# 结构体表示与本文件既有 promotion(_from_node_name / _from_node_attribute
# 的 `BaseType = t.CStruct(name=...); IsStruct = True`)**逐字同口径**:
# 类引用不额外加指针层(PtrCount 保持 0)——本文件里 `rawptr[X]` 的层数
# 由 rawptr 分支自己 +1,若此处再加一层会得到 `X**`。
_R = CTypeInfo()
_R.BaseType = t.CStruct(name=TypeName)
_R.IsStruct = True
_R.Name = TypeName
return _R
if getattr(_Cand, 'IsEnum', False):
_R = CTypeInfo()
_R.BaseType = t.CInt()
_R.IsEnum = True
_R.Name = TypeName
return _R
return None
@staticmethod
def _from_node_name(Node: ast.Name, SymbolTable: dict | SymbolTable) -> CTypeInfo:
"""处理 ast.Name 节点"""
@@ -538,6 +586,18 @@ class TypeAnnotationResolver:
if Entry.BaseType is None and (Entry.IsStruct or Entry.Name):
Entry.BaseType = t.CStruct(name=TypeName)
Entry.IsStruct = True
if (Entry.BaseType is None and not Entry.IsStruct and not Entry.IsEnum
and not Entry.IsTypedef and not Entry.IsCpythonObject and not Entry.Name):
# 平坦条目不是"类型"(同名**模块别名** / 函数 / 变量 / define /
# 枚举成员占住裸名):直接 return Entry 会得到"无基类型"的空
# CTypeInfo ⇒ `rawptr[X]` 之类注解退化成 void 指针链
# (i8*/i8**),struct 布局里该槽被 set_body 永久冻结。
# 与上方 _from_node_attribute 及 LLVMTypeMapper._resolve_name
# 的"同名冲突找回类型"同一条规则源。
_RecoveredName: CTypeInfo | None = TypeAnnotationResolver._RecoverTypeFromNamespaces(
TypeName, SymbolTable)
if _RecoveredName is not None:
return _RecoveredName
return Entry
elif isinstance(Entry, dict):
if Entry.get('type') == 'typedef':
@@ -1088,7 +1148,24 @@ class TypeAnnotationResolver:
if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name):
Result.BaseType = t.CStruct(name=TypeName)
Result.IsStruct = True
if (Result.BaseType is None and not Result.IsStruct and not Result.IsEnum
and not Result.IsTypedef and not Result.IsCpythonObject and not Result.Name):
# 平坦条目不是"类型"(同名**模块别名** / 函数 / 变量 / define /
# 枚举成员占住了裸名):Copy 得到的是"无基类型"的空 CTypeInfo ⇒
# `rawptr[Mod.Cls]` 之类注解退化成 void 指针链(i8*/i8**),
# struct 布局里该槽被 set_body 永久冻结(现场:Generator 的
# ExprGenFstr 槽 = i8**,而声明槽是 %"…ExprGenFstr"*,赋值时报
# "层数不同")。与 LLVMTypeMapper._resolve_name 的"同名冲突找回
# 类型"同一条规则源:按命名空间找回同名 typedef/结构体/枚举。
_Recovered: CTypeInfo | None = TypeAnnotationResolver._RecoverTypeFromNamespaces(
TypeName, SymbolTable)
if _Recovered is not None:
return _Recovered
return Result
_Recovered2: CTypeInfo | None = TypeAnnotationResolver._RecoverTypeFromNamespaces(
TypeName, SymbolTable)
if _Recovered2 is not None:
return _Recovered2
return CTypeInfo()
if FullName in SymbolTable: