fix(overload): _translate_method 补传 ClassDef,修复 undefined name cd

方法重载需要在类体内统计同名 def 才能决定是否追加 _v{hash},但 _translate_method 之前没有 ClassDef 参数。改为从 _translate_oop_methods 把 cd 传下去(两处调用点:sig_only 预扫描与正式翻译),未传时 _method_slot_name 退回原方法名,保持非重载路径行为不变。
This commit is contained in:
TermiNexus committed 2026-10-24 19:34:22 +08:00
1 parent 51b30d3413
commit af445058b4
1 file changed
+44 -44
+44 -44
View File
@@ -54,34 +54,34 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
for i in name:
if i == '.': return 1
return 0
# _method_slot_name - 方法在函数表 / vtable 里的短名。
# 类内同名方法 >=2 构成重载组时追加 "_v{参数签名hash}"(跳过 self);三者必须一致:
# 函数表键 "Class.m_v{hash}"、LLVM 符号 "{sha1}.Class.m_v{hash}"、vtable 槽名 "m_v{hash}"。
def _method_slot_name(self, pool: memhub.MemBuddy*, trans: HT.Translator*, cd: ast.ClassDef*, fd: ast.FunctionDef*) -> str:
"""方法短名(重载组带签名后缀);失败返回 None(已报错)"""
if fd is None or fd.name is None: return None
if cd is None or cd.children is None: return fd.name
if self.Gen.FuncGenDef._overload_name_count(cd.children, fd.name) < 2: return fd.name
if fd.type_params is not None:
self.Gen.TypeGenErr.fatal_error(fd, f"generic method '{fd.name}' cannot be overloaded (generic overloads are not supported)", "TypeError")
return None
# @staticmethod 没有 self;实例方法 / 类方法的第 0 个形参是 self,不参与签名
skip_self: int = 1
fm_s: int = self.Gen.ClassGenBase._extract_func_meta(fd.decorator_list)
if fm_s & GenTypes.META_STATIC != 0: skip_self = 0
sig: str = self.Gen.FuncGenDef._overload_sig_text(pool, fd, trans, skip_self)
if sig is None: return None
h: str = TSpec.SpecSigHash16(sig)
stdlib.free(sig)
if h is None: return None
base_len: sizet = string.strlen(fd.name)
out: str = pool.alloc(base_len + 24)
if out is None: return None
viperlib.snprintf(out, base_len + 24, "%s_v%s", fd.name, h)
return out
# _collect_vtable_methods - collect virtual methods (inherited first, then own) into the
# Vt* buffers and entry.VTableMethods/VTableMethodCount; returns 1 if any, else 0.
# _method_slot_name - 方法在函数表 / vtable 里的短名。
# 类内同名方法 >=2 构成重载组时追加 "_v{参数签名hash}"(跳过 self);三者必须一致:
# 函数表键 "Class.m_v{hash}"、LLVM 符号 "{sha1}.Class.m_v{hash}"、vtable 槽名 "m_v{hash}"。
def _method_slot_name(self, pool: memhub.MemBuddy*, trans: HT.Translator*, cd: ast.ClassDef*, fd: ast.FunctionDef*) -> str:
"""方法短名(重载组带签名后缀);失败返回 None(已报错)"""
if fd is None or fd.name is None: return None
if cd is None or cd.children is None: return fd.name
if self.Gen.FuncGenDef._overload_name_count(cd.children, fd.name) < 2: return fd.name
if fd.type_params is not None:
self.Gen.TypeGenErr.fatal_error(fd, f"generic method '{fd.name}' cannot be overloaded (generic overloads are not supported)", "TypeError")
return None
# @staticmethod 没有 self;实例方法 / 类方法的第 0 个形参是 self,不参与签名
skip_self: int = 1
fm_s: int = self.Gen.ClassGenBase._extract_func_meta(fd.decorator_list)
if fm_s & GenTypes.META_STATIC != 0: skip_self = 0
sig: str = self.Gen.FuncGenDef._overload_sig_text(pool, fd, trans, skip_self)
if sig is None: return None
h: str = TSpec.SpecSigHash16(sig)
stdlib.free(sig)
if h is None: return None
base_len: sizet = string.strlen(fd.name)
out: str = pool.alloc(base_len + 24)
if out is None: return None
viperlib.snprintf(out, base_len + 24, "%s_v%s", fd.name, h)
return out
# _collect_vtable_methods - collect virtual methods (inherited first, then own) into the
# Vt* buffers and entry.VTableMethods/VTableMethodCount; returns 1 if any, else 0.
def _collect_vtable_methods(self, trans: HT.Translator*, cd: ast.ClassDef*, class_name: str) -> int:
"""Collect virtual methods into entry.VTableMethods/VTableMethodCount."""
if trans is None or cd is None or class_name is None: return 0
@@ -237,12 +237,12 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
# stay loud rather than writing past the PermPool array.
self.Gen.TypeGenErr.fatal_error(cd, f"internal error: vtable of '{class_name}' exceeded its computed capacity {vt_cap}", "InternalCompilerError")
mname: str = rawptr(slot_names[ci])
if mname is None: mname = fd.name
# Skip constructors and special methods (they must not enter the vtable).
# 用 fd.name 判断:重载组的槽名带后缀,用槽名会漏判把 __init__ 塞进 vtable。
if string.strcmp(fd.name, "__init__") == 0: continue
if string.strcmp(fd.name, "__before_init__") == 0: continue
mname: str = rawptr(slot_names[ci])
if mname is None: mname = fd.name
# Skip constructors and special methods (they must not enter the vtable).
# 用 fd.name 判断:重载组的槽名带后缀,用槽名会漏判把 __init__ 塞进 vtable。
if string.strcmp(fd.name, "__init__") == 0: continue
if string.strcmp(fd.name, "__before_init__") == 0: continue
if string.strcmp(fd.name, "__new__") == 0: continue
# Function-level decorator filter: decide whether the method belongs in the vtable.
if self.Gen.ClassGenBase._should_method_be_virtual(cd, fd, trans) == 0: continue
@@ -503,7 +503,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
if stmt_pd is None: continue
if stmt_pd.kind() == ast.ASTKind.FunctionDef:
fd_pd: ast.FunctionDef* = ast.FunctionDef*(stmt_pd)
if fd_pd is not None and fd_pd.name is not None: self._translate_method(trans, fd_pd, struct_ty, class_name, 1)
if fd_pd is not None and fd_pd.name is not None: self._translate_method(trans, fd_pd, struct_ty, class_name, 1, cd)
for ci in range(int(cn)):
stmt: ast.AST* = children.get(ci)
@@ -517,7 +517,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
prev_nf: ast.AST* = self.Gen.StructGen.NllCurFunc
self.Gen.StructGen.NllCurFunc = fd
self.Gen.TypeGenBase.push_trace(tr_mf, fd.lineno)
self._translate_method(trans, fd, struct_ty, class_name)
self._translate_method(trans, fd, struct_ty, class_name, 0, cd)
self.Gen.TypeGenBase.pop_trace()
self.Gen.StructGen.NllCurFunc = prev_nf
@@ -560,7 +560,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
return 0
# _translate_method - emit define <ret_ty> @SHA1.ClassName.method_name(Ptr(StructTy) %self, ...).
# self is registered as an SSA Ptr(struct_ty) value (no alloca) so self.field can GEP directly.
def _translate_method(self, trans: HT.Translator*, fd: ast.FunctionDef*, struct_ty: mlirlite.LLVMType*, class_name: str, sig_only: int = 0) -> int:
def _translate_method(self, trans: HT.Translator*, fd: ast.FunctionDef*, struct_ty: mlirlite.LLVMType*, class_name: str, sig_only: int = 0, cd: ast.ClassDef* = None) -> int:
"""Translate a single method; sig_only emits a forward declaration only."""
if trans is None or fd is None or struct_ty is None or class_name is None: return 0
@@ -594,13 +594,13 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
elif func_meta & GenTypes.META_PROP_DELETER != 0:
mn_len2: sizet = string.strlen(method_name_buf)
if mn_len2 + 5 < 128: string.strcat(method_name_buf, "$del")
method_name = method_name_buf
# 重载:类内同名方法 >=2 时短名追加 "_v{签名hash}",使符号、函数表键与 vtable 槽名一致。
# 属性 setter/deleter 已带 $set/$del 后缀,不参与重载。
if func_meta & GenTypes.META_PROP_SETTER == 0 and func_meta & GenTypes.META_PROP_DELETER == 0:
slot_nm_m: str = self._method_slot_name(pool, trans, cd, fd)
if slot_nm_m is None: return 0
method_name = method_name_buf
# 重载:类内同名方法 >=2 时短名追加 "_v{签名hash}",使符号、函数表键与 vtable 槽名一致。
# 属性 setter/deleter 已带 $set/$del 后缀,不参与重载。
if func_meta & GenTypes.META_PROP_SETTER == 0 and func_meta & GenTypes.META_PROP_DELETER == 0:
slot_nm_m: str = self._method_slot_name(pool, trans, cd, fd)
if slot_nm_m is None: return 0
method_name = slot_nm_m
is_static_m: int = 0