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:
1 parent
2aa55f36b9
commit
43853bc455
1 file changed
+56
-1
@@ -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
|
||||
|
||||
|
||||
Reference in new issue
Block a user