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:
1 parent
fc93a28ec6
commit
87b9dec1ef
7 files changed
+344
-128
No files matched your search
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user