fix(HandlesExprCall): 同名类构造消歧——ctor 的 self 实参按 callee 限定类名解析,不再回退有歧义的短名

类别:a(编译器缺陷)

现象:includes/ast/parser.vp:1774 `kw: rawptr[AST] = KwNode(ps.pool, None, val)` 报
  FailFastError: 指针隐式转换已禁止(非基本类型(结构体/类/联合)):调用
  8312ce86a2fd82c0.Keyword.__new__ 第 0 个实参 %"fef783da4d24330d.Keyword"*
  不能隐式转为形参 %"8312ce86a2fd82c0.Keyword"*

根因:Keyword 同时存在于 ast.astaux(8312ce86a2fd82c0) 与 ast.tokens(fef783da4d24330d)。
  KwNode 是 `from .astaux import Keyword as KwNode` 的导入别名,_ctor_module_sha1
  只从 ModulePath(ast.attr 形态) 解析 ⇒ 裸名/别名调用拿不到 sha1;
  _get_struct_type 回退短名 Gen.structs.get('Keyword') ⇒ 撞上 tokens 的同名实例。

修复:从**已解析到的构造函数对象**的 IR 名({sha1}.{Class}.{method})取限定类名,
  仅在「同短名 + 已具化」时改判——同短名保证不会把无关类引进来,已具化保证
  _allocaEntry 的尺寸正确(opaque 实例算不出大小)。取不到限定名时保持原短名回退,
  对无同名冲突的类零变化。
This commit is contained in:
TermiNexus committed 2026-09-30 16:38:09 +08:00
1 parent cad70fa8f3
commit ba7e117ecb
1 file changed
+29 -1
+29 -1
View File
@@ -5063,11 +5063,39 @@ class ExprCallHandle(BaseHandle):
print(f"[DEBUG_CLASSNEW] _HandleClassNewLlvm called for Asm, module_sha1={module_sha1}", file=_dbg_sys.stderr)
# 跨模块类型引用:优先用 {module_sha1}.{ClassName} 查找 struct
_struct_full_key: str | None = f"{module_sha1}.{ClassName}" if module_sha1 else None
# 【同名类消歧(2026-09-30)】ClassName 可能是**导入别名**(
# `from .astaux import Keyword as KwNode` 后写作 KwNode)或短名,而
# `Gen.structs` / `Gen.functions` 的**短名键**在"两个模块各定义同名类"时是有歧义的
# ——现场:Keyword 同时存在于 ast.astaux(8312ce86a2fd82c0) 与
# ast.tokens(fef783da4d24330d)。ctor 的 self 实参按短名取到了 tokens.Keyword*,
# 而 callee 是 astaux 的 `8312ce86a2fd82c0.Keyword.__new__` ⇒ `_adjust_args` 报
# "指针隐式转换已禁止(非基本类型(结构体/类/联合)):第 0 个实参
# %"fef783da4d24330d.Keyword"* 不能隐式转为形参 %"8312ce86a2fd82c0.Keyword"*"
# (includes/ast/parser.vp:1774 `kw: rawptr[AST] = KwNode(ps.pool, None, val)`)。
# 真名从**已解析到的构造函数对象**上取(其 IR 名是 `{sha1}.{Class}.{method}`),
# 与 callee 同源;取不到时保持原行为(短名回退),对无同名冲突的类零变化。
_QCls: str | None = None
for _probe_key in (f'{ClassName}.__new__', f'{ClassName}.__before_init__', f'{ClassName}.__init__'):
_probe_fn: Any = Gen._find_function(_probe_key)
_probe_nm: str = (getattr(_probe_fn, 'name', '') or '') if _probe_fn is not None else ''
if _probe_nm.count('.') >= 2:
_QCls = _probe_nm.rsplit('.', 1)[0]
break
def _get_struct_type(name: str) -> ir.Type | None:
"""优先用 SHA1 前缀完整名查找,回退到短名"""
"""优先用 SHA1 前缀完整名查找,再按"与 callee 同源的限定名"消歧,最后回退短名"""
if _struct_full_key and _struct_full_key in Gen.structs:
return Gen.structs[_struct_full_key]
if _QCls and _QCls != name and _QCls in Gen.structs:
_qc: Any = Gen.structs[_QCls]
# 只在"**同短名**(即确实是同名类的另一份实例)且**已具化**"时改判:
# 同短名保证不会把无关类引进来;已具化保证 `_allocaEntry` 的尺寸正确
# (opaque 实例算不出大小,会让 ctor 的 self 指向尺寸错误的块)。
if (isinstance(_qc, ir.IdentifiedStructType)
and (getattr(_qc, 'name', '') or '').rsplit('.', 1)[-1]
== (name or '').rsplit('.', 1)[-1]
and _qc.elements is not None):
return _qc
return Gen.structs.get(name)
if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates: