Files
TransPyC/wiki/15-multiple-inheritance.md
T
TermiNexus f6f8c4183c test: 新增 MultiInheritTest 多继承专项测试 + wiki 方案
4 组用例: 字段合并 C(A,B) / 菱形去重最左优先(Diamond) /
虚方法 vtable 多继承(ColoredCircle) / 运算符重载 MRO 链(Vec2Both)。
wiki/15-multiple-inheritance.md: Viper 多继承方案(M1-M6)设计文档。
2026-08-10 00:29:13 +08:00

135 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 紧跟同步 |