fix(tpc): 字段解析「内层是类却成通用指针」当场 fail-fast(降级源头定位)

承接 b8ed33a2 / 7fb0e498:前两者修的是**结果**(错位 body),本次收**源头** ——
class_members 在某个早期 pass 被解析出 i8**(void 基座 + 2 层),随后被冻进
struct body。CollectAnnAssignMember 是字段类型的唯一汇总点,在此加判据式 fail-fast:

判据(只拦"必属类型信息丢失"的组合):注解是指针包装(rawptr[T] / t.CPtr[T] /
裸名 CPtr[T] / `T | t.CPtr` 联合)且其**内层节点(Name/Attribute)的名字在
Gen.structs 或 Gen._struct_sha1_map 中有类定义**,而解析出的 BaseType 却是
t.CVoid ⇒ 必定是解析路径把类丢了,响亮失败并附完整判据:
  解析结果 BaseType/PtrCount/IsStruct/IsTypedef/Name
  符号表[内层名] => IsTypedef/BaseType/PtrCount/IsStruct/IsRenum/IsModuleAlias/IsEnumMember
  Gen.structs 命中 / _struct_sha1_map 命中

放行:rawptr[rawptr] 这类本就 void 基座的多层指针、模块名、泛型特化实参(内层非
Name/Attribute)—— 不误伤合法写法。
This commit is contained in:
TermiNexus committed 2026-09-29 00:21:39 +08:00
1 parent 7fb0e49854
commit 02d89b0900
1 file changed
+65 -1
+65 -1
View File
@@ -14,7 +14,8 @@ from lib.includes import t
from lib.includes.t import CTypeRegistry
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
from lib.core.SymbolUtils import (
IsPtrSubscriptNode, IsListAnnotation, FixedArrayKeywordAnnotationError)
IsPtrSubscriptNode, IsListAnnotation, IsCPtrMarkerNode,
FlattenUnionOperands, FixedArrayKeywordAnnotationError)
from lib.core.VLogger import get_logger as _vlog
@@ -1044,8 +1045,71 @@ class BaseHandle:
f"IsTypedef={getattr(TypeInfo, 'IsTypedef', None)} "
f"Name={getattr(TypeInfo, 'Name', None)})—— 拒绝静默退化为 i8*"
)
# 「内层是类引用却解析成通用指针」fail-fast(降级源头定位):
# `rawptr[Mod.Class]` / `Mod.Class | t.CPtr` 的语义是"指向该类",内层若确实是
# 已定义类,解析结果必须带该类 BaseType;退化成 void 基座(i8* / 多一层 i8**)
# 就是类型信息被丢掉 —— 该值一旦进 class_members 就会被冻进 struct body
# (llvmlite set_body 只能设一次),后期只修表不修体(现场:Generator 第 3/11
# 槽 i8**)。此处响亮失败并附判据,使降级**当场暴露**而非留到赋值时报"层数不同"。
self._CheckPtrAnnotationKeepsClass(item.annotation, TypeInfo, VarName, AnnotationText)
return VarName, MemberType, TypeInfo
def _CheckPtrAnnotationKeepsClass(self, Annotation: ast.AST, Info: CTypeInfo | None,
MemberName: str, AnnotationText: str) -> None:
"""指针包装注解的内层是**已定义类**时,解析结果不得退化成 void 基座(fail-fast)。
只拦"必属类型信息丢失"的组合:内层节点(Name / Attribute)的名字在
`Gen.structs`(本模块已建)或 `Gen._struct_sha1_map`(预扫描的类→模块映射)
中有类定义,而解析出的 `BaseType` 却是 `t.CVoid`。其余一律放行
(`rawptr[rawptr]` 这类本就 void 基座的多层指针、模块名、泛型特化实参等)。
"""
if Info is None or Info.BaseType is None:
return
if not (Info.BaseType is t.CVoid or isinstance(Info.BaseType, t.CVoid)):
return
Inner: ast.AST | None = None
if isinstance(Annotation, ast.Subscript) and IsPtrSubscriptNode(Annotation, self.Trans.SymbolTable):
Inner = Annotation.slice
elif isinstance(Annotation, ast.BinOp) and isinstance(Annotation.op, ast.BitOr):
for Side in FlattenUnionOperands(Annotation):
if not IsCPtrMarkerNode(Side, self.Trans.SymbolTable):
Inner = Side
break
if Inner is None:
return
InnerName: str | None = None
if isinstance(Inner, ast.Name):
InnerName = Inner.id
elif isinstance(Inner, ast.Attribute):
InnerName = Inner.attr
if not InnerName or InnerName in ('rawptr', 'CPtr'):
return
Gen: Any = getattr(self.Trans, 'LlvmGen', None)
if Gen is None:
return
if (InnerName not in getattr(Gen, 'structs', {})
and InnerName not in getattr(Gen, '_struct_sha1_map', {})):
return
_e: Any = None
try:
_e = self.Trans.SymbolTable.lookup(InnerName)
except Exception:
_e = None
raise ValueError(
f"[FATAL] 成员 '{MemberName}' 的注解 '{AnnotationText}' 内层 '{InnerName}' "
f"是**已定义类**,却被解析成通用指针(类型信息丢失)—— 拒绝静默降级:"
f"解析结果 BaseType={Info.BaseType} PtrCount={getattr(Info, 'PtrCount', None)} "
f"IsStruct={getattr(Info, 'IsStruct', None)} IsTypedef={getattr(Info, 'IsTypedef', None)} "
f"Name={getattr(Info, 'Name', None)};"
f"符号表['{InnerName}'] => IsTypedef={getattr(_e, 'IsTypedef', None)} "
f"BaseType={getattr(_e, 'BaseType', None)} PtrCount={getattr(_e, 'PtrCount', None)} "
f"IsStruct={getattr(_e, 'IsStruct', None)} IsRenum={getattr(_e, 'IsRenum', None)} "
f"IsModuleAlias={getattr(_e, 'IsModuleAlias', None)} "
f"IsEnumMember={getattr(_e, 'IsEnumMember', None)};"
f"Gen.structs 命中={'有' if InnerName in getattr(Gen, 'structs', {}) else '无'} "
f"_struct_sha1_map 命中={getattr(Gen, '_struct_sha1_map', {}).get(InnerName)!r}"
)
def LookupFunctionSymbol(self, name: str, *, module_path: str | None = None) -> CTypeInfo | None:
"""查找函数符号,先尝试 module_path.name,再回退到 name。