fix(HandlesAssign): self 属性写入的基址收口统一为 _ConcretizeGepBase;收口失败不再静默丢写
类别:a(编译器缺陷)。 1) 收口统一:`self.字段 = v` 的基址此前走**内联**孪生体搜索,缺 `_TryLoadStructFromStub` 一步 —— 类键那份仍 opaque 且 Gen.structs 里尚无已具化 孪生体时(body 只在 stub 文件里待加载),内联版会一路走到 GEP 撞 opaque 守卫 (现场:includes/ast/astaux.vp:165 `self.arg = _copy_str(pool, arg)`,基址 pointee 是 opaque 的 %"8312ce86a2fd82c0.Keyword"*,而同短名 'Keyword' 键那份已具化 10 槽)。 现改为调用读路径的**同一判据源** HandlesExprAttr._ConcretizeGepBase / _ConcretePointeeFor:① 类键那份 + stub 补 body → ② 同短名已具化孪生体 → ③ 都拿不到则原样返回、由守卫报根因。偏移与 GEP 同源(返回实例同时作为 _get_member_offset 的 StructHint)。 2) 收口失败改 fail-fast:三条路都拿不到 elements 时,此前会落回 `offset >= max_offset` 的「存回临时变量」分支 —— 该临时变量不在对象布局里, 后续 `self.attr` 读路径按 GEP 取值,写入被**静默丢弃**。现直接 FailFastError, 并报出三次尝试的结果(不兜底)。 静态核验:py_compile 通过;全仓 symtable 未定义名扫描 0 条;以 _GuardIrBuilder + 真实 _ConcretizeGepBase 复现现场实例形状(opaque '8312ce86a2fd82c0.Keyword' + 已具化 'fef783da4d24330d.Keyword'(10 槽))→ 解析成功、GEP 正常发出(索引 3); 未收口的裸 opaque 基址仍被守卫拦下。
This commit is contained in:
1 parent
7ee6ebe6b0
commit
393ffefcd5
1 file changed
+28
-43
@@ -856,51 +856,36 @@ class AssignHandle(BaseHandle):
|
||||
FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}")
|
||||
Gen._store(FuncPtrI8, MethodPtrAddr)
|
||||
return
|
||||
# 自指针的 pointee 可能是**另一份同名 struct 实例**:函数签名里那份
|
||||
# 仍 opaque(`_get_or_create_struct` 早期创建、从未 set_body),而类键
|
||||
# `Gen.structs[ClassName]` 上那份已具化。typed pointer 的 GEP 必须在
|
||||
# 编译期算出元素类型 ⇒ 走 opaque pointee 时 llvmlite 在
|
||||
# `types.py:633 self.elements[i.constant]` 抛裸 TypeError
|
||||
# ('NoneType' object is not subscriptable;现场:astaux.vp
|
||||
# `Keyword.__init__` 的 `self.arg = _copy_str(pool, arg)`)。
|
||||
# 修法:先 bitcast 到**有 body 的那份实例**,再把该实例作为
|
||||
# StructHint 交给 `_get_member_offset` —— 偏移与 GEP 必须同源
|
||||
# (与属性读取路径 _gep_and_Load_member 的 415916b3 同口径)。
|
||||
_SelfPointee: ir.Type | None = None
|
||||
if isinstance(SelfPtr.type, ir.PointerType):
|
||||
_SelfPointee = SelfPtr.type.pointee
|
||||
struct_type: ir.Type = Gen.structs[ClassName]
|
||||
if (isinstance(_SelfPointee, ir.IdentifiedStructType)
|
||||
and _SelfPointee.elements is None
|
||||
and isinstance(struct_type, ir.IdentifiedStructType)
|
||||
and struct_type.elements is not None):
|
||||
SelfPtr = Gen.builder.bitcast(
|
||||
SelfPtr, ir.PointerType(struct_type),
|
||||
name=f"concrete_self_{ClassName}")
|
||||
_SelfPointee = struct_type
|
||||
# 孪生体搜索(治本,2026-09-30):类键实例可能**也是** opaque —— 同一类名
|
||||
# 常有两份 struct 实例(短名 'Keyword' / sha1 全名 '<sha1>.Keyword'),
|
||||
# 函数签名里的 self 用哪一份、StructGen 具化的是哪一份**并不保证一致**。
|
||||
# 现场:includes/ast/astaux.vp:165 `self.arg = _copy_str(pool, arg)` 的
|
||||
# 基址 pointee 是 opaque 的 `%"<sha1>.Keyword"*`,GEP 无法在编译期算元素类型。
|
||||
# 修法:按**同短名**取一份已具化实例(工具函数 _FindConcreteTwin,读路径
|
||||
# HandlesExprAttr 共用同一判据)并 bitcast —— 偏移与 GEP 由此同源。
|
||||
# 找不到 ⇒ 保持现状,交由 RequirePointerOperand 的 opaque 守卫 fail-fast
|
||||
# (报出同短名实例清单,暴露"body 从未 set_body"),**不静默兜底**。
|
||||
# 自指针基址收口:与**读路径同一判据源**(HandlesExprAttr
|
||||
# `_ConcretizeGepBase` / `_ConcretePointeeFor`),三步同源:
|
||||
# ① 类键那份 opaque ⇒ 先 `_TryLoadStructFromStub` 补 body;
|
||||
# ② 仍不可用 ⇒ 按同短名取一份已具化实例(`_FindConcreteTwin`);
|
||||
# ③ 都拿不到 ⇒ 原样返回,由下方 opaque fail-fast 报根因。
|
||||
# 写路径此前是**内联**版本、缺 ①:类键那份仍 opaque 且 `Gen.structs`
|
||||
# 里也还没有孪生体时(body 只在 stub 文件里待加载),内联版会一路走到
|
||||
# GEP 撞 opaque(现场 2026-09-30:includes/ast/astaux.vp:165
|
||||
# `self.arg = _copy_str(pool, arg)` 的基址 pointee 是 opaque 的
|
||||
# %"8312ce86a2fd82c0.Keyword"*,而同短名 'Keyword' 键那份已具化 10 槽)。
|
||||
# 偏移与 GEP 必须同源:返回的实例同时作为 `_get_member_offset` 的 StructHint。
|
||||
SelfPtr, _SelfPointee = self.Trans.ExprAttrHandle._ConcretizeGepBase(
|
||||
Gen, SelfPtr, ClassName, f"concrete_self_{ClassName}")
|
||||
struct_type: ir.Type = (_SelfPointee
|
||||
if isinstance(_SelfPointee, ir.IdentifiedStructType)
|
||||
else Gen.structs[ClassName])
|
||||
if (isinstance(_SelfPointee, ir.IdentifiedStructType)
|
||||
and _SelfPointee.elements is None):
|
||||
_Twin: ir.IdentifiedStructType | None = Gen._FindConcreteTwin(_SelfPointee)
|
||||
if _Twin is None:
|
||||
try:
|
||||
_Twin = Gen._FindConcreteTwin(Gen.structs.get(ClassName))
|
||||
except Exception:
|
||||
_Twin = None
|
||||
if _Twin is not None:
|
||||
SelfPtr = Gen.builder.bitcast(
|
||||
SelfPtr, ir.PointerType(_Twin),
|
||||
name=f"concrete_twin_self_{ClassName}")
|
||||
_SelfPointee = _Twin
|
||||
struct_type = _Twin
|
||||
# 收口失败:类键那份、同短名孪生体、以及 `_TryLoadStructFromStub`
|
||||
# 三条路都没拿到 body。**不得**再落回下方 `offset >= max_offset`
|
||||
# 的「存回临时变量」分支 —— 该临时变量不在对象布局里,后续
|
||||
# `self.attr` 读路径按 GEP 取值,写入会被**静默丢弃**。此处 fail-fast。
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError as _FFE0
|
||||
raise _FFE0(
|
||||
f"属性写入 '{ClassName}.{AttrName}' 的 self 基址指向**未具化**"
|
||||
f"结构体:'{getattr(_SelfPointee, 'name', '?')}'(opaque)。"
|
||||
f"已尝试:类键 {ClassName!r} 的实例 → 同短名孪生体 → "
|
||||
f"_TryLoadStructFromStub 补 body,均未拿到 elements。"
|
||||
f"请查该类 body 为何从未 set_body(StructGen._generate_structs)。"
|
||||
+ (f"\n {Gen._get_node_info()}" if hasattr(Gen, '_get_node_info') else ""))
|
||||
offset: int = Gen._get_member_offset(AttrName, ClassName, _SelfPointee)
|
||||
max_offset: int = (len(struct_type.elements)
|
||||
if isinstance(struct_type, ir.IdentifiedStructType)
|
||||
|
||||
Reference in new issue
Block a user