fix(tpc): 属性取值失败的报文补"基址诊断" + 补掉声明加载去重签名的真实缺口
类别:a(编译器缺陷)—— 两者都是"缺事实/漏输入",不是放宽判定。
【一】`_RaiseUnresolvedExpr` 增打基址事实(HandlesBase)
现场:TransPyV/App/lib/core/Gen/MatchGenMixin.vp:231
`val: ast.AST* = expr_node.value`(base 是 `expr_node: rawptr[ast.Expr]`)
→ Attribute 取值返回 None → 本报文 + sys.exit(1)。
属性读回 None 的根因只有两类:① 类名登记退化(var_struct_class 存 'rawptr' /
'rawptr[X]' / 折叠态,或压根没登记);② 登记名与 Gen.structs / class_members 的键
不同源(短名 vs sha1 全名)。原报文只有"目标变量 + 注解 + 源码",不含任何一项事实
⇒ 只能从"求值为空"反推。现追加一行(仅 Attribute + Name 基址时,其余形态逐字不变):
基址诊断: 'expr_node' 的 var_struct_class=<...>;alloca 类型=<...>;
该名在 Gen.structs=<是/否>;class_members=<N 个字段/无该键>
与 `_DescribeMemberSlot` 同口径:列数据、不猜。
【二】`_ClassMembersReloadSignature` 的"类数"改为"逐类 (键, 表长) 元组"(HandlesImports)
上一轮 3399b44c 的签名里全局进度只记 `len(class_members)`(键数)。缺口:**某已有类的
成员表继续增长时键数不变**(典型=父类成员后到),而父类成员正是继承前缀的唯一来源
⇒ 极端时序下会漏掉一次必要重跑。改为逐类 (键, 长度) 元组,并补记
`len(class_parents)` / `len(class_parent)`(父链登记本身也是输入)。
代价 O(类数)(约 300 项/次调用),仍远低于一次重跑的成本。
验证:GetDiagnostics 干净;py 层 import + 既有 16 例类型判定 smoke test 全过。
未跑编译器(无 includes 改动,无需重编)。
This commit is contained in:
1 parent
aa1b536517
commit
716cd61a75
2 files changed
+36
-2
No files matched your search
@@ -658,6 +658,34 @@ class BaseHandle:
|
||||
f"{(',目标变量 ' + repr(VarName)) if VarName else ''}"
|
||||
f"{(',注解 ' + ann_text) if ann_text else ''}。位置 {loc}"
|
||||
f"{(',源码: ' + code_line) if code_line else ''}")
|
||||
# 【基址诊断】属性读返回 None 的根因只有两类(先说事实,不再从"求值为空"反推):
|
||||
# ① 类名登记退化 —— var_struct_class 存的是占位/折叠态('rawptr'、'rawptr[X]'、
|
||||
# 'CVoid'…)或压根没登记;
|
||||
# ② 登记名与 Gen.structs / class_members 的键不同源(短名 vs sha1 全名)。
|
||||
# 故把"基址变量登记成什么 + alloca 实际 LLVM 类型 + 该登记名在两表的命中情况"
|
||||
# 一并打进报文(与 _DescribeMemberSlot 同口径:列数据而非猜)。仅 Attribute + Name
|
||||
# 基址时追加,其余形态报文逐字不变。
|
||||
if isinstance(Node, ast.Attribute) and isinstance(Node.value, ast.Name):
|
||||
_bn: str = Node.value.id
|
||||
_vc: str | None = None
|
||||
_alloc: Any = None
|
||||
try:
|
||||
_vc = (getattr(Gen, 'var_struct_class', None) or {}).get(_bn)
|
||||
if not _vc:
|
||||
_vc = (getattr(Gen, 'global_struct_class', None) or {}).get(_bn)
|
||||
_alloc = (getattr(Gen, 'variables', None) or {}).get(_bn)
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
_slot_ty: object = getattr(_alloc, 'type', None)
|
||||
if _vc:
|
||||
_hit_st: str = '是' if _vc in Gen.structs else '否'
|
||||
_hit_cm: str = ('%d 个字段' % len(Gen.class_members.get(_vc) or [])) \
|
||||
if _vc in Gen.class_members else '无该键'
|
||||
else:
|
||||
_hit_st, _hit_cm = '—', '—'
|
||||
msg += (f"\n│ 基址诊断: '{_bn}' 的 var_struct_class={_vc!r};"
|
||||
f"alloca 类型={_slot_ty};该名在 Gen.structs={_hit_st};"
|
||||
f"class_members={_hit_cm}")
|
||||
_vlog().compile_error(msg, src_file, lineno, code_line)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -3206,7 +3206,10 @@ class ImportHandle(BaseHandle):
|
||||
"""`_TryLoadClassMembersFromPyi` 重跑的依赖签名(纯读,不产生副作用)。
|
||||
|
||||
收录"重跑能否产生新结果"的全部输入:
|
||||
- 全局进度:`len(class_members)` / `len(_members_flattened)`
|
||||
- 全局进度:**逐类**(`class_members` 键, 该表长度) 的完整元组(不是"类数"——
|
||||
只看键数会在"某已有类的成员表继续增长"(父类成员后到)时看不出变化,
|
||||
而父类成员正是继承前缀的来源);`_members_flattened` 长度;
|
||||
`class_parents` / `class_parent` 的条目数(父链登记本身也是输入)
|
||||
- 本类自身:成员表长度、是否已登记已展平、struct body 元素数(None ⇒ -1)
|
||||
- 各父类:成员表长度 + 是否已展平(父类从 `class_parents` / `class_parent` 取;
|
||||
两者都缺时用空元组 —— 此时本类依赖尚未建立,签名仍稳定,不影响收敛)
|
||||
@@ -3225,9 +3228,12 @@ class ImportHandle(BaseHandle):
|
||||
(_p, len(Gen.class_members.get(_p, []) or []), _p in _flat)
|
||||
for _p in _parents
|
||||
)
|
||||
_cm_sig: tuple = tuple((_k, len(_v)) for _k, _v in Gen.class_members.items())
|
||||
return (
|
||||
len(Gen.class_members),
|
||||
_cm_sig,
|
||||
len(_flat),
|
||||
len(getattr(Gen, 'class_parents', {}) or {}),
|
||||
len(getattr(Gen, 'class_parent', {}) or {}),
|
||||
len(Gen.class_members.get(class_name, []) or []),
|
||||
class_name in _flat,
|
||||
_st_len,
|
||||
|
||||
Reference in new issue
Block a user