fix(HandlesExprAttr): 基座 pointee 与 Gen.structs 的匹配补「同 sha1 前缀」与「同短名唯一候选」

现场(Repl.vp:802):`ct_names: list[str]* = GenApi._g_gen.TypeGenCType.CTypedefNames`
的基座 `.TypeGenCType` 取值后 pointee 为 `%"750b8c10137d273e.TypeGenCType"*`(= 撤销
6a287b9 后的新 sha1),而 Gen.structs(250 键)里没有该 IR 名的实例 ⇒ 旧判据只有
"身份相同 / IR 全名逐字相同" ⇒ 全部未命中 ⇒ 属性链求值为空 → 带注解赋值判定"无值可存"
而终止编译。(a18ca4da 的记账正是把"基座形态 / pointee / 键数"三项事实直接印了出来,
本轮不必再猜。)

改动(判据分级,强到弱;找不到仍留痕失败,不兜底造类型):
  ① 身份相同(原判据);
  ② IR 全名逐字相同(原判据,覆盖"同名第二份实例");
  ③ 同 sha1 前缀 —— IR 名形如 `<sha1>.<短名>`,前缀相等即"同一模块的同一类";
  ④ 同短名——**仅当候选唯一**时放行(调用点算 `_UniqShortCN`):两个及以上同名类无法
     判定是哪一个,宁可留痕失败也不选错布局(同名类冲突在本仓一律以 sha1 全名区分)。
同时把"未命中"记账扩为:列出分级判据、同短名候选清单,以及"候选 >1 会被主动拒绝"。

验证:py_compile 通过;`_PointeeMatchesStruct` 冒烟 6 例(身份 / 同名第二份实例 /
同短名不同 sha1 / 裸短名 / 不同类 / 非 Identified 一侧)全部符合预期。
This commit is contained in:
TermiNexus committed 2026-09-30 12:20:20 +08:00
1 parent 2aa55f36b9
commit 43853bc455
1 file changed
+56 -1
+56 -1
View File
@@ -21,6 +21,36 @@ class ExprAttrHandle(BaseHandle):
val: ir.Value = Gen._load(ElemPtr, name="arr_elem_load")
return Gen._apply_bswap_if_big(val, arr_byte_order, "bswap_arr_load")
@staticmethod
def _PointeeMatchesStruct(Pointee: Any, ST: Any) -> bool:
"""pointee 与该 struct 实例是否算**同一个类**(判据分级,宽到窄)。
原始判据只有"身份相同 / IR 全名逐字相同",遇到"同名类的另一份实例"就整条链放弃
(现场:Repl.vp:802 `GenApi._g_gen.TypeGenCType.CTypedefNames` 的基座 pointee 是
`%"750b8c10137d273e.TypeGenCType"*`,而 Gen.structs(250 键)里没有该 IR 名的实例
⇒ 身份与全名都不等 ⇒ 属性链求值为空终止编译)。故补两级退化判据:
① 同 IR 全名(原判据);
② 同 sha1 前缀 —— IR 名形如 `<sha1>.<短名>`,前缀相等即"同一模块的同一类"
(sha1 全名正是本仓为同名类冲突引入的命名形态)。
同**短名**但不同 sha1 前缀的情形**不放行**(那可能是别模块的同名类,选错即静默
错布局):它由调用点在"同短名候选唯一"时单独放行(见 `_UniqShortCN`)。
找不到时仍返回 False(由调用点留痕,不兜底造类型)。
"""
if Pointee is ST:
return True
if not (isinstance(Pointee, ir.IdentifiedStructType)
and isinstance(ST, ir.IdentifiedStructType)):
return False
_pn: str = getattr(Pointee, 'name', '') or ''
_sn: str = getattr(ST, 'name', '') or ''
if _pn and _pn == _sn:
return True
_pp: str = _pn.rsplit('.', 1)[0] if '.' in _pn else ''
_sp: str = _sn.rsplit('.', 1)[0] if '.' in _sn else ''
return bool(_pp and _sp and _pp == _sp)
def _gep_and_Load_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, offset: int | None, AttrName: str, ClassName: str, ST: ir.Type | None = None) -> ir.Value | None:
"""从结构体指针通过 GEP 取成员,处理 array/struct pointer/class_members 特殊情况"""
if offset is None:
@@ -967,8 +997,21 @@ class ExprAttrHandle(BaseHandle):
parent_hint: str | None = self._resolve_attr_parent_hint(Node, Gen)
if not parent_hint and isinstance(Node.value, ast.Attribute):
parent_hint = self._resolve_chain_result_class(Node.value, Gen) or parent_hint
# 同短名候选:**唯一**时才放行(两个及以上同名类无法判定是哪一个,
# 宁可留痕失败也不能选错布局——同名类冲突在本仓一律以 sha1 全名区分)。
_UniqShortCN: str | None = None
if isinstance(pointee, ir.IdentifiedStructType):
_PShort2: str = (getattr(pointee, 'name', '') or '').rsplit('.', 1)[-1]
_ShortCNs: list[str] = [
_c5 for _c5, _s5 in Gen.structs.items()
if isinstance(_s5, ir.IdentifiedStructType)
and (getattr(_s5, 'name', '') or '').rsplit('.', 1)[-1] == _PShort2
]
if len(_ShortCNs) == 1:
_UniqShortCN = _ShortCNs[0]
for CN, ST in Gen.structs.items():
if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name):
if ((pointee == ST) or self._PointeeMatchesStruct(pointee, ST)
or (_UniqShortCN is not None and CN == _UniqShortCN)):
st, ok = self._try_Load_struct_from_stub(Gen, CN)
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN, parent_hint)
@@ -1018,9 +1061,21 @@ class ExprAttrHandle(BaseHandle):
return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
# 结构体分支未命中任何类:pointee 与 Gen.structs 全部键都不等(同名类双实例 /
# 该类未注册)——这是"基座类型已知却读不到字段"的最后一种来源,必须留痕。
_PShortN: str = (getattr(pointee, 'name', '') or '').rsplit('.', 1)[-1]
_SameShort: list[str] = []
for _cn3, _st3 in Gen.structs.items():
if not isinstance(_st3, ir.IdentifiedStructType):
continue
if (getattr(_st3, 'name', '') or '').rsplit('.', 1)[-1] == _PShortN:
_SameShort.append(_cn3)
self._NoteAttrNone(
Gen, None, Node.attr,
f"基座 pointee {pointee} 未匹配 Gen.structs 中任何 struct(键数={len(Gen.structs)})"
f";分级匹配(身份 / IR 全名 / 同 sha1 前缀)与「同短名 '{_PShortN}' 唯一候选」"
f"**全部未命中**,同短名候选={_SameShort if _SameShort else '无'}"
f"(候选 >1 时会被主动拒绝,避免选错同名类)"
f"——即该类在本 Gen 的 structs 里没有可用实例(另一 Gen/缓存的实例漏进来了,"
f"或该类从未注册)"
f";基座形态={self._ExprShape(Node.value)}")
return None