feat(handles): Viper 多继承支持 M1-M4 - 父类数组+MRO/字段展平/vtable合并/this调整

HandlesStruct: StructEntry 增加 ParentNames/ParentCount + get_mro_chain
(深度优先+声明顺序+去重, 含自身, mro[0]=自身)
HandlesClassDef: 多父字段展平去重 + vtable 合并(方法短名去重+探测实际定义类)
+ 继承链统一 vtable 判定 + 无字段类(接口/标记类)支持 + 空 struct 跳过 zeroinitializer
HandlesExprCall: 方法调用沿 MRO 回退 + 继承方法 this 调整(GEP 定位+bitcast 成父类指针)
HandlesExprOps: 运算符重载 MRO 链查找
This commit is contained in:
TermiNexus committed 2026-08-10 00:28:58 +08:00
1 parent 37626bca63
commit b3170ba823
4 files changed
+467 -164

No files matched your search

+221 -105
View File
@@ -506,6 +506,73 @@ def _get_parent_class(cd: ast.ClassDef | t.CPtr,
return None
# ============================================================
# _collect_parents — 收集 ClassDef 的所有真实父类名(多继承)
#
# 遍历 cd.bases,跳过 marker base(Object/CVTable/NoVTable 等),
# 收集全部真实父类名到 parents_buf(t.CSizeT 数组,每元素 str 指针)。
# 返回收集数量。
# ============================================================
def _collect_parents(pool: memhub.MemBuddy | t.CPtr,
cd: ast.ClassDef | t.CPtr,
parents_buf: t.CSizeT | t.CPtr,
max_parents: int) -> int:
"""收集所有非 marker 父类名到 parents_buf,返回数量"""
if pool is None or cd is None or cd.bases is None or parents_buf is None:
return 0
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = bases.__len__()
count: int = 0
for bi in range(bn):
if count >= max_parents:
break
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
bname: str = _get_base_name(base_node, pool)
if bname is not None and _is_marker_base(bname) == 0:
parents_buf[count] = t.CSizeT(bname)
count += 1
return count
# ============================================================
# _field_name_exists — 检查字段名是否已存在于收集数组(去重)
# ============================================================
def _field_name_exists(names_buf: t.CSizeT | t.CPtr,
count: int, name: str) -> int:
"""检查字段名是否已在 names_buf 中(先声明父类优先,重复跳过)"""
if names_buf is None or name is None:
return 0
for fi in range(count):
addr: t.CSizeT = names_buf[fi]
if addr != 0:
existing: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr))
if existing is not None and string.strcmp(existing, name) == 0:
return 1
return 0
# ============================================================
# _class_body_has_field — 检查类体是否声明了字段(AnnAssign)
#
# 用于区分"无字段类"(接口/标记类,合法)与"注册不完整"
# (类体有字段但 FieldCount==0,漏注册报错)。
# ============================================================
def _class_body_has_field(cd: ast.ClassDef | t.CPtr) -> int:
"""检查类体是否声明了字段(AnnAssign),0=纯方法/无字段类"""
if cd is None or cd.children is None:
return 0
cn: t.CSizeT = cd.children.__len__()
for ci in range(cn):
stmt: ast.AST | t.CPtr = cd.children.get(ci)
if stmt is None:
continue
if stmt.kind() == ast.ASTKind.AnnAssign:
return 1
return 0
# ============================================================
# _trigger_base_specialization — 触发 base 中 Subscript 的泛型特化
#
@@ -641,7 +708,13 @@ def _should_method_be_virtual(cd: ast.ClassDef | t.CPtr,
else:
is_nvt = HandlesStruct.is_novtable_by_name(parent_name)
if is_nvt != 1:
return 1 # 有继承且父类非 NoVTable
# 继承链统一虚表:父类有虚表 → 方法进虚表;父类无虚表 → 静态方法。
# 与 _detect_vtable_status 规则一致,避免父类无 vptr 布局/子类有 vptr 的错位。
if p_entry is None:
return 1 # 父类信息未知,保守进虚表
if p_entry.HasVTable == 1:
return 1
return 0
# 5. 默认排除
return 0
@@ -691,7 +764,14 @@ def _detect_vtable_status(cd: ast.ClassDef | t.CPtr,
if is_nvt == 1:
# 父类是 NoVTable,检查函数级 @t.CVTable
return _has_any_func_cvtable(cd)
return 1 # 有父类且非 NoVTable,自动启用虚表
# 继承链统一虚表:父类有虚表 → 子类启用;父类无虚表 → 子类静态。
# 若父类无 vtable 而子类有,父类方法按无 vptr 布局(self.field@0)操作
# 子类实例(有 vptr@0)会字段错位 → 运行时错误(父类方法读 vptr 当字段)。
if p_entry is None:
return 1 # 父类信息未知(跨模块/未注册),保守启用虚表
if p_entry.HasVTable == 1:
return 1
return 0
# 默认(无装饰器无继承),检查函数级 @t.CVTable
return _has_any_func_cvtable(cd)
@@ -2516,12 +2596,15 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
if existing is not None:
# BUG 5 方案1修改点2:existing 时字段完整性检查
# 结构体已注册,但需验证字段信息是否完整(防止 i32 回退残留或注册不完整)
# 注意:无字段类(接口/标记类,类体无 AnnAssign)合法(空 struct + 方法),
# 仅当"类体声明了字段但 FieldCount==0"才算注册不完整(Phase A-pre 漏注册)。
if existing.FieldCount == 0 and trans._declare_only == 0:
# Phase B 时字段数为 0 说明注册不完整(Phase A-pre 可能漏注册)
HandlesType.fatal_error(
node,
f"结构体已注册但字段数为0,类: {class_name},可能注册不完整",
"InternalCompilerError")
if _class_body_has_field(cd) != 0:
# Phase B 时字段数为 0 说明注册不完整(Phase A-pre 可能漏注册)
HandlesType.fatal_error(
node,
f"结构体已注册但字段数为0,类: {class_name},可能注册不完整",
"InternalCompilerError")
# 结构体已注册(Phase A-pre 多遍扫描或 Phase B 重新翻译),但仍需在当前模块中翻译方法
if existing.Ty is not None:
# Phase 1b(declare_only=0):existing.Ty 是 Phase 1a 注册的 struct_ty,
@@ -2563,6 +2646,11 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
# ============================================================
has_vtable: int = _detect_vtable_status(cd, trans)
parent_name: str = _get_parent_class(cd, trans)
# 多继承:收集所有真实父类名(跳过 marker base),供字段展平/vtable/MRO 使用
parents_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.PARENT_MAX)
parents_count: int = 0
if parents_buf is not None:
parents_count = _collect_parents(pool, cd, parents_buf, HandlesStruct.PARENT_MAX)
is_novtable_deco: int = 0
if cd.decorator_list is not None:
if _has_decorator(cd.decorator_list, "NoVTable") == 1:
@@ -2616,16 +2704,25 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
# [vtable_ptr?, parent_field1, ..., child_field1, ...]
# 跳过父类的 __vtable__ 字段(子类会有自己的 vtable 指针)
# ============================================================
if parent_name is not None:
# 用 SHA1 感知查找父类,规避跨模块同名找错
parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
parent_name, trans.ModuleSha1)
if parent_entry is None:
# 父类可能定义在另一个模块(不同 SHA1,如 HandlesBase.Mixin),
# find_struct_by_module 不回退全局查找,此处手动回退到 find_struct,
# 否则子类无法继承父类字段 → field_count==0 → __sizeof__ 失败
parent_entry = HandlesStruct.find_struct(parent_name)
if parent_entry is not None:
# 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明优先)
if parents_count > 0 and parents_buf is not None:
for pi in range(parents_count):
pname_addr: t.CSizeT = parents_buf[pi]
if pname_addr == 0:
continue
pname: str = (str | t.CPtr)(t.CVoid(pname_addr, t.CPtr))
if pname is None:
continue
# 用 SHA1 感知查找父类,规避跨模块同名找错
parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
pname, trans.ModuleSha1)
if parent_entry is None:
# 父类可能定义在另一个模块(不同 SHA1,如 HandlesBase.Mixin),
# find_struct_by_module 不回退全局查找,此处手动回退到 find_struct,
# 否则子类无法继承父类字段 → field_count==0 → __sizeof__ 失败
parent_entry = HandlesStruct.find_struct(pname)
if parent_entry is None:
continue
pfc: int = parent_entry.FieldCount
for pfi in range(pfc):
pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
@@ -2638,6 +2735,9 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
# 跳过父类的 vtable 指针字段
if string.strcmp(pfn, "__vtable__") == 0:
continue
# 多继承去重:字段名已存在跳过(先声明父类优先)
if _field_name_exists(field_names_buf, field_count, pfn) != 0:
continue
if field_count < 48:
pft: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_field_type_ptr(pfe)
pfd: ast.AST | t.CPtr = HandlesStruct.get_field_default_ptr(pfe)
@@ -2750,11 +2850,13 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
# 静默返回,Phase2.py 的多遍 PhaseA-pre 会在后续遍中重试。
if trans._declare_only == 1 and parent_name is not None:
return 0
# 无字段类(接口/标记类):不能整体跳过——类可能只有方法
# (如多继承中的 ShapeM/Vec2Extra),需注册类并翻译方法。
# 空 struct 在 LLVM 中合法({});@t.CVTable 类由下方补 vtable 指针字段。
fb_cf: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cf is not None:
viperlib.snprintf(fb_cf, 1024, "%s has no fields", class_name)
VLogger.info(fb_cf, "CLASS")
return 0
# ============================================================
# 2. 创建 LLVM StructType
@@ -2867,6 +2969,9 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
entry.IsNoVTable = 1
if parent_name is not None:
entry.ParentName = parent_name
# 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活)
if parents_count > 0 and parents_buf is not None:
HandlesStruct.set_parent_names(class_name, parents_buf, parents_count)
# 添加字段信息
# 如果有虚表,先添加 __vtable__ 字段占位(索引 0),用户字段从索引 1 开始
@@ -3067,95 +3172,101 @@ def _collect_vtable_methods(trans: HT.Translator | t.CPtr,
# ============================================================
vt_self_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
class_name, trans.ModuleSha1)
parent_name: str = None
if vt_self_entry is not None:
parent_name = vt_self_entry.ParentName
if parent_name is not None:
# 查找父类 entry(优先同模块 SHA1 匹配)
vt_parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
parent_name, trans.ModuleSha1)
if vt_parent_entry is None:
# 跨模块继承: 父类在不同模块定义(SHA1 不同),回退到按类名查找
vt_parent_entry = HandlesStruct.find_struct(parent_name)
parent_vt_count: int = 0
if vt_parent_entry is not None:
parent_vt_count = vt_parent_entry.VTableMethodCount
if parent_vt_count > 0:
for pvi in range(parent_vt_count):
if method_count >= VTBL_METHOD_MAX:
break
pmethod_name: str = None
if vt_parent_entry is not None:
pmethod_name = HandlesStruct.get_vtable_method_name(parent_name, pvi)
if pmethod_name is None:
continue
# 检查子类是否覆盖了该方法,以及是否标记 @t.NoVTable
child_overrides: int = 0
child_nvt: int = 0
for ci2 in range(cn):
stmt2: ast.AST | t.CPtr = children.get(ci2)
if stmt2 is None:
# 多继承:遍历所有父类(声明顺序),vtable 方法合并(短名去重,先声明父类优先)
parent_count: int = HandlesStruct.get_parent_count(class_name)
if parent_count > 0:
for pi in range(parent_count):
pname: str = HandlesStruct.get_parent_name_at(class_name, pi)
if pname is None:
continue
# 查找父类 entry(优先同模块 SHA1 匹配)
vt_parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
pname, trans.ModuleSha1)
if vt_parent_entry is None:
# 跨模块继承: 父类在不同模块定义(SHA1 不同),回退到按类名查找
vt_parent_entry = HandlesStruct.find_struct(pname)
parent_vt_count: int = 0
if vt_parent_entry is not None:
parent_vt_count = vt_parent_entry.VTableMethodCount
if parent_vt_count > 0:
for pvi in range(parent_vt_count):
if method_count >= VTBL_METHOD_MAX:
break
pmethod_name: str = None
if vt_parent_entry is not None:
pmethod_name = HandlesStruct.get_vtable_method_name(pname, pvi)
if pmethod_name is None:
continue
if stmt2.kind() != ast.ASTKind.FunctionDef:
# 多继承 vtable 去重:方法短名已存在跳过(先声明父类优先)
if _field_name_exists(method_names_buf, method_count, pmethod_name) != 0:
continue
fd2: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt2)
if fd2 is not None and fd2.name is not None:
if string.strcmp(fd2.name, pmethod_name) == 0:
child_overrides = 1
# 检查子类覆盖方法是否标记 @t.NoVTable
if fd2.decorator_list is not None:
if _has_decorator(fd2.decorator_list, "NoVTable") == 1:
child_nvt = 1
break
# 构造 full_name
# 子类覆盖且未标记 NoVTable → 用子类实现
# 子类未覆盖 或 子类覆盖但标记 NoVTable → 用实际定义类实现(保持 vtable 槽位)
#
# 多层继承修复: 直接父类可能只是继承而非定义该方法
# (如 ElectricCar 继承 Car 的 is_running 实际定义在 Vehicle),
# 沿父类链向上用 find_func_global("类名.方法名") 探测实际定义类,
# 避免生成 "Car.is_running" 这类找不到函数的 full_name → vtable 槽变 null。
def_class: str = class_name
if child_overrides == 1 and child_nvt == 0:
def_class = class_name
else:
def_class = parent_name
probe_class: str = parent_name
while probe_class is not None:
probe_buf: t.CChar | t.CPtr = pool.alloc(128)
if probe_buf is not None:
viperlib.snprintf(probe_buf, 128, "%s.%s", probe_class, pmethod_name)
if HandlesExprCall.find_func_global(probe_buf) is not None:
def_class = probe_class
# 检查子类是否覆盖了该方法,以及是否标记 @t.NoVTable
child_overrides: int = 0
child_nvt: int = 0
for ci2 in range(cn):
stmt2: ast.AST | t.CPtr = children.get(ci2)
if stmt2 is None:
continue
if stmt2.kind() != ast.ASTKind.FunctionDef:
continue
fd2: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt2)
if fd2 is not None and fd2.name is not None:
if string.strcmp(fd2.name, pmethod_name) == 0:
child_overrides = 1
# 检查子类覆盖方法是否标记 @t.NoVTable
if fd2.decorator_list is not None:
if _has_decorator(fd2.decorator_list, "NoVTable") == 1:
child_nvt = 1
break
probe_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
probe_class)
if probe_entry is None or probe_entry.ParentName is None:
break
probe_class = probe_entry.ParentName
pfname_buf: t.CChar | t.CPtr = pool.alloc(128)
if pfname_buf is not None:
viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name)
full_names_buf[method_count] = t.CSizeT(pfname_buf)
# 复制方法名(短名)
pmname_len: t.CSizeT = string.strlen(pmethod_name)
pmname_buf: t.CChar | t.CPtr = stdlib.malloc(pmname_len + 1)
if pmname_buf is not None:
string.strcpy(pmname_buf, pmethod_name)
method_names_buf[method_count] = t.CSizeT(pmname_buf)
# 记录 mangling 用的 SHA1(继承未覆盖的方法用实际定义类的模块 SHA1)
if child_overrides == 1 and child_nvt == 0:
# 子类覆盖: 用当前模块 SHA1(保持 0)
method_parent_sha1s[method_count] = 0
else:
# 继承未覆盖: 用实际定义类的模块 SHA1(跨模块继承时 mangling 正确)
def_entry2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
def_class)
if def_entry2 is not None and def_entry2.ModuleSha1 is not None:
method_parent_sha1s[method_count] = t.CSizeT(def_entry2.ModuleSha1)
# 构造 full_name
# 子类覆盖且未标记 NoVTable → 用子类实现
# 子类未覆盖 或 子类覆盖但标记 NoVTable → 用实际定义类实现(保持 vtable 槽位)
#
# 多层继承修复: 直接父类可能只是继承而非定义该方法
# (如 ElectricCar 继承 Car 的 is_running 实际定义在 Vehicle),
# 沿父类链向上用 find_func_global("类名.方法名") 探测实际定义类,
# 避免生成 "Car.is_running" 这类找不到函数的 full_name → vtable 槽变 null。
def_class: str = class_name
if child_overrides == 1 and child_nvt == 0:
def_class = class_name
else:
def_class = pname
# 多继承:沿 pname 的 MRO 祖先链探测实际定义类(跳过自身,先声明父类优先)
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, pname)
mro_i: int = 1
while mro_ptr is not None and mro_ptr[mro_i] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mro_i], t.CPtr))
if anc is not None:
probe_buf: t.CChar | t.CPtr = pool.alloc(128)
if probe_buf is not None:
viperlib.snprintf(probe_buf, 128, "%s.%s", anc, pmethod_name)
if HandlesExprCall.find_func_global(probe_buf) is not None:
def_class = anc
break
mro_i += 1
pfname_buf: t.CChar | t.CPtr = pool.alloc(128)
if pfname_buf is not None:
viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name)
full_names_buf[method_count] = t.CSizeT(pfname_buf)
# 复制方法名(短名)
pmname_len: t.CSizeT = string.strlen(pmethod_name)
pmname_buf: t.CChar | t.CPtr = stdlib.malloc(pmname_len + 1)
if pmname_buf is not None:
string.strcpy(pmname_buf, pmethod_name)
method_names_buf[method_count] = t.CSizeT(pmname_buf)
# 记录 mangling 用的 SHA1(继承未覆盖的方法用实际定义类的模块 SHA1)
if child_overrides == 1 and child_nvt == 0:
# 子类覆盖: 用当前模块 SHA1(保持 0)
method_parent_sha1s[method_count] = 0
method_count += 1
else:
# 继承未覆盖: 用实际定义类的模块 SHA1(跨模块继承时 mangling 正确)
def_entry2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
def_class)
if def_entry2 is not None and def_entry2.ModuleSha1 is not None:
method_parent_sha1s[method_count] = t.CSizeT(def_entry2.ModuleSha1)
else:
method_parent_sha1s[method_count] = 0
method_count += 1
# 2. 收集当前类的虚方法(跳过已从父类继承的)
for ci in range(cn):
@@ -3917,9 +4028,14 @@ def _generate_before_init(trans: HT.Translator | t.CPtr,
self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self")
# 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
if zero is not None:
llvmlite.build_store(func_builder, zero, self_val)
# 空 struct({})在 LLVM 中不允许 zeroinitializer(invalid type for null constant),
# 无字段类(接口/标记类,如多继承的 Vec2Extra)跳过零值填充;
# @t.CVTable 类必有 vtable 指针字段(非空),不受影响。
struct_fcount_zi: int = llvmlite.get_struct_fcount(struct_ty)
if struct_fcount_zi > 0:
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
if zero is not None:
llvmlite.build_store(func_builder, zero, self_val)
# 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0)
# 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错
+58 -28
View File
@@ -3504,23 +3504,23 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
viperlib.snprintf(spec_lookup, 160, "%s.%s", mc_entry.Name, method_name)
found_func = find_func_in_module(mod, spec_lookup)
# 沿继承链查找父类方法(子类未覆盖时回退到父类)
# 沿 MRO 祖先链查找父类方法(子类未覆盖时回退到父类,先声明父类优先)
mc_anc: str = None # 方法实际定义类(多继承 this 调整用)
if found_func is None:
cur_parent: str = None
if mc_entry is not None:
cur_parent = mc_entry.ParentName
else:
cur_parent = HandlesStruct.get_parent_name(class_name)
while cur_parent is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, method_name)
parent_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, parent_lookup)
if parent_func is not None:
found_func = parent_func
break
# 后续父类按名查找(无 ParentSha1,只能按名回退)
cur_parent = HandlesStruct.get_parent_name(cur_parent)
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
mi: int = 1
while mro_ptr is not None and mro_ptr[mi] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
if anc is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, method_name)
parent_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, parent_lookup)
if parent_func is not None:
found_func = parent_func
mc_anc = anc
break
mi += 1
# 确定调用名
call_name: str = lookup_name
@@ -3537,14 +3537,13 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
else:
cls_sha1_mc = HandlesStruct.get_struct_sha1(class_name)
if cls_sha1_mc is None:
cur_p: str = None
if mc_entry is not None:
cur_p = mc_entry.ParentName
else:
cur_p = HandlesStruct.get_parent_name(class_name)
while cur_p is not None and cls_sha1_mc is None:
cls_sha1_mc = HandlesStruct.get_struct_sha1(cur_p)
cur_p = HandlesStruct.get_parent_name(cur_p)
mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
mj: int = 1
while mro_p is not None and mro_p[mj] != 0 and cls_sha1_mc is None:
anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr))
if anc_p is not None:
cls_sha1_mc = HandlesStruct.get_struct_sha1(anc_p)
mj += 1
if cls_sha1_mc is not None:
mangled_len_mc: t.CSizeT = string.strlen(cls_sha1_mc) + string.strlen(lookup_name) + 2
mangled_mc: str = pool.alloc(mangled_len_mc)
@@ -3643,10 +3642,41 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
if kw_calls is not None:
kwc = kw_calls.__len__()
# 构建参数链表: obj_ptr → arg1 → arg2 → ...
llvmlite.value_set_next(obj_ptr, None)
head: llvmlite.Value | t.CPtr = obj_ptr
tail: llvmlite.Value | t.CPtr = obj_ptr
# 多继承 this 调整:继承方法定义在"无 vtable 的父类"且该父类字段区在子类中
# 偏移 > 0 时(如 C(A,B).get_b,B 的字段区在 C 中从 b 开始),父类方法按自身
# 布局读 self.field@0 会读到前面父类的字段。调整:GEP 到父类第一个用户字段
# 在子类中的位置,bitcast 成父类指针作为 self。
# 有 vtable 的父类布局是子类布局前缀(vptr 共享),self 无需调整。
self_arg: llvmlite.Value | t.CPtr = obj_ptr
if mc_anc is not None and string.strcmp(mc_anc, class_name) != 0:
anc_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(mc_anc)
if anc_entry_th is not None and anc_entry_th.HasVTable == 0 and anc_entry_th.FieldCount > 0:
anc_first_name_th: str = None
afi_th: int = 0
while afi_th < anc_entry_th.FieldCount:
afe_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
anc_entry_th, afi_th)
if afe_th is not None:
afn_th: str = HandlesStruct.get_field_name_ptr(afe_th)
if afn_th is not None and string.strcmp(afn_th, "__vtable__") != 0:
anc_first_name_th = afn_th
break
afi_th += 1
if anc_first_name_th is not None:
sub_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
class_name)
if sub_entry_th is not None:
sub_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
sub_entry_th.Ty, anc_first_name_th)
if sub_field_th is not None and sub_field_th.Index > 0:
anc_ptr_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_th.Ty)
adj_th: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, sub_entry_th.Ty, sub_field_th.Ty, obj_ptr, sub_field_th.Index)
self_arg = llvmlite.build_bitcast(builder, adj_th, anc_ptr_ty_th)
# 构建参数链表: self → arg1 → arg2 → ...
llvmlite.value_set_next(self_arg, None)
head: llvmlite.Value | t.CPtr = self_arg
tail: llvmlite.Value | t.CPtr = self_arg
arg_count_eff: int = 0
if kwc > 0 and found_func is not None:
+44 -30
View File
@@ -122,17 +122,21 @@ def try_operator_overload(pool: memhub.MemBuddy | t.CPtr,
search_class: str = class_name
if found_func is None:
cur_parent: str = HandlesStruct.get_parent_name(class_name)
while cur_parent is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, dunder)
parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup)
if parent_func is not None:
found_func = parent_func
search_class = cur_parent
break
cur_parent = HandlesStruct.get_parent_name(cur_parent)
# 多继承:沿 MRO 祖先链查找(先声明父类优先)
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
mi: int = 1
while mro_ptr is not None and mro_ptr[mi] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
if anc is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder)
parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup)
if parent_func is not None:
found_func = parent_func
search_class = anc
break
mi += 1
# 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入)
# 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错)
@@ -143,10 +147,13 @@ def try_operator_overload(pool: memhub.MemBuddy | t.CPtr,
if cls_sha1 is None:
cls_sha1 = HandlesStruct.get_struct_sha1(search_class)
if cls_sha1 is None:
cur_p: str = HandlesStruct.get_parent_name(search_class)
while cur_p is not None and cls_sha1 is None:
cls_sha1 = HandlesStruct.get_struct_sha1(cur_p)
cur_p = HandlesStruct.get_parent_name(cur_p)
mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class)
mj: int = 1
while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None:
anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr))
if anc_p is not None:
cls_sha1 = HandlesStruct.get_struct_sha1(anc_p)
mj += 1
# 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算
if found_func is None and cls_sha1 is None:
@@ -208,17 +215,21 @@ def try_unary_operator_overload(pool: memhub.MemBuddy | t.CPtr,
search_class: str = class_name
if found_func is None:
cur_parent: str = HandlesStruct.get_parent_name(class_name)
while cur_parent is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, dunder)
parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup)
if parent_func is not None:
found_func = parent_func
search_class = cur_parent
break
cur_parent = HandlesStruct.get_parent_name(cur_parent)
# 多继承:沿 MRO 祖先链查找(先声明父类优先)
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
mi: int = 1
while mro_ptr is not None and mro_ptr[mi] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
if anc is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder)
parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup)
if parent_func is not None:
found_func = parent_func
search_class = anc
break
mi += 1
# 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入)
cls_sha1: str = None
@@ -228,10 +239,13 @@ def try_unary_operator_overload(pool: memhub.MemBuddy | t.CPtr,
if cls_sha1 is None:
cls_sha1 = HandlesStruct.get_struct_sha1(search_class)
if cls_sha1 is None:
cur_p: str = HandlesStruct.get_parent_name(search_class)
while cur_p is not None and cls_sha1 is None:
cls_sha1 = HandlesStruct.get_struct_sha1(cur_p)
cur_p = HandlesStruct.get_parent_name(cur_p)
mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class)
mj: int = 1
while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None:
anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr))
if anc_p is not None:
cls_sha1 = HandlesStruct.get_struct_sha1(anc_p)
mj += 1
# 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算
if found_func is None and cls_sha1 is None:
+144 -1
View File
@@ -24,6 +24,9 @@ import lib.core.VLogger as VLogger
STRUCT_MAX: t.CDefine = 512
FIELD_MAX: t.CDefine = 48
FIELD_NAME_MAX: t.CDefine = 64
# 多继承(MRO)支持:单类最大父类数 / MRO 链最大长度
PARENT_MAX: t.CDefine = 8
MRO_MAX: t.CDefine = 16
# ============================================================
@@ -53,7 +56,9 @@ class StructEntry:
HasNew: int # 1=有__new__方法 / 0=无
HasVTable: int # 1=有虚表 / 0=无虚表
IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记
ParentName: t.CChar | t.CPtr # 父类名(None=无父类)
ParentName: t.CChar | t.CPtr # 父类名(None=无父类,多继承时为第一个父类,兼容旧调用)
ParentNames: t.CSizeT | t.CPtr # 多继承父类名数组(每元素 str 指针,ParentCount 个;stdlib 深拷贝)
ParentCount: t.CInt # 父类数量(0=无父类,1=单继承,>1=多继承)
VTableMethodCount: int # 虚表中的方法数量
VTableMethods: t.CChar | t.CPtr # 虚表方法名数组(每个方法名 str,VTableMethodCount 个)
ModuleSha1: t.CChar | t.CPtr # 定义该类的模块 SHA1(None=无 SHA1)
@@ -928,6 +933,144 @@ def set_parent_name(name: str, parent_name: str) -> int:
return 1
# ============================================================
# set_parent_names — 设置多继承父类名数组
#
# names_ptr: t.CSizeT 数组(每元素类名 str 指针),count 个。
# 传 None/0 清除父类数组。ParentName(第一个父类)由调用方
# 另行通过 set_parent_name 维护(兼容现有单继承调用方)。
# ============================================================
def set_parent_names(name: str, names_ptr: t.CSizeT | t.CPtr,
count: int) -> int:
"""设置结构体的父类名数组(stdlib 深拷贝,跨文件永久存活)"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
if names_ptr is None or count <= 0:
entry.ParentNames = None
entry.ParentCount = 0
return 1
if count > PARENT_MAX:
count = PARENT_MAX
arr: t.CSizeT | t.CPtr = stdlib.malloc(8 * count)
if arr is None:
return 0
for i in range(count):
addr: t.CSizeT = names_ptr[i]
arr[i] = 0
if addr != 0:
src: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr))
if src is not None:
slen: t.CSizeT = string.strlen(src)
dup: t.CChar | t.CPtr = stdlib.malloc(slen + 1)
if dup is not None:
string.strcpy(dup, src)
arr[i] = t.CSizeT(dup)
entry.ParentNames = t.CSizeT(arr)
entry.ParentCount = count
return 1
# ============================================================
# get_parent_count — 获取父类数量
# ============================================================
def get_parent_count(name: str) -> int:
"""获取父类数量(0=无父类,1=单继承,>1=多继承)"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.ParentCount
# ============================================================
# get_parent_name_at — 获取第 idx 个父类名(声明顺序)
# ============================================================
def get_parent_name_at(name: str, idx: int) -> str:
"""获取第 idx 个父类名,越界返回 None"""
if name is None or idx < 0:
return None
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None or entry.ParentNames is None:
return None
if idx >= entry.ParentCount:
return None
parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr))
addr: t.CSizeT = parr[idx]
if addr == 0:
return None
return (str | t.CPtr)(t.CVoid(addr, t.CPtr))
# ============================================================
# get_mro_chain — MRO 线性化类名数组(深度优先 + 声明顺序 + 去重,含自身)
#
# 返回: pool 分配的 t.CSizeT 数组(每元素类名 str 指针),末尾 0 结束。
# 顺序: 自身 → 父类1 及祖先 → 父类2 及祖先(先声明优先,菱形去重)。
# 失败返回 None。
# ============================================================
def get_mro_chain(pool: memhub.MemBuddy | t.CPtr,
name: str) -> t.CSizeT | t.CPtr:
"""MRO 线性化类名数组(深度优先 + 声明顺序 + 去重,含自身)"""
if pool is None or name is None:
return None
arr: t.CSizeT | t.CPtr = pool.alloc(8 * (MRO_MAX + 1))
if arr is None:
return None
stack: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX)
if stack is None:
return None
visited: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX)
if visited is None:
return None
stack_count: int = 0
out_count: int = 0
visit_count: int = 0
# 初始压入自身
stack[0] = t.CSizeT(name)
stack_count = 1
while stack_count > 0:
stack_count -= 1
cur_addr: t.CSizeT = stack[stack_count]
cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr))
if cur is None:
continue
# 已访问检查(线性搜索)
dup: int = 0
for vi in range(visit_count):
va: t.CSizeT = visited[vi]
if va != 0:
vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr))
if vn is not None and string.strcmp(vn, cur) == 0:
dup = 1
break
if dup != 0:
continue
# 加入结果与已访问集合
if out_count < MRO_MAX:
arr[out_count] = t.CSizeT(cur)
out_count += 1
if visit_count < MRO_MAX:
visited[visit_count] = t.CSizeT(cur)
visit_count += 1
# 父类逆序压栈(正向 range 计算逆序索引,保证声明顺序弹出)
entry: StructEntry | t.CPtr = find_struct(cur)
if entry is not None and entry.ParentCount > 0 and entry.ParentNames is not None:
pc: int = entry.ParentCount
parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr))
for pi2 in range(pc):
pi: int = pc - 1 - pi2
if stack_count < MRO_MAX:
stack[stack_count] = parr[pi]
stack_count += 1
# 末尾 0 结束
arr[out_count] = 0
return arr
# ============================================================
# get_parent_name — 获取父类名
# ============================================================