feat(gen): 实现 super() 语义(super().__init__ / super().method 静态绑定父类)

- 新增 _translate_super_call:当前类取 self 变量注解类名(Mixin 字段
  跨类偏移不一致的替代方案),沿 MRO 跳过自身找父类方法,静态调用
  父类实现(不虚分派),this_adjust 字节偏移 + 参数 coerce
- translate_call 拦截 super().method 形态
This commit is contained in:
TermiNexus committed 2026-08-10 21:48:42 +08:00
1 parent 45ba3a4b5a
commit cca468e910
1 file changed
+206
+206
View File
@@ -3728,6 +3728,199 @@ class CallGenMixin:
is_variadic_3441: int = HandlesExprCall._check_and_promote_variadic_call(pool, builder, mod, call_name, head, total_count)
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, is_variadic_3441)
# ============================================================
# _translate_super_call — super().method(args) → 静态调用父类方法
#
# Python super 语义(2026-08-10 实现):
# - 当前类来自 self.CurClassName(_translate_method 翻译方法体时设置)
# - 父类查找:沿 get_mro_chain(CurClassName) 跳过自身,找第一个定义 method 的祖先
# - self 指针:符号表 self 变量 alloca load(对象头,复用 c.Addr(self) 模式)
# - this_adjust:父类字段区在子类中字节偏移 delta>0 时 GEP i8* + delta
# (复用 _field_byte_offset 字节偏移法,与 _translate_method_call 一致)
# - 静态调用父类实现:不虚分派(super() 不触发子类 override)
# ============================================================
def _translate_super_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
method_name: str,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""super().method(args) → 父类方法静态调用,返回 call 结果 Value"""
if pool is None or builder is None or cl is None or method_name is None:
return None
if trans is None:
return None
# 1. 当前方法所属类:从 self 变量的注解类名获取(_translate_method
# 注册 self 时 set_var_annot_class_name(SymTab, "self", class_name))。
# 不用 Mixin 字段:TPV Mixin 字段按声明类独立布局(Generator 多继承
# 去重只保留首个声明),ClassGenMixin 写的 CurClassName 与 CallGenMixin
# 读的位置偏移不一致 → 运行时读到空 → super() 误报"只能在类方法内使用"。
self_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, "self")
if self_entry is None:
self_entry = HandlesVar.lookup_var_entry(trans.SymTab, "cls")
if self_entry is None:
HandlesType.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError")
return None
cur_class: str = self_entry.AnnotClassName
if cur_class is None:
HandlesType.fatal_error(cl, "super() 只能在类方法内使用(self 无注解类名)")
return None
# 2. 沿 MRO 跳过自身,找第一个定义 method 的祖先类
anc: str = None
mro_sp: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, cur_class)
mi_sp: int = 1
while mro_sp is not None and mro_sp[mi_sp] != 0:
anc_sp: str = (str | t.CPtr)(t.CVoid(mro_sp[mi_sp], t.CPtr))
if anc_sp is not None:
probe_sp: t.CChar | t.CPtr = pool.alloc(160)
if probe_sp is not None:
viperlib.snprintf(probe_sp, 160, "%s.%s", anc_sp, method_name)
if HandlesExprCall.find_func_global(probe_sp) is not None:
anc = anc_sp
break
mi_sp += 1
if anc is None:
err_sp: t.CChar | t.CPtr = pool.alloc(256)
if err_sp is not None:
viperlib.snprintf(err_sp, 256, "super(): 当前类 %s 的父类链未定义方法 %s",
cur_class, method_name)
HandlesType.fatal_error(cl, err_sp, "TypeError")
HandlesType.fatal_error(cl, "super(): 父类链未定义方法", "TypeError")
return None
# 3. self 指针(self 变量 alloca load,复用 c.Addr(self) 模式)
if self_entry.Alloca is None or self_entry.Alloca.Ty is None:
HandlesType.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError")
return None
self_ptr: llvmlite.Value | t.CPtr = None
match self_entry.Alloca.Ty:
case llvmlite.LLVMType.Ptr(inner1):
match inner1:
case llvmlite.LLVMType.Ptr(inner2):
obj_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2)
self_ptr = llvmlite.build_load(builder, obj_ty_sp, self_entry.Alloca)
case _:
self_ptr = llvmlite.build_load(builder, self_entry.Alloca.Ty, self_entry.Alloca)
case _:
self_ptr = self_entry.Alloca
if self_ptr is None:
return None
# 3. this_adjust(字节偏移法:父类字段区在子类中的偏移差)
self_arg: llvmlite.Value | t.CPtr = self_ptr
if string.strcmp(anc, cur_class) != 0:
anc_entry_sp: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(anc)
if anc_entry_sp is not None and anc_entry_sp.FieldCount > 0:
first_name_sp: str = None
afi_sp: int = 0
while afi_sp < anc_entry_sp.FieldCount:
afe_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
anc_entry_sp, afi_sp)
if afe_sp is not None:
afn_sp: str = HandlesStruct.get_field_name_ptr(afe_sp)
if afn_sp is not None and string.strcmp(afn_sp, "__vtable__") != 0:
first_name_sp = afn_sp
break
afi_sp += 1
if first_name_sp is not None:
sub_entry_sp: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
cur_class)
if sub_entry_sp is not None:
anc_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
anc_entry_sp.Ty, first_name_sp)
sub_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
sub_entry_sp.Ty, first_name_sp)
if anc_field_sp is not None and sub_field_sp is not None:
anc_off_sp: int = self._field_byte_offset(
pool, anc_entry_sp, anc_field_sp.Index)
sub_off_sp: int = self._field_byte_offset(
pool, sub_entry_sp, sub_field_sp.Index)
delta_sp: int = sub_off_sp - anc_off_sp
if delta_sp > 0:
i8_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_sp)
obj_i8_sp: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, self_ptr, i8_ptr_sp)
dval_sp: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, delta_sp)
adj_sp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i8_ty_sp, obj_i8_sp, dval_sp)
if adj_sp is not None:
anc_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_sp.Ty)
self_arg = llvmlite.build_bitcast(builder, adj_sp, anc_ptr_sp)
# 4. 查找父类方法函数 + 构造调用名(SHA1 mangled)
anc_lookup: t.CChar | t.CPtr = pool.alloc(160)
if anc_lookup is None:
return None
viperlib.snprintf(anc_lookup, 160, "%s.%s", anc, method_name)
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, anc_lookup)
call_name: str = anc_lookup
anc_sha1_sp: str = HandlesStruct.get_struct_sha1(anc)
if anc_sha1_sp is None:
anc_sha1_sp = trans.ModuleSha1
if found_func is not None:
fname_sp: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
if fname_sp is not None:
call_name = fname_sp
else:
if anc_sha1_sp is not None:
mangled_sp: str = HandlesFunctions._mangle_name_with_sha1(anc_sha1_sp, anc_lookup)
if mangled_sp is not None:
call_name = mangled_sp
# 5. 翻译参数 + 按形参 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
cargs_sp: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can_sp: t.CSizeT = 0
if cargs_sp is not None:
can_sp = cargs_sp.__len__()
llvmlite.value_set_next(self_arg, None)
head: llvmlite.Value | t.CPtr = self_arg
tail: llvmlite.Value | t.CPtr = self_arg
arg_count_sp: int = 1
for ai_sp in range(can_sp):
arg_node_sp: ast.AST | t.CPtr = cargs_sp.get(ai_sp)
if arg_node_sp is None:
continue
arg_val_sp: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node_sp, None, 0, trans)
if arg_val_sp is None:
continue
if found_func is not None:
pp_sp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
pi_sp: int = 0
while pp_sp is not None and pi_sp < ai_sp + 1:
if pi_sp == ai_sp + 1:
break
pp_sp = llvmlite.param_get_next(pp_sp)
pi_sp += 1
if pp_sp is not None:
pty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp_sp)
if pty_sp is not None:
arg_val_sp = HandlesExpr.coerce_to_type(
builder, arg_val_sp, pty_sp, arg_node_sp)
llvmlite.value_set_next(arg_val_sp, None)
llvmlite.value_set_next(tail, arg_val_sp)
tail = arg_val_sp
arg_count_sp += 1
# 6. 返回类型:found_func → 特殊方法 → text.ll/vpi
ret_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if found_func is not None:
frt_sp: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt_sp is not None:
ret_ty_sp = frt_sp
else:
sp_ty_sp: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, anc, method_name)
if sp_ty_sp is not None:
ret_ty_sp = sp_ty_sp
else:
looked_sp: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
pool, anc_sha1_sp, anc, method_name)
if looked_sp is not None:
ret_ty_sp = looked_sp
# 7. 跨模块:创建 declare;生成 call
if found_func is None:
self._ensure_method_declare(pool, mod, call_name, ret_ty_sp, head, arg_count_sp)
is_variadic_sp: int = HandlesExprCall._check_and_promote_variadic_call(
pool, builder, mod, call_name, head, arg_count_sp)
return llvmlite.build_call(builder, call_name, head, arg_count_sp, ret_ty_sp, is_variadic_sp)
# ============================================================
# _field_byte_offset — 计算字段在结构体布局中的字节偏移
#
@@ -4392,6 +4585,19 @@ class CallGenMixin:
return None
func_name: str = HandlesExpr.get_func_name(cl.func)
# super() 语义(2026-08-10):super().method(args) → 静态调用父类方法
# 形态: Call(func=Attribute(value=Call(func=Name('super')), attr=method))
# 必须在 Attribute 分派前拦截——否则 value 的 Call(super) 被 translate_value
# 当作普通函数调用报错,且走普通属性调用会命中自身/虚分派而非父类实现。
if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
sup_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if sup_at.value is not None and sup_at.value.kind() == ast.ASTKind.Call:
sup_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(sup_at.value)
if sup_cl.func is not None and sup_cl.func.kind() == ast.ASTKind.Name:
sup_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sup_cl.func)
if sup_nm.id is not None and string.strcmp(sup_nm.id, "super") == 0:
return self._translate_super_call(
pool, builder, mod, cl, func_name, trans)
if func_name is None:
# 检查是否是 list[int](pool) 形式的泛型实例化调用
# Subscript 节点作为 Call func: 泛型类构造函数