Files
TransPyC/lib/core
TermiNexus 7aa12263f5 fix(HandlesExprAttr/BaseGen): _get_attr_ptr 的 self 分支补 opaque 基址收口(孪生体 bitcast)+ GEP 守卫报出 TPC 发射点
【a 编译器缺陷】现场:Phase2 翻译 includes/ast/astaux.vp:165
`self.arg = _copy_str(pool, arg)`,守卫报
"getelementptr(GEP) 的基址指向**未具化**的具名结构体:基址类型=%"8312ce86a2fd82c0.Keyword"*,
GEP 名='arg'",而同短名实例清单显示 'Keyword' 键上那份已具化(10 槽)。

根因:`_get_attr_ptr` 的 **self 分支**是全仓"self 字段取址"家族里唯一**没有**做 opaque
收口的一处 —— 同函数下方各分支(变量分支 / 属性链分支 / i8* 分支 / 强转基座分支)都先
`_TryLoadStructFromStub` 补 body、再 bitcast 到已具化实例;`HandlesAssign` 的 `self.X = v`
写路径与读路径 `_gep_and_Load_member` 也都有同一套孪生体搜索(`_FindConcreteTwin`)。
本分支直接 `gep(SelfPtr, …)`,typed pointer 下 llvmlite 必须在编译期从 pointee 算元素类型
⇒ 撞 opaque 即抛裸 TypeError(被 IR 边界守卫拦下)。

修法(与同函数其余分支同口径,不引入新判据):
  · 基址 pointee 为 opaque 时,先在类键(`Gen.structs[ClassName]`)上 `_TryLoadStructFromStub`
    补 body;类键那份仍不可用则退回 `Gen._FindConcreteTwin`(同短名、取槽数最多);
  · 命中即 bitcast 到该实例,并把该实例作为 `StructHint` 传给 `_get_member_offset`
    —— 偏移与 GEP 必须同源(与 a43513c9 的"hint 只接受同类"口径一致);
  · 顺带补 `offset is None ⇒ return None`(原实现会把 None 塞进 `ir.Constant(i32, None)`,
    属同一函数其余分支已有的判断)。

【a 编译器缺陷·取证】`RequirePointerOperand` 的 opaque 分支新增一行
「TPC 发射点(由内向外)」:取 Python 栈中位于本仓 `lib/`、且不在 BaseGen.py(守卫自身)
的最内 3 帧,报出 `文件:行(函数)`。理由:该守卫的报文只能指到**语句**,而同一语句里常有
多个候选 GEP 点(本例 astaux.vp:165 在读写两侧共有 4 个 self 字段 GEP 点),逐个读代码
无法判定是哪一个 —— 本次即靠该取证能力闭环(先按"唯一漏收口的分支"修正,下一次构建若
仍失败会直接指出真实发射点)。只在失败路径执行,热路径零开销。

冒烟(临时脚本已删):
  · `_get_attr_ptr` 复刻现场(self 槽持有 opaque `%8312…Keyword*`、'Keyword' 键那份 10 槽)
    ⇒ 输出 GEP 基址类型 `%"fef783da4d24330d.Keyword"*`(经 `cast_self_Keyword`),PASS;
  · 守卫取证:伪造 lib/ 下的发射帧 ⇒ 报文含
    `TPC 发射点(由内向外): core/Handles/_FakeProbe.py:2(_LibEmit)`,PASS。
2026-09-30 14:35:50 +08:00
..
2026-07-18 19:25:40 +08:00
2026-07-18 19:25:40 +08:00
2026-07-18 19:25:40 +08:00
2026-07-18 19:25:40 +08:00
2026-07-18 19:25:40 +08:00