feat(core): TPC 多继承同步 M5 - MRO 查找/字段展平/vtable合并/this调整

BaseGen: 新增 class_parents + _get_mro_chain(与 TPV 语义一致: 深度优先
+声明顺序+去重) 与 _get_parent_classes 兼容旧单链
HandlesClassDef: 停用 is_base_of_any 自动 vtable; 多父字段展平去重;
方法合并用定义类名; vtable 槽沿 MRO 取定义类
HandlesExprCall: 方法调用沿 MRO 回退 + stub(无函数体)判定修复
undefined reference; 继承方法 this 调整(GEP+bitcast 成父类指针)
HandlesExprUtils/HandlesImports/HandlesWith/StructGen: MRO 查找同步
This commit is contained in:
TermiNexus committed 2026-08-10 00:29:05 +08:00
1 parent fc93a28ec6
commit 87b9dec1ef
7 files changed
+344 -128

No files matched your search

+114 -65
View File
@@ -406,17 +406,14 @@ class ClassHandle(BaseHandle):
if class_graph.get(ClassName, {}).get('has_methods', False) and not IsNoVTable:
if not IsCpythonObject:
IsCpythonObject = True
# 仅当该类作为其他类的基类时,才启用 CVTable
# 检查 _class_graph 中是否有任何类将此类作为基类
is_base_of_any: bool = False
for other_cls, info in class_graph.items():
if ClassName in info.get('bases', []):
is_base_of_any = True
break
if is_base_of_any:
IsCVTable = True
# 多继承支持(与 TPV _detect_vtable_status 对齐):不再因"作为其他类的基类"
# 自动启用 vtable。vtable 状态统一由继承链决定(见下方 HasParentClass 判定):
# 类自身无 @t.CVTable 时,父类有 vtable → 子类有;父类无 vtable → 子类静态。
# 否则基类(如 C(A,B) 中的 A/B)被自动加 vptr 后,其字段区在子类中的偏移
# 与自身布局不一致,继承方法按自身布局读 self 会字段错位。
HasParentClass: bool = False
ParentClassName: str | None = None
ParentClasses: list[str] = []
ParentIsNoVTable: bool = False
if Node.bases:
for base in Node.bases:
@@ -429,18 +426,29 @@ class ClassHandle(BaseHandle):
kind: str | None = self._resolve_base_kind(base_name, Gen)
if kind is not None or base_name in t._MARKER_BASES:
continue # 标记基类,跳过
# 多继承:收集所有真实父类(声明顺序),不再 break
ParentClasses.append(base_name)
if ParentClassName is None:
ParentClassName = base_name
if base_name in class_graph or base_name in Gen.class_members or base_name in Gen.structs:
HasParentClass = True
ParentClassName = base_name
# 检测父类是否有 @t.NoVTable 标记(非多态继承)
if class_graph.get(base_name, {}).get('has_novtable', False):
ParentIsNoVTable = True
# 跨模块父类:检查 _cross_module_novtable 集合
if base_name in Gen._cross_module_novtable:
ParentIsNoVTable = True
break
# 检测父类是否有 @t.NoVTable 标记(非多态继承)
if class_graph.get(base_name, {}).get('has_novtable', False):
ParentIsNoVTable = True
# 跨模块父类:检查 _cross_module_novtable 集合
if base_name in Gen._cross_module_novtable:
ParentIsNoVTable = True
if HasParentClass and not IsCVTable and not IsNoVTable and not ParentIsNoVTable:
IsCVTable = True
# 继承链统一 vtable(与 TPV _detect_vtable_status 一致):
# 父类有 vtable → 子类启用;父类无 vtable → 子类不启用(静态);
# 父类 vtable 状态未知(跨模块/未注册)→ 保守启用。
parent_has_vtable: bool = (ParentClassName in Gen.class_vtable
or ParentClassName in Gen._cross_module_vtable_classes)
parent_known: bool = (ParentClassName in class_graph
or ParentClassName in Gen.class_members
or ParentClassName in Gen.structs)
if parent_has_vtable or not parent_known:
IsCVTable = True
if IsCVTable:
Gen.class_vtable.add(ClassName)
# 沿继承链向上传播,将所有祖先类加入 vtable
@@ -572,6 +580,7 @@ class ClassHandle(BaseHandle):
Gen.class_member_byteorders[ClassName] = {}
Gen.class_member_bitoffsets[ClassName] = {}
ParentClass: str | None = None
ParentClasses: list[str] = []
if Node.bases:
class_graph: dict = Gen._class_graph
for base in Node.bases:
@@ -593,49 +602,83 @@ class ClassHandle(BaseHandle):
continue
if base_name in ('Object', 'CVTable', 'NoVTable', 'CStruct', 'CUnion', 'CEnum', 'REnum', 'Exception', 'Enum'):
continue
# 多继承:收集所有真实父类(声明顺序),不再 break。
# 总是记录父类名,即使父类 class_members 未加载。
# _get_member_offset 会沿 class_parent 链回退查找继承字段。
ParentClass = base_name
Gen.class_parent[ClassName] = ParentClass
break
if ParentClass and (ParentClass in class_graph or ParentClass in Gen.class_members):
parent_members: list = list(Gen.class_members[ParentClass])
parent_defaults: dict = dict(Gen.class_member_defaults.get(ParentClass, {}))
existing_names: set = {m[0] for m in Gen.class_members[ClassName]}
inherited: list[tuple] = []
for pm_name, pm_type in parent_members:
if pm_name not in existing_names:
inherited.append((pm_name, pm_type))
if pm_name in parent_defaults:
Gen.class_member_defaults[ClassName][pm_name] = parent_defaults[pm_name]
Gen.class_members[ClassName] = inherited + Gen.class_members[ClassName]
if ParentClass in Gen.class_methods:
parent_methods: list = list(Gen.class_methods[ParentClass])
# 构建子类已有方法映射(方法短名 -> 方法全名)
if ParentClass is None:
ParentClass = base_name
Gen.class_parent[ClassName] = ParentClass
ParentClasses.append(base_name)
if ParentClasses:
Gen.class_parents[ClassName] = ParentClasses
if ParentClasses:
# ============================================================
# 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明父类优先),
# __vtable__ 跳过(vtable 指针由 _generate_structs 按 class_vtable 统一添加)。
# 布局: [父类1字段..., 父类2字段..., 子类字段...]
# ============================================================
for ParentClass in ParentClasses:
if ParentClass not in class_graph and ParentClass not in Gen.class_members:
continue
parent_members: list = list(Gen.class_members.get(ParentClass, []))
parent_defaults: dict = dict(Gen.class_member_defaults.get(ParentClass, {}))
existing_names: set = {m[0] for m in Gen.class_members[ClassName]}
inherited: list[tuple] = []
for pm_name, pm_type in parent_members:
if pm_name == '__vtable__':
continue
if pm_name not in existing_names:
inherited.append((pm_name, pm_type))
if pm_name in parent_defaults:
Gen.class_member_defaults[ClassName][pm_name] = parent_defaults[pm_name]
if inherited:
Gen.class_members[ClassName] = inherited + Gen.class_members[ClassName]
# ============================================================
# 多继承方法合并:遍历所有父类(声明顺序)收集方法(短名去重,先声明父类优先),
# vtable 槽/方法名用"实际定义类.方法"(如 B.get_b,与 TPV 一致),
# 不再生成子类包装器 "ClassName.method"(旧逻辑注册了包装器但未生成函数体,
# 导致链接 undefined reference,如 C.get_b / ColoredCircle.color_code / Vec2Both.extra_val)。
# ============================================================
all_parent_methods: list[str] = []
parent_method_names_seen: set[str] = set()
for ParentClass in ParentClasses:
for pm in list(Gen.class_methods.get(ParentClass, [])):
method_name: str = pm.split('.')[-1] if '.' in pm else pm
if method_name in ('__new__', '__init__', '__before_init__'):
continue
if method_name in parent_method_names_seen:
continue # 先声明父类优先,菱形去重
parent_method_names_seen.add(method_name)
all_parent_methods.append(pm)
if all_parent_methods:
# 构建子类已有方法映射(方法短名 -> 方法全名)。
# 子类覆盖判定:既查 class_methods(prescan/导入阶段已注册),
# 也直接扫描 ClassDef 自身的方法(与 TPV _collect_vtable_methods 一致)。
child_method_map: dict[str, str] = {}
for m in Gen.class_methods[ClassName]:
method_name: str = m.split('.')[-1] if '.' in m else m
child_method_map[method_name] = m
for _item_self in Node.body:
if isinstance(_item_self, ast.FunctionDef):
_mn_self: str = _item_self.name
if _mn_self in ('__new__', '__init__', '__before_init__'):
continue
child_method_map[_mn_self] = f"{ClassName}.{_mn_self}"
# 父类方法在前(保证 vtable 布局一致性,子类多态分派索引正确),
# 子类新增方法在后。子类覆盖的方法放在父类方法的位置(用子类实现)。
new_methods: list = []
covered_names: set[str] = set()
for pm in parent_methods:
for pm in all_parent_methods:
method_name: str = pm.split('.')[-1] if '.' in pm else pm
if method_name in child_method_map:
# 子类覆盖了父类方法 — 用子类的实现,放在父类的位置
new_methods.append(child_method_map[method_name])
covered_names.add(method_name)
else:
# 父类独有方法 — 子类未覆盖,注册子类包装器
child_method: str = f"{ClassName}.{method_name}"
new_methods.append(child_method)
Gen.register_method(ClassName, child_method)
# 父类独有方法 — 直接用父类方法原名(定义类名,如 B.get_b)
new_methods.append(pm)
covered_names.add(method_name)
# 添加子类新增方法(不在父类中的)
# 用快照遍历:register_method 会原地修改 class_methods,
# 若遍历活列表会把父类独有方法(已由 register_method 追加)再次追加,
# 导致 vtable 槽数与跨模块调用方推断不一致(如 MemBuddy 36 槽 vs 28 槽)。
for m in list(Gen.class_methods[ClassName]):
method_name: str = m.split('.')[-1] if '.' in m else m
if method_name not in covered_names:
@@ -766,9 +809,11 @@ class ClassHandle(BaseHandle):
self.Trans.FunctionHandler._EmitFunctionLlvm(item, Gen, ClassName=ClassName)
if IsCVTable and ClassName in Gen.Vtables:
self._fill_vtable_with_methods(ClassName, Gen)
# Generate wrapper functions for inherited methods that are not overridden
if ParentClass:
self._generate_inherited_method_wrappers(ClassName, Gen)
# 多继承支持:不再生成子类包装器(_generate_inherited_method_wrappers)。
# 包装器只对 self 做 bitcast 基址转换,不调整字段偏移——对多继承中
# 第二个及之后的父类(字段区偏移 > 0)会错位。继承方法统一走
# MRO 祖先链查找 + this 调整(见 HandlesExprCall._adjust_this_for_inherited_method),
# 与 TPV 一致。
Gen._classes_in_progress.discard(ClassName)
def _generate_inherited_method_wrappers(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
@@ -777,19 +822,20 @@ class ClassHandle(BaseHandle):
例如 Label 继承 Widget.place,生成 Label.place 函数,
内部将 self 从 Label* bitcast 为 Widget*,然后调用 Widget.place。
"""
# 收集本类方法 + 沿继承链收集父类方法名
# 收集本类方法 + 沿 MRO 继承链收集父类方法名
# 原代码只遍历 class_methods[ClassName],遗漏父类独有方法(如 __enter__),
# 导致子类调用继承的方法时链接失败(undefined reference)
methods: list = list(Gen.class_methods.get(ClassName, []))
p: str | None = Gen.class_parent.get(ClassName) if hasattr(Gen, 'class_parent') else None
while p:
parent_methods: list = Gen.class_methods.get(p, [])
seen_shorts: set[str] = {m.split('.')[-1] if '.' in m else m for m in methods}
mro_list: list[str] = Gen._get_mro_chain(ClassName)
for anc in mro_list[1:]: # 跳过自身,先声明父类优先(MRO 已去重)
parent_methods: list = Gen.class_methods.get(anc, [])
for pm in parent_methods:
pm_short: str = pm.split('.')[-1] if '.' in pm else pm
# 避免重复:如果子类已覆写同名方法,不添加
if not any(m.split('.')[-1] == pm_short for m in methods):
if pm_short not in seen_shorts:
seen_shorts.add(pm_short)
methods.append(pm)
p = Gen.class_parent.get(p)
if not methods:
return
if ClassName not in Gen.structs:
@@ -803,17 +849,15 @@ class ClassHandle(BaseHandle):
if Gen._find_function(child_full):
continue
# 沿继承链查找父类实现
# 沿 MRO 继承链查找父类实现(先声明父类优先)
parent_func: ir.Function | None = None
parent_class: str | None = None
p: str | None = Gen.class_parent.get(ClassName)
while p:
parent_full: str = f"{p}.{method_short}"
for anc in Gen._get_mro_chain(ClassName)[1:]:
parent_full: str = f"{anc}.{method_short}"
parent_func = Gen._find_function(parent_full)
if parent_func:
parent_class = p
parent_class = anc
break
p = Gen.class_parent.get(p)
if not parent_func or not parent_class:
continue
@@ -902,19 +946,24 @@ class ClassHandle(BaseHandle):
null_i8ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
initializers: list[ir.Constant] = []
for mi, method_name in enumerate(methods):
method_short: str = method_name.split('.')[-1] if '.' in method_name else method_name
func: ir.Function | None = Gen._find_function(f"{ClassName}.{method_short}")
# 多继承:vtable 槽直接用完整方法名(实际定义类.方法,如 B.get_b),
# 与 TPV 一致,避免"子类名.方法"包装器导致链接 undefined reference。
func: ir.Function | None = Gen._find_function(method_name)
if not func:
func = Gen._find_function(f"{method_name}__")
if not func:
method_short: str = method_name.split('.')[-1] if '.' in method_name else method_name
func = Gen._find_function(f"{ClassName}.{method_short}")
if not func:
func = Gen._find_function(f"{ClassName}.{method_short}__")
if not func:
p: str | None = Gen.class_parent.get(ClassName)
while p:
func = Gen._find_function(f"{p}.{method_short}")
# 沿 MRO 祖先链查找定义类(先声明父类优先)
for anc in Gen._get_mro_chain(ClassName)[1:]:
func = Gen._find_function(f"{anc}.{method_short}")
if not func:
func = Gen._find_function(f"{p}.{method_short}__")
func = Gen._find_function(f"{anc}.{method_short}__")
if func:
break
p = Gen.class_parent.get(p)
if func:
initializers.append(func.bitcast(ir.PointerType(ir.IntType(8))))
else:
+127 -31
View File
@@ -885,19 +885,23 @@ class ExprCallHandle(BaseHandle):
func_type = ir.FunctionType(ret_type, llvm_param_types)
func = ir.Function(Gen.module, func_type, name=MangledName)
Gen.functions[MangledName] = func
if not func:
p = Gen.class_parent.get(ClassName)
while p:
parent_mangled = Gen._mangle_name(f'{p}.{MethodName}')
# 方法实际定义类(多继承 this 调整用)
method_anc_st: str | None = None
# 若 MangledName 只有 stub 声明(无函数体),也走 MRO 回退找定义类方法
if not func or len(list(func.blocks)) == 0:
# 多继承:沿 MRO 祖先链查找(先声明父类优先)
for anc in Gen._get_mro_chain(ClassName)[1:]:
parent_mangled = Gen._mangle_name(f'{anc}.{MethodName}')
parent_func = Gen.functions.get(parent_mangled)
if parent_func:
func = parent_func
method_anc_st = anc
break
parent_func = Gen._find_function(f'{p}.{MethodName}')
parent_func = Gen._find_function(f'{anc}.{MethodName}')
if parent_func:
func = parent_func
method_anc_st = anc
break
p = Gen.class_parent.get(p)
if not func:
return None
CallArgs = []
@@ -932,7 +936,10 @@ class ExprCallHandle(BaseHandle):
if self._is_char_pointer(ObjVal):
if ClassName in Gen.structs:
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_static")
CallArgs[0] = ObjVal
# 多继承 this 调整(仅调整 self 参数;vtable 槽位读取用原始 ObjVal,
# 因为 vptr 总在对象首字段,与 TPV _do_virtual_call 一致)
self_arg_st = self._adjust_this_for_inherited_method(Gen, ObjVal, ClassName, method_anc_st)
CallArgs[0] = self_arg_st
VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}_static")
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_static")
VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
@@ -2194,9 +2201,13 @@ class ExprCallHandle(BaseHandle):
else:
self_methods.append(f"{class_name}.{method_name}")
# 收集基类方法
# 收集基类方法(多继承:遍历所有父类,声明顺序,短名去重,先声明父类优先)
parent_methods: list[str] = []
parent_name: str | None = None
parent_names: list[str] = []
parent_method_names_seen: set[str] = set()
# 第一个真实父类的 vtable 状态(None=无父类/未知)
first_parent_vtable: bool | None = None
for base in target_node.bases:
base_name: str | None = None
if hasattr(base, 'id'):
@@ -2205,6 +2216,7 @@ class ExprCallHandle(BaseHandle):
base_name = base.attr
if not base_name or base_name in ('Object', 'CVTable', 'NoVTable', 'CStruct', 'CUnion', 'CEnum', 'REnum', 'Exception', 'Enum'):
continue
parent_names.append(base_name)
if parent_name is None:
parent_name = base_name
@@ -2212,28 +2224,43 @@ class ExprCallHandle(BaseHandle):
base_node = class_map.get(base_name)
if base_node is not None:
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, sha1, visited)
if base_novtable:
pass # 父类是 NoVTable,不继承 vtable
elif base_cvtable:
is_cvtable = True
parent_methods.extend(base_methods)
# 仅第一个真实父类决定 vtable 继承状态(与 _resolve_class_flags 一致)
if parent_name == base_name:
first_parent_vtable = (base_cvtable and not base_novtable)
for bm in base_methods:
bmn = bm.split('.')[-1] if '.' in bm else bm
if bmn not in parent_method_names_seen:
parent_method_names_seen.add(bmn)
parent_methods.append(bm)
else:
# 跨模块基类 — 查找基类的 sha1
base_sha1 = struct_sha1_map.get(base_name)
if base_sha1:
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, base_sha1, visited)
if base_novtable:
pass
elif base_cvtable:
is_cvtable = True
parent_methods.extend(base_methods)
if parent_name == base_name:
first_parent_vtable = (base_cvtable and not base_novtable)
for bm in base_methods:
bmn = bm.split('.')[-1] if '.' in bm else bm
if bmn not in parent_method_names_seen:
parent_method_names_seen.add(bmn)
parent_methods.append(bm)
else:
# 无法找到基类的 sha1
# 无法找到基类的 sha1 → 父类信息未知,保守启用 vtable
if parent_name == base_name and first_parent_vtable is None:
first_parent_vtable = True
if base_name in Gen._cross_module_novtable:
pass # 父类是 NoVTable,不继承 vtable
# 继承链统一 vtable(与 _resolve_class_flags 一致):
# 类自身无 @t.CVTable 时,第一个父类有 vtable → 子类启用;
# 父类无 vtable → 子类静态;父类信息未知 → 保守启用。
if not is_cvtable and not is_novtable and first_parent_vtable is not None:
if first_parent_vtable:
is_cvtable = True
# 合并方法列表:基类方法在前,子类方法在后
# 子类覆盖的方法放在父类的位置
# 子类覆盖的方法放在父类的位置;
# 父类独有方法直接用父类方法原名(实际定义类.方法,与 TPV 一致)
child_method_map: dict[str, str] = {}
for m in self_methods:
mn = m.split('.')[-1] if '.' in m else m
@@ -2247,8 +2274,8 @@ class ExprCallHandle(BaseHandle):
merged.append(child_method_map[mn])
covered_names.add(mn)
else:
# 父类独有方法 — 用子类名(虚分派时函数查找会沿继承链回退)
merged.append(f"{class_name}.{mn}")
# 父类独有方法 — 用父类方法原名(虚分派时函数查找沿 MRO 回退)
merged.append(pm)
for m in self_methods:
mn = m.split('.')[-1] if '.' in m else m
@@ -2269,9 +2296,15 @@ class ExprCallHandle(BaseHandle):
Gen.class_vtable.add(ClassName)
# 设置方法列表(与 prescan 逻辑一致:基类方法在前)
Gen.class_methods[ClassName] = methods
# 设置 class_parent(用于虚分派时的函数查找回退)
# 设置 class_parent / class_parents(用于虚分派时的函数查找回退与 MRO)
if parent_name and ClassName not in Gen.class_parent:
Gen.class_parent[ClassName] = parent_name
parent_names_map = getattr(Gen, 'class_parents', None)
if parent_names_map is None:
parent_names_map = {}
Gen.class_parents = parent_names_map
if parent_name and ClassName not in parent_names_map:
parent_names_map[ClassName] = [parent_name]
except Exception:
pass
@@ -2332,6 +2365,45 @@ class ExprCallHandle(BaseHandle):
# 失败时恢复 declare_only 标记,避免后续调用跳过补发
Gen._generic_class_specializations[spec_key] = (cached_name, True)
def _adjust_this_for_inherited_method(self, Gen: LlvmGeneratorMixin, ObjVal: ir.Value,
ClassName: str, method_anc: str | None) -> ir.Value:
"""多继承 this 调整(与 TPV _translate_method_call 一致):
继承方法定义在"无 vtable 的父类"且该父类字段区在子类中偏移 > 0 时
(如 C(A,B).get_b,B 的字段区从 b 开始),父类方法按自身布局读
self.field@0 会读到前面父类的字段。调整:GEP 到父类第一个用户字段
在子类中的位置(索引 > 0),bitcast 成父类指针作为 self。
有 vtable 的父类布局是子类前缀(vptr 共享),self 无需调整。
"""
if method_anc is None or method_anc == ClassName:
return ObjVal
anc_has_vtable: bool = (method_anc in Gen.class_vtable
or method_anc in Gen._cross_module_vtable_classes)
if anc_has_vtable:
return ObjVal
anc_members: list = Gen.class_members.get(method_anc, [])
if not anc_members:
return ObjVal
first_field_name: str | None = None
for _fn, _ft in anc_members:
if _fn == '__vtable__':
continue
first_field_name = _fn
break
if first_field_name is None:
return ObjVal
field_idx: int | None = Gen._get_member_offset(first_field_name, ClassName)
if field_idx is None or field_idx <= 0:
return ObjVal
if method_anc not in Gen.structs:
return ObjVal
adj: ir.Value = Gen.builder.gep(
ObjVal,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), field_idx)],
name=f"this_adjust_{method_anc}")
return Gen.builder.bitcast(adj, ir.PointerType(Gen.structs[method_anc]),
name=f"this_adjust_cast_{method_anc}")
def _HandleMethodCallLlvm(self, Node: ast.Call) -> ir.Value:
Gen = self.Trans.LlvmGen
MethodName = Node.func.attr
@@ -2800,18 +2872,22 @@ class ExprCallHandle(BaseHandle):
break
if method_idx >= 0:
func = Gen._find_function(FullMethodName)
if not func:
# 方法实际定义类(多继承 this 调整用,None=本类或未知)
method_anc: str | None = None
# 仅当无函数或只有 stub 声明(无函数体)时,沿 MRO 祖先链回退,
# 否则 stub 会挡住回退导致 this 调整失效(与直接调用路径一致)
if not func or len(list(func.blocks)) == 0:
func = Gen._find_function(f'{FullMethodName}__')
if not func:
p = Gen.class_parent.get(ClassName)
while p:
parent_full = f'{p}.{MethodName}'
if not func or len(list(func.blocks)) == 0:
# 多继承:沿 MRO 祖先链查找定义类方法(先声明父类优先)
for anc in Gen._get_mro_chain(ClassName)[1:]:
parent_full = f'{anc}.{MethodName}'
func = Gen._find_function(parent_full)
if not func:
func = Gen._find_function(f'{parent_full}__')
if func:
method_anc = anc
break
p = Gen.class_parent.get(p)
# 修复:vtable 分派需要 func 的函数类型。当 func=None 时(如 __new__
# 编译较早,MemManager.alloc 的 declare 尚未加入 Gen.functions),
# 从 stub 获取函数类型并创建 declare,确保 vtable 分派不被跳过
@@ -2829,6 +2905,9 @@ class ExprCallHandle(BaseHandle):
plain_name = f'{ClassName}.{MethodName}'
func = Gen._find_function(plain_name)
if func:
# 多继承 this 调整:继承方法定义在无 vtable 父类且字段区偏移 > 0 时,
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
self_arg = self._adjust_this_for_inherited_method(Gen, ObjVal, ClassName, method_anc)
VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}")
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}")
VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
@@ -2837,7 +2916,7 @@ class ExprCallHandle(BaseHandle):
MethodPtrI8 = Gen._load(MethodPtrAddr, name=f"vmethod_ptr_{MethodName}")
FuncPtrType = ir.PointerType(func.function_type)
MethodPtrTyped = Gen.builder.bitcast(MethodPtrI8, FuncPtrType, name=f"vmethod_typed_{MethodName}")
call_args = [ObjVal] + CallArgs
call_args = [self_arg] + CallArgs
self._fill_default_args(call_args, func, FullMethodName)
self._append_eh_msg_out_arg(call_args, func, Gen)
adjusted = Gen._adjust_args(call_args, func)
@@ -2845,6 +2924,8 @@ class ExprCallHandle(BaseHandle):
self._check_eh_return(result, FullMethodName, Gen, called_func=func)
return result
func = Gen._find_function(FullMethodName)
# 方法实际定义类(多继承 this 调整用,None=本类或未知)
method_anc: str | None = None
if not func:
func = Gen._find_function(f'{FullMethodName}__')
if not func and class_sha1:
@@ -2860,8 +2941,23 @@ class ExprCallHandle(BaseHandle):
if not func:
plain_name = f'{ClassName}.{MethodName}'
func = Gen._find_function(plain_name)
# 若 FullMethodName 只有 stub 声明(无函数体),也走 MRO 回退找定义类方法
if not func or len(list(func.blocks)) == 0:
# 多继承:沿 MRO 祖先链查找定义类方法(先声明父类优先),
# 继承方法用"定义类.方法"(如 B.get_b)直接调用,不再依赖子类包装器。
for anc in Gen._get_mro_chain(ClassName)[1:]:
anc_full = f'{anc}.{MethodName}'
func = Gen._find_function(anc_full)
if not func:
func = Gen._find_function(f'{anc_full}__')
if func:
method_anc = anc
break
if func:
call_args = [ObjVal] + CallArgs
# 多继承 this 调整:继承方法定义在无 vtable 父类且字段区偏移 > 0 时,
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
self_arg = self._adjust_this_for_inherited_method(Gen, ObjVal, ClassName, method_anc)
call_args = [self_arg] + CallArgs
self._fill_default_args(call_args, func, FullMethodName)
self._append_eh_msg_out_arg(call_args, func, Gen)
call_args = Gen._apply_auto_addr(FullMethodName, call_args)
+21 -1
View File
@@ -71,6 +71,17 @@ class ExprUtils:
FullMethodName: str = f'{ClassName}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{ClassName}.{op_name}__'
if not Gen._has_function(FullMethodName):
# 多继承:沿 MRO 祖先链查找 dunder 方法(先声明父类优先,与 TPV 一致)
for anc in Gen._get_mro_chain(ClassName)[1:]:
anc_method: str = f'{anc}.{op_name}'
if Gen._has_function(anc_method):
FullMethodName = anc_method
break
anc_method_ss = f'{anc}.{op_name}__'
if Gen._has_function(anc_method_ss):
FullMethodName = anc_method_ss
break
if not Gen._has_function(FullMethodName):
# 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且
# 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本
@@ -92,7 +103,16 @@ class ExprUtils:
FullMethodName = f'{SpecClass}.{op_name}__'
if Gen._has_function(FullMethodName):
func: Any = Gen._get_function(FullMethodName)
call_args: list[Any] = [obj_val]
# 多继承 this 调整:运算符重载方法定义在"无 vtable 父类"且字段区偏移 > 0 时,
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
method_anc: str | None = None
_fm_short: str = FullMethodName.split('.')[-1] if '.' in FullMethodName else FullMethodName
if '.' in FullMethodName:
_fm_cls: str = FullMethodName.split('.')[0]
if _fm_cls != ClassName:
method_anc = _fm_cls
_call_self: Any = self.Trans.ExprCallHandle._adjust_this_for_inherited_method(Gen, obj_val, ClassName, method_anc)
call_args: list[Any] = [_call_self]
if other_val is not None:
call_args.append(other_val)
if len(func.ftype.args) == len(call_args):
+32 -18
View File
@@ -1783,6 +1783,7 @@ class ImportHandle(BaseHandle):
# 修复:先尝试从已加载的父类获取真实字段名;若父类未加载,
# 则用 struct body 元素数推断继承字段数并补充占位条目 __inherited_N。
_ParentClass: str | None = None
_ParentClasses: list[str] = []
if Node.bases:
for _base in Node.bases:
_base_name: str | None = None
@@ -1833,18 +1834,27 @@ class ImportHandle(BaseHandle):
continue
if _base_name in ('CVTable', 'Object', 'NoVTable', 'CStruct', 'CUnion', 'CEnum', 'REnum', 'Exception', 'Enum'):
continue
# 多继承:收集所有真实父类(声明顺序),不再 break。
# 总是记录父类名,即使父类 class_members 未加载。
# _get_member_offset 会沿 class_parent 链回退查找继承字段。
_ParentClass = _base_name
if not hasattr(Gen, 'class_parent'):
Gen.class_parent = {}
Gen.class_parent[ClassName] = _ParentClass
break
_ParentClasses.append(_base_name)
if _ParentClass is None:
_ParentClass = _base_name
if not hasattr(Gen, 'class_parent'):
Gen.class_parent = {}
Gen.class_parent[ClassName] = _ParentClass
if _ParentClasses:
if not hasattr(Gen, 'class_parents'):
Gen.class_parents = {}
Gen.class_parents[ClassName] = _ParentClasses
# 治本修复:在继承展开前,尝试从 stub/.pyi 加载父类的 class_members。
# 确保子类 class_members 能正确展平父类真实字段名(而非 __inherited_N 占位符),
# 避免 struct body 从不完整 class_members 生成导致 GEP 越界。
# 同时处理父类 class_members 全为占位符的情况(清除后重新加载)。
if _ParentClass:
_any_parent_loaded: bool = False
for _ParentClass in _ParentClasses:
if not _ParentClass:
continue
_parent_members_check: list = Gen.class_members.get(_ParentClass, [])
_parent_all_placeholders: bool = bool(_parent_members_check) and all(
n.startswith('__inherited_') for n, _ in _parent_members_check
@@ -1869,18 +1879,22 @@ class ImportHandle(BaseHandle):
if not _parent_loaded and _old_parent_members:
# 加载失败,回滚到旧占位条目(有总比没有好)
Gen.class_members[_ParentClass] = _old_parent_members
if _ParentClass and _ParentClass in Gen.class_members:
_parent_members: list = list(Gen.class_members[_ParentClass])
_parent_defaults: dict = dict(Gen.class_member_defaults.get(_ParentClass, {}))
_existing_names: set = {m[0] for m in Gen.class_members[ClassName]}
_inherited: list[tuple] = []
for _pm_name, _pm_type in _parent_members:
if _pm_name not in _existing_names:
_inherited.append((_pm_name, _pm_type))
if _pm_name in _parent_defaults:
Gen.class_member_defaults[ClassName][_pm_name] = _parent_defaults[_pm_name]
Gen.class_members[ClassName] = _inherited + Gen.class_members[ClassName]
else:
if _ParentClass in Gen.class_members:
_parent_members: list = list(Gen.class_members[_ParentClass])
_parent_defaults: dict = dict(Gen.class_member_defaults.get(_ParentClass, {}))
_existing_names: set = {m[0] for m in Gen.class_members[ClassName]}
_inherited: list[tuple] = []
for _pm_name, _pm_type in _parent_members:
if _pm_name == '__vtable__':
continue
if _pm_name not in _existing_names:
_inherited.append((_pm_name, _pm_type))
if _pm_name in _parent_defaults:
Gen.class_member_defaults[ClassName][_pm_name] = _parent_defaults[_pm_name]
if _inherited:
Gen.class_members[ClassName] = _inherited + Gen.class_members[ClassName]
_any_parent_loaded = True
if not _any_parent_loaded and _ParentClasses:
# 父类未加载到 class_members(常见于泛型特化基类如 GSListNode[Value],
# 其特化不在 .pyi 中)。用 struct body 元素数推断继承字段数。
_st = Gen.structs.get(ClassName)
+4 -6
View File
@@ -20,14 +20,12 @@ class WithHandle(BaseHandle):
func = Gen._find_function(FullName) if hasattr(Gen, '_find_function') else Gen.functions.get(FullName)
if func:
return (ClassName, func)
# 沿继承链查找
p: str | None = Gen.class_parent.get(ClassName) if hasattr(Gen, 'class_parent') else None
while p:
parent_full: str = f'{p}.{MethodName}'
# 沿 MRO 继承链查找(多继承:先声明父类优先)
for anc in Gen._get_mro_chain(ClassName)[1:]:
parent_full: str = f'{anc}.{MethodName}'
parent_func = Gen._find_function(parent_full) if hasattr(Gen, '_find_function') else Gen.functions.get(parent_full)
if parent_func:
return (p, parent_func)
p = Gen.class_parent.get(p)
return (anc, parent_func)
return (None, None)
def _HandleWithLlvm(self, Node: ast.With) -> None:
+36
View File
@@ -95,6 +95,8 @@ class BaseGenMixin:
self.class_vtable: set[str] = set()
self._class_graph: dict[str, Any] = {}
self.class_parent: dict[str, str] = {}
# 多继承:父类名数组(声明顺序)。class_parent 兼容保留为第一个父类。
self.class_parents: dict[str, list[str]] = {}
# Store member annotations for deferred type resolution (cross-module class references)
self.class_member_annotations: dict[str, dict[str, Any]] = {}
self.loop_break_targets: list[ir.Block] = []
@@ -594,6 +596,40 @@ class BaseGenMixin:
def _has_function(self, name: str) -> bool:
return self._find_function(name) is not None
def _get_mro_chain(self, ClassName: str) -> list[str]:
"""MRO 线性化类名列表(深度优先 + 声明顺序 + 去重,含自身)。
顺序: 自身 → 父类1 及祖先 → 父类2 及祖先(先声明父类优先,菱形去重)。
与 TPV HandlesStruct.get_mro_chain 的语义一致。
"""
chain: list[str] = []
visited: set[str] = set()
stack: list[str] = [ClassName]
parents_map: dict[str, list[str]] = getattr(self, 'class_parents', {})
while stack:
cur: str = stack.pop()
if not cur or cur in visited:
continue
visited.add(cur)
chain.append(cur)
parents: list[str] = parents_map.get(cur, [])
# 父类逆序压栈,保证声明顺序弹出(先访问父类1 的整条链)
for p in reversed(parents):
if p and p not in visited:
stack.append(p)
return chain
def _get_parent_classes(self, ClassName: str) -> list[str]:
"""获取类的所有父类名(声明顺序),兼容旧 class_parent 单链。"""
parents_map: dict[str, list[str]] = getattr(self, 'class_parents', {})
parents: list[str] = parents_map.get(ClassName)
if parents:
return parents
p: str | None = self.class_parent.get(ClassName)
if p:
return [p]
return []
def _get_or_declare_function(self, mangled_name: str, func_type: ir.FunctionType) -> ir.Function:
# DDEBUG: 检测 mangled_name 含双点(不应到达这里)
if '..' in mangled_name:
+10 -7
View File
@@ -626,18 +626,21 @@ class StructGenMixin:
Vtable_entries: list[ir.Constant] = []
for MethodName in methods:
short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName
full_MethodName: str = f"{ClassName}.{short_name}"
# 多继承:vtable 槽直接用完整方法名(实际定义类.方法,如 B.get_b)
func: ir.Function | None = None
if full_MethodName in self.functions:
func = self.functions[full_MethodName]
if MethodName in self.functions:
func = self.functions[MethodName]
if func is None:
parent_cls: str | None = self.class_parent.get(ClassName)
while parent_cls:
parent_full: str = f"{parent_cls}.{short_name}"
full_MethodName: str = f"{ClassName}.{short_name}"
if full_MethodName in self.functions:
func = self.functions[full_MethodName]
if func is None:
# 沿 MRO 祖先链查找定义类(先声明父类优先)
for anc in self._get_mro_chain(ClassName)[1:]:
parent_full: str = f"{anc}.{short_name}"
if parent_full in self.functions:
func = self.functions[parent_full]
break
parent_cls = self.class_parent.get(parent_cls)
if func is None:
Vtable_entries.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
continue