diff --git a/Test/MultiInheritTest/App/main.vp b/Test/MultiInheritTest/App/main.vp new file mode 100644 index 0000000..5abac69 --- /dev/null +++ b/Test/MultiInheritTest/App/main.vp @@ -0,0 +1,199 @@ +from stdint import * +import w32.win32console +import t, c +from t import CInt, CPtr, CChar, CInt32T, CFloat64T, CExport, State +import viperlib +import stdlib +import testcheck + + +# === 1. 多继承字段合并 === + +class A: + a: CInt + + def __init__(self, a: CInt): + self.a = a + + def get_a(self) -> CInt: + return self.a + + +class B: + b: CInt + + def __init__(self, b: CInt): + self.b = b + + def get_b(self) -> CInt: + return self.b + + +# 多继承:C(A, B),字段展平 a+b+c,布局 [a, b, c] +class C(A, B): + c: CInt + + def __init__(self, a: CInt, b: CInt, cc: CInt): + self.a = a + self.b = b + self.c = cc + + def get_c(self) -> CInt: + return self.c + + +# === 2. 菱形去重 + 最左优先 === + +class Base: + shared: CInt + + def who(self) -> CInt: + return 1 + + def base_method(self) -> CInt: + return 100 + + +class Left(Base): + def who(self) -> CInt: + return 2 + + +class Right(Base): + def who(self) -> CInt: + return 3 + + +# 菱形:Diamond(Left, Right),Left/Right 共享 Base, +# Base.shared 字段只展平一次,who() 用 Left(先声明优先) +class Diamond(Left, Right): + def __init__(self, s: CInt): + self.shared = s + + +# === 3. 虚方法多继承 vtable === + +@t.CVTable +class ShapeM: + def area(self) -> CFloat64T: + return 0.0 + + +@t.CVTable +class ColorM: + color: CInt + + def __init__(self, color: CInt): + self.color = color + + def color_code(self) -> CInt: + return self.color + + +@t.CVTable +class ColoredCircle(ShapeM, ColorM): + r: CFloat64T + + def __init__(self, r: CFloat64T, color: CInt): + self.color = color + self.r = r + + def area(self) -> CFloat64T: + return 3.14159265 * self.r * self.r + + +# === 4. 运算符重载 + 方法继承链(MRO) === + +class Vec2M: + x: CFloat64T + y: CFloat64T + + def __new__() -> 'Vec2M' | CPtr: + return t.CVoid(t.CUInt64T(stdlib.malloc(16)), CPtr) + + def __init__(self, x: CFloat64T, y: CFloat64T): + self.x = x + self.y = y + + def __add__(self, b: 'Vec2M' | CPtr) -> 'Vec2M' | CPtr: + return Vec2M(self.x + b.x, self.y + b.y) + + +class Vec2Extra: + # 注意:方法体字段访问基于"定义类字段"(TPV 模型), + # 不引用 Vec2M 的 x/y(跨父类字段引用是更深层语义,暂不验证)。 + def extra_val(self) -> CInt: + return 7 + + +# 多继承:__add__ 继承自 Vec2M(运算符重载 MRO 链), +# extra_val 继承自 Vec2Extra(方法查找 MRO 链) +class Vec2Both(Vec2M, Vec2Extra): + def __new__() -> 'Vec2Both' | CPtr: + return t.CVoid(t.CUInt64T(stdlib.malloc(16)), CPtr) + + def __init__(self, x: CFloat64T, y: CFloat64T): + self.x = x + self.y = y + + +def main() -> CInt | CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + testcheck.begin("MultiInheritTest: 多继承专项测试") + + buf: CChar | CPtr = CPtr(stdlib.malloc(256)) + + # === 1. 字段合并 + 属性访问 + 方法调用 === + testcheck.section("多继承字段合并") + obj_c = C(1, 2, 3) + viperlib.snprintf(buf, 256, "C: a=%d b=%d c=%d", obj_c.a, obj_c.b, obj_c.c) + print(buf) + testcheck.check(obj_c.a == 1, "C.a 合并 OK", "C.a 合并 FAILED") + testcheck.check(obj_c.b == 2, "C.b 合并 OK", "C.b 合并 FAILED") + testcheck.check(obj_c.c == 3, "C.c 自身 OK", "C.c 自身 FAILED") + testcheck.check(obj_c.get_a() == 1, "C.get_a 继承 OK", "C.get_a 继承 FAILED") + testcheck.check(obj_c.get_b() == 2, "C.get_b 继承 OK", "C.get_b 继承 FAILED") + testcheck.check(obj_c.get_c() == 3, "C.get_c 自身 OK", "C.get_c 自身 FAILED") + testcheck.ok("字段合并测试完成") + + # === 2. 菱形去重 + 最左优先 === + testcheck.section("菱形去重 + 最左优先") + dm = Diamond(5) + viperlib.snprintf(buf, 256, "Diamond: shared=%d who=%d base=%d", dm.shared, dm.who(), dm.base_method()) + print(buf) + testcheck.check(dm.shared == 5, "Diamond.shared 菱形去重 OK", "Diamond.shared 菱形去重 FAILED") + testcheck.check(dm.who() == 2, "who() 最左优先(Left) OK", "who() 最左优先 FAILED") + testcheck.check(dm.base_method() == 100, "Base 方法继承 OK", "Base 方法继承 FAILED") + testcheck.ok("菱形去重测试完成") + + # === 3. 虚方法多继承 vtable === + testcheck.section("虚方法多继承 vtable") + cc = ColoredCircle(3.0, 7) + area: CFloat64T = cc.area() + viperlib.snprintf(buf, 256, "ColoredCircle: r=%.1f color=%d area=%.2f code=%d", + cc.r, cc.color, area, cc.color_code()) + print(buf) + testcheck.check(cc.color == 7, "ColorM.color 字段 OK", "ColorM.color 字段 FAILED") + testcheck.check(cc.color_code() == 7, "color_code 虚方法分派 OK", "color_code 虚方法分派 FAILED") + testcheck.check(area > 28.0 and area < 28.5, "area 虚方法覆盖 OK", "area 虚方法覆盖 FAILED") + testcheck.ok("虚方法多继承测试完成") + + # === 4. 运算符重载 + 方法继承链 === + testcheck.section("运算符重载 + 方法继承链") + v1 = Vec2Both(3.0, 4.0) + v2 = Vec2Both(1.0, 2.0) + v3 = v1 + v2 + viperlib.snprintf(buf, 256, "Vec2Both add: (%.1f, %.1f)", v3.x, v3.y) + print(buf) + testcheck.check(v3.x == 4.0, "Vec2Both __add__ 继承 OK", "Vec2Both __add__ 继承 FAILED") + testcheck.check(v3.y == 6.0, "Vec2Both __add__ y OK", "Vec2Both __add__ y FAILED") + lsq: CInt = v1.extra_val() + viperlib.snprintf(buf, 256, "Vec2Both extra_val: %d", lsq) + print(buf) + testcheck.check(lsq == 7, "extra_val 继承(Vec2Extra) OK", "extra_val 继承(Vec2Extra) FAILED") + testcheck.ok("运算符重载继承链测试完成") + + stdlib.free(buf) + return testcheck.end() diff --git a/Test/MultiInheritTest/project.json b/Test/MultiInheritTest/project.json new file mode 100644 index 0000000..85272f5 --- /dev/null +++ b/Test/MultiInheritTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "MultiInheritTest", + "version": "1.0.0", + "source_dir": "./App", + "build_dir": "./.tpv_build", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "MultiInheritTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "sha1_slice_level": 1, + "target": "llvm", + "strict_mode": true + } +} diff --git a/wiki/15-multiple-inheritance.md b/wiki/15-multiple-inheritance.md new file mode 100644 index 0000000..dfb49f5 --- /dev/null +++ b/wiki/15-multiple-inheritance.md @@ -0,0 +1,134 @@ +# Viper 多继承支持方案 + +> 背景:Viper 语法层已支持 `class X(A, B)`(`ClassDef.bases` 是列表,parser 正常解析), +> 但语义层只实现单继承(`StructEntry.ParentName` 单值,字段展平/vtable/方法查找均单父)。 +> 目标:实现多继承(含字段合并、vtable 合并、方法查找、菱形去重),并同步 TPC 参考实现。 +> 状态:方案稿,未实施。 + +## 1. 现状(已实测定位) + +| 位置 | 现状 | 多继承缺口 | +|---|---|---| +| ast/stmts.vp:504 `ClassDef.bases` | 列表,parser 支持多 base | 无(语法已就绪) | +| HandlesClassDef.vp:2868 `entry.ParentName = parent_name` | 单值 | 需父类数组 | +| HandlesClassDef.vp:2618-2655 字段展平 | 只遍历单个 `parent_entry` | 需 MRO 多父合并 | +| HandlesClassDef.vp:3028+ `_collect_vtable_methods` | 单父 `parent_vt_count` | 需多父 vtable 合并 | +| HandlesStruct.vp:56 `ParentName` | 单 str 字段 | 需数组 + MRO 辅助 | +| HandlesExprCall.vp `try_operator_overload` / `_translate_method_call` | `get_parent_name` 单链 | 需多父链 | +| HandlesExpr.vp 属性访问回退链 | `get_parent_name` 单链 | 需多父链 | + +## 2. MRO 规则(分阶段) + +### Phase 1(本方案默认):深度优先 + 声明顺序 + 去重 +- 查找顺序:**当前类 → bases 声明顺序逐个递归** +- 同名冲突:**先声明者优先**(最左优先) +- 菱形(`D(A, B)`,A/B 均继承 C):**深度优先去重**(已访问集合),C 的字段/方法只合并一次 +- 理由:与 Python C3 相比实现简单,覆盖本仓库实际场景(Generator Mixin 链、无复杂菱形) + +### Phase 2(可选,后续):C3 线性化 +- 严格 C3 保证单调性,处理复杂菱形歧义 +- 仅在 Phase 1 遇到真实需求后实施 + +## 3. 数据结构改造(HandlesStruct.vp) + +```python +@t.NoVTable +class StructEntry: + # 现有字段不变 + ParentNames: list[str] | t.CPtr # 新增:父类名数组(声明顺序,跳过 marker) + ParentCount: t.CInt # 新增 + +# 辅助函数(新增) +def get_parent_count(entry) -> int +def get_parent_name_at(entry, i) -> str +def get_mro_chain(entry) -> list[str] # 深度优先去重线性化(含自身) +def get_mro_parent_entries(entry) -> 父类 StructEntry 数组 +``` + +- `ParentName` 保留(兼容现有调用,指向第一个父类),新代码优先用 `ParentNames` +- 迁移点:`get_parent_name()` 调用方逐步替换为 MRO 链遍历 + +## 4. 字段布局(HandlesClassDef.vp 字段展平 L2618-2655) + +改造前(单父): +``` +[parent_fields..., child_fields...] +``` +改造后(多父): +``` +[vtable?, parent1_fields..., parent2_fields..., child_fields...] +``` + +实现: +1. `parent_entries = get_mro_parent_entries(self_entry)`(深度优先去重) +2. 遍历每个父类字段:`__vtable__` 跳过;**字段名去重**(已存在跳过,先声明者优先) +3. 布局顺序 = MRO 父类顺序 → 子类自身字段 + +**影响面**:所有继承类的 `__sizeof__`/GEP 偏移变化 → 需全量回归 + +## 5. vtable 合并(HandlesClassDef.vp `_collect_vtable_methods` L3028+) + +改造前(单父):`parent_vt_count` 遍历,full_name 用实际定义类(find_func_global 探测,已支持多层单继承) + +改造后: +1. 遍历 **MRO 所有父类**的 `VTableMethods`(每个父类的 vtable 方法短名) +2. **方法短名去重**:先声明父类优先;子类覆盖优先(`child_overrides` 检查不变) +3. full_name 定位:沿用 `find_func_global("类名.方法")` 探测(多父链探测) +4. 槽位顺序:父类方法(MRO 序)→ 子类新增方法 + +## 6. 方法查找/运算符重载/属性访问(多父链替换单链) + +| 位置 | 单链现状 | 改法 | +|---|---|---| +| HandlesExprCall.vp `try_operator_overload` L123-135 | `while cur_parent is not None` | 改为 `get_mro_chain` 遍历 | +| HandlesExprCall.vp `try_unary_operator_overload` L211-221 | 同上 | 同上 | +| HandlesExprCall.vp `_translate_method_call` 继承方法查找 | `get_parent_name` 单链 | MRO 链 | +| HandlesExpr.vp 属性访问 lookup_field 回退 | 单链 | MRO 链 | +| HandlesClassDef.vp `_find_method_defining_class`(本轮已加) | `entry.ParentName` 单链 | MRO 链 | +| HandlesType.vp / 其他 `get_parent_name` 调用 | 单链 | 逐步替换 | + +## 7. 菱形继承处理 + +- **字段**:MRO 去重(已访问父类集合),C 字段只合并一次 +- **方法/vtable**:方法短名去重,C 的 vtable 槽合并一次 +- **歧义**:先声明优先;Phase 1 不报歧义错误(静默最左优先),Phase 2 C3 时再考虑警告 + +## 8. TPC 同步清单 + +TPC(Python,`lib/core/`)与 TPV 结构一致,按顺序同步: +1. `Handles/HandlesStruct.py`:StructEntry 父类数组 + MRO 辅助 +2. `Handles/HandlesClassDef.py`:字段展平多父、vtable 多父合并、parent 收集 +3. `Handles/HandlesExprCall.py`:方法查找/运算符重载多父链 +4. `Handles/HandlesExpr.py`(若 TPC 属性访问在 HandlesExprAttr.py):多父回退 + +**顺序**:先 TPV(活跃编译器)实现 + 验证,再 TPC 同步(保持一致,防分叉)。 + +## 9. 实施计划 + +| 阶段 | 内容 | 验证 | +|---|---|---| +| M1 | HandlesStruct:父类数组 + MRO 辅助(新增字段/函数,不改现有逻辑) | bootstrap | +| M2 | HandlesClassDef:parent 收集多 base + 字段展平多父 | bootstrap + 单继承回归 | +| M3 | HandlesClassDef:vtable 多父合并 | bootstrap + 多继承 vtable 用例 | +| M4 | HandlesExprCall/HandlesExpr:方法/运算符/属性多父链 | bootstrap + 全用例 | +| M5 | TPC 同步(4 文件) | TPC 自测 | +| M6 | 新增 Test/MultiInheritTest(字段/vtable/菱形去重/运算符重载) | 编译 + 运行 | + +## 10. 验证用例(Test/MultiInheritTest/App/main.vp) + +- 多父字段合并 + 属性访问(`d = D(); d.a + d.b`) +- 多父方法调用(非虚 + 虚 vtable 分派) +- 运算符重载继承链(父类 dunder) +- 菱形去重(`D(A, B)`,A/B ← C:C 字段/方法只出现一次) +- 同名冲突最左优先 +- Generator 多继承实例化(`class Generator(BaseGenMixin, TypeGenMixin, ...)`)——**本轮对象化 P2+ 的落地验证** + +## 11. 风险与对策 + +| 风险 | 对策 | +|---|---| +| 字段布局变化破坏现有继承类 | 全量回归(所有 Test 项目) | +| vtable 合并槽位错误 | 多继承 vtable 用例 + obj 反汇编核对 | +| Viper 方法符号不转发(P1 已踩坑) | 多继承下子类仍只调自己文件定义的方法;父类方法用字段/模块函数 | +| 菱形去重遗漏 | MRO 已访问集合严格实现 | +| TPC/TPV 分叉 | TPV 先验,TPC 紧跟同步 |