TermiNexus
|
78d3941f7d
|
refactor(call): 跨模块返回类型解析改以 .vpi 为权威,text.ll 降为回退
将 8 处跨模块方法/函数返回类型解析的 text.ll → vpi 顺序对调为 vpi → text.ll:
- CallGenProp:属性方法调用
- CallGenMixin:跨模块裸名 CExport、from-import 函数
- CallGenCall:跨模块方法、类方法调用、self 方法调用(含 MRO 祖先链重试段整体搬移)
- CallGenDispatch:__len__ 跨模块、泛型 Mixin 方法
本模块 found_func / local_fn 取当前 IR 声明类型的路径保持不变。
去 IR 化步骤②;未编译验证。
|
2026-10-03 08:10:34 +08:00 |
|
TermiNexus
|
94d2bf5047
|
feat(sidecar): 落盘 {sha1}.meta 函数定义清单,声明文件判定改读结构化 sidecar
- 新增 WriteModuleFuncMeta:翻译期从 Module.FuncHead + Function.IsDeclared 产出 FUNC <mangled> DEF|DECL(与 dump_ir 的 stub/text 判据同源)
- 新增 _MetaHasDef / 重写 IsDeclOnlyModule:不再扫 text.ll 的 define 行,改读 meta
- Phase1/Phase2 落盘点紧随 text.ll 写出 meta;Phase1 增量跳转额外要求 meta 存在
- Phase2 内联 is_decl_mi 与 PhaseC 判定统一走 IsDeclOnlyModule
去 IR 化步骤①(sidecar 最小闭环),全后端统一,默认行为不变。
|
2026-10-03 08:06:39 +08:00 |
|
TermiNexus
|
0ebe2e0752
|
feat(backend): 新增 MLIR 后端开关/产物隔离/降级管线/模块别名(默认 llvm 逐字不变)
- Config: BackendTarget/BackendIsMlir/set_backend/is_mlir_backend/backend_dir_suffix/alias_module_name;读取 options.backend(回退 options.target)
- main.vp: 新增 --backend llvm|mlir(CLI 优先级最高,默认 llvm),加载工程后、resolve_paths 前生效
- 产物隔离: temp/output 追加 _mlir 后缀;includes 缓存追加后端后缀(.binary[_asan][_mlir])
- BuildPipeline: MLIR 降级 mlir-opt(校验) -> mlir-translate --mlir-to-llvmir,覆盖串行/并行/--phase2command,且置于 ASan opt 之前;LlcTask 增 MlirOptCmd/MlirTranslateCmd 字段
- 别名: ResolveModuleToPath 与 _FindSha1ByModName 经 Config.alias_module_name 把 llvmlite 重定向到 mlirlite(调用点零改动)
|
2026-10-03 07:53:04 +08:00 |
|
TermiNexus
|
4eec3f0908
|
feat(dunder): 补齐 dunder 协议(__bool__/__call__/__str__/__abs__/__del__/**/增量/反向)
- __bool__:ExprGenOps.coerce_cond_to_bool 统一 if/while/and/or/not/三元/协程条件的真值归一,优先调度 __bool__
- __call__:obj(args) 分发到 obj.__call__(CallGenMixin 裸名分支)
- __str__:str()/print/f-string 调度(CallGenDispatch/CallGenLeafKit/ExprGenFstr)
- __abs__:abs(obj) 调度(CallGenMixin)
- __del__/__delete__:del obj → __delete__;del obj.attr 无 property deleter 时回退对象 __del__
- ** / __pow__:新增 llvm.pow 内联(整数按常量指数回写),_binop_to_dunder 补 Pow
- 增量赋值:__iX__ 优先、缺失回退 __X__(新增 _aug_op_to_dunder)
- 反向运算符:新增 _rbinop_to_dunder,lhs 无 dunder 时调度 rhs.__rX__
|
2026-10-03 00:40:00 +08:00 |
|
TermiNexus
|
a3bb62f2c3
|
feat(switch): switch 允许重复 case 标签(match 仍禁止)
- HandlesMatch / MatchGenMixin:值标签去重仅对 match 生效;switch 允许重复 case
标签(按书写顺序,先出现者生效);通配臂多个(default / case _)仍 fail-fast
- wiki/07-control-flow.md 同步该语义
|
2026-10-03 00:18:55 +08:00 |
|
TermiNexus
|
fabd92adc7
|
feat(switch): 新增 switch 语句并禁止 match 内 fallthrough
- MatchGenMixin:case 体按 node.is_switch 置 _in_switch_case;_has_no_break 只认 FallThrough 节点(去掉 c.NoBreak() 兼容路径)
- StmtGenDeclMixin:translate_fallthrough 只在 switch 的 case 体内合法,match/switch 之外 fail-fast
- Translator:_in_match_case 更名 _in_switch_case(语义 = 当前 case 体属于 switch)
- FuncGenDef / FuncGenMixin:函数体 / 嵌套函数 / lambda 入口隔离并恢复 _in_switch_case
- 因 match 改为硬关键字,重命名同名局部变量 match -> Matched(StubMergerStore / ImportsGenMixin / ExprGenAttr / CallGenBase)
|
2026-10-02 23:15:43 +08:00 |
|
TermiNexus
|
38860a6313
|
feat(match): 重名 case 标签 fail-fast
MatchGenMixin._translate_match_impl 新增前置检查(任何 IR 产出之前):新增
_case_label_same / _value_label_same 比较 switch 标签(常量 / 名字 / 属性链 /
MatchSingleton / MatchClass 变体名 / MatchOr 子模式),标签重复或出现多个
`case _` 时 fatal_error 终止(C switch 不允许重复 case 标签)。
|
2026-10-02 22:44:34 +08:00 |
|
TermiNexus
|
d633a5786f
|
fix(flow): 函数体入口清空 break/continue 目标与 match-case 标记
- FuncGenDef.translate_function_def:进函数体前保存并清空 _break_bb / _continue_bb /
_in_match_case,退出恢复
- FuncGenMixin:嵌套函数体与 lambda 体两处同样处理——原实现下嵌套函数体内的
break/continue 会继承外层函数的跳转目标(跨函数 br,非法 IR)
|
2026-10-02 22:40:04 +08:00 |
|
TermiNexus
|
fb4175736f
|
fix(flow): 循环/match 外的 break/continue 改为 fail-fast
- StmtGenDeclMixin:translate_break / translate_continue 增加 node 形参,目标块
缺失(_break_bb / _continue_bb 为 None)时 fatal_error,不再静默不发跳转
- StmtGenMixin:Break / Continue 分派传入 node(供错误定位)
|
2026-10-02 22:35:26 +08:00 |
|
TermiNexus
|
43d25e58b9
|
feat(match): case 内 break 跳出 match,并落地 fallthrough
- Translator:新增 _in_match_case(FallThrough 合法性判定用);_break_bb 注释补充
case 内 break 语义
- StmtGenDeclMixin:新增 translate_fallthrough(本身不产出 IR;非 case 体内 fail-fast)
- StmtGenMixin:FallThrough 语句分派
- MatchGenMixin:进出 case 体(含 default 臂)时暂存/覆盖 _break_bb = match end_bb,
使 case 内 break 跳出 match 而非外层循环;_has_no_break 兼容 FallThrough 标记;
REnum / simple 两条 switch 路径的 fallthrough 由"只留无终结符块"改为显式 br
下一个 case body(原实现产出非法 IR)
|
2026-10-02 22:33:15 +08:00 |
|
TermiNexus
|
0b7f7a50c7
|
docs(types): 同步 list 相关注释,list[T, N] 不是定长数组
- TypeGenResolve._is_count_arg_container:说明把 list 纳入判据只是为了历史写法
list[E, N] 的第 2 实参不被误当类名归一;list 本体是 _list.vp 的堆上 STL 容器
- AssignGenMixin:注释示例由 list[type] / list[type, N] 改为 CArray 形态
|
2026-10-02 22:16:30 +08:00 |
|
TermiNexus
|
8d01c01afd
|
feat(viperbuild): 落地 --src 工程模式配置面,并补齐循环 else 与整型 None 比较
- 新增 lib/core/builtin/ViperBuild.vp:--src Pass 0 依赖闭包扫描 + 宏配置提取 +
默认值填充 + 写回 Config;main.vp 路由改为工程模式并删除单文件分支
- Translator.vp:写入 triple / datalayout,翻译期擦除 viperbuild 宏语句;
ImportsGenMixin.vp:对 viperbuild 豁免 SHA1 校验
- StmtGenCifMixin.vp:for / while 的 else 子句在 11 条循环生成路径全部接通
- ExprGenOps.vp:None 比较按 None 所在侧分派,整型 None 隐式为 == 0 / != 0
|
2026-10-02 22:07:01 +08:00 |
|
TermiNexus
|
15b416b527
|
fix(type): 统一注入期类归属与导入上下文记账,修占位表爆与属性标记误解析
- StubMergerStore 新增共享导入上下文记账(AppendImportedModule / AppendFromImport /
ImportCtx / AllocImportCtx / NotePlainImport),ImportsGenMixin 与 VpiReader 共用同一份
口径;顺带移除 add_from_import 的 256 缓冲静默截断,VpiReader 删除两份私有副本
- 注入窗口按「名字归属」判据解析(is_module_class + CurDefModuleSha1):
_forward_declare_ptr_from_node 的 Name 分支、resolve_annotation_type 的 Name/Attribute
分支均补齐,使同一 stub 内先声明/先引用的类产出**具名占位**而不是 Ptr(i8),并新增
_is_tattr_marker 让 t.attr.* 属性标记不参与类型联合竞争
- VpiReader._inject_class_struct_declare:命中前向声明占位时不再早退,改为「占位 Ty
原地写入」(对齐 ClassGenDef.fill_fwd),修 StructTable 爆表(table full, cannot
register Translator)
- 清除全部一次性探针:[DBG-GEN](VpiReader / StructGenMixin / ClassGenDef)、
[DBG-ATTR](ExprGenAttr)、[MODSHA1](CallGenMixin)
根因记录:vpi 注入期漏记 `import X as Y -> from_imports "Y:X"`,使 GenTypes.VarEntry.Spec
(TSpec.TypeSpec | t.CPtr)取不到模块 SHA1、退化为 i8* 并被永久冻结
(CallGenCtor.vp:897 .PtrLevel 属性访问失败)。
last-good-0.0.5-dev.479
|
2026-10-02 17:29:38 +08:00 |
|
TermiNexus
|
2c33effee1
|
fix(type): 前向声明补 import-as 别名反查(LookupModNameByAlias)
_forward_declare_ptr_from_node 的 Attribute 分支此前仅走
ImportsGen.lookup_from_import 反查别名;对 `import X as Y`(from_imports 里存
"Y:X")补一道 StubMergerStore.LookupModNameByAlias 专用反查,避免别名解析不到
→ 拿不到模块 sha1 → 无法前向声明而退回 Ptr(i8)。现场候选:GenTypes.vp 的
`import lib.core.Gen.Type.TypeSpec as TSpec`,字段 `Spec: TSpec.TypeSpec*`
(ve_i.Spec.PtrLevel 属性访问失败)。
|
2026-10-02 11:48:31 +08:00 |
|
TermiNexus
|
4958fd2c14
|
debug(attr): [DBG-ATTR] 泛化到任意属性访问失败,打印基座/结构体/字段数(用完删除)
Generator.FuncGenBase 已由前向声明修复;新报错 ve_i.Spec.PtrLevel 属同类症状
(某字段指针的 pointee 不是可查字段的结构体)。去掉 attr=="FuncGenBase" 守卫,
任何属性访问失败都打印 obj_ptr.Ty / struct 名 / 条目 FieldCount / base_class。
仅打印,不改行为。
|
2026-10-02 02:50:01 +08:00 |
|
TermiNexus
|
87e2356eea
|
feat(type): rawptr[T]/t.CPtr[T] 下标形也走前向声明,并覆盖同文件前向引用
承接 c0d3231(X | t.CPtr 已改前向声明):
- t.CPtr[T] 分支:inner 解析为 None 时先尝试前向声明具名占位并返回
Ptr(占位.Ty),保住类身份;无法确定类名/模块时才回 None 交多遍收敛。
rawptr[T] 经 builtins typedef(rawptr = t.CPtr)兜底归一到本分支,故一并覆盖。
- _forward_declare_ptr_from_node 的 Name 分支补"本文件顶层类"回退:用
StructGen.register_file_classes 登记的"{名字 → 本文件模块 SHA1}"前向声明,
覆盖同文件前向引用 / 自我引用(如 JsonValue | t.CPtr 自引用字段)。
无编译验证。
|
2026-10-02 02:48:26 +08:00 |
|
TermiNexus
|
c0d3231e02
|
fix(type): 未注册类指针改前向声明(具名不透明占位)+ 定义侧原位填充
对齐 TPC 语义(未注册类 → 具名空 CStruct 占位 + 后续 set_body 填充)。
此前 TPV 对"指向尚未注册类的指针"回退匿名 Ptr(i8),丢类身份且被冻结后
无法修复:现场 CallGenBase.Gen: Generator.Generator* 与 Generator 构成
循环依赖(Gen→Generator,Generator.CallGenBase→CallGenBase),Gen 先于
Generator 注册 ⇒ 冻结成 i8* ⇒ self.Gen.FuncGenBase 属性访问失败
(1.log 取证:Generator 条目本身正确 fcount=47,但 lookup_field 收到
struct_ty=<non-struct>)。
- GenTypes.StructEntry 新增 IsForwardDecl 标记(占位条目)。
- StructGenMixin.ensure_forward_class:按"类名 + 定义模块 SHA1"登记具名
不透明结构体 {sha}.Class 占位(名称与定义侧 ClassGenDef 同口径,持久池
分配),幂等;定义侧据此按名定位原位填充。
- TypeGenResolve._forward_declare_ptr_from_node(Attribute/Name 两形,经
from_imports 与模块名表求 sha1,再 _class_true_def_sha1 校正)+ BinOp
(X|t.CPtr) 未注册回退:优先返回 Ptr(占位.Ty);仅在无法确定类名/模块时
才退回 Ptr(i8) 由 AnnotClassName 恢复。
- ClassGenDef:命中前向声明占位时不早退,把新构建的字段体**原位写入同一
Ty 对象**(*existing.Ty = Struct(...),指针身份不变),登记条目沿用占位
条目;declare_only 1/0 均适用。所有已发出的 Ptr(占位.Ty) 引用在填充后
自动指向完整定义。
TPC 侧核对:TPC 本就是"具名占位 + set_body"模型(TypeAnnotationResolver
.CreateFromTypeName / BaseGen._get_or_create_struct / StructGen op 占位),
并有 fail-fast 拒绝类引用降级为 void**,无需改动。
|
2026-10-02 02:40:05 +08:00 |
|
TermiNexus
|
d1c0f6754c
|
debug(gen): 补 [DBG-ATTR] 探针——FuncGenBase 处 obj_ptr 类型与注解类名兜底(用完删除)
已知(1.log 取证):Generator 结构体登记正确(tbl[337] fcount=47 含 FuncGenBase),
真正问题是 `self.Gen` 字段类型退化成 i8*(lookup_field 收到 struct_ty=<non-struct>)。
本探针在报错点补打印:
- obj_ptr.Ty(确认是否为 i8*)
- base_class(_resolve_attr_field_class 取到的 Gen 字段注解类名)
- 用 base_class 走 lookup_field_by_class 找 FuncGenBase 的字段下标
用于判定"注解类名未记录"还是"按类名查询也失败"。仅打印,不改行为。
|
2026-10-02 02:31:09 +08:00 |
|
TermiNexus
|
01e95b51cf
|
debug(gen): 一次性取证插桩——Generator 结构体登记/查找全链路(用完删除)
覆盖点(全部以 [DBG-GEN] 为前缀,仅打印不改行为):
- StructGenMixin.register_struct:IN(name/sha1/ty/StructCount)、DEDUP(命中条目)
- StructGenMixin.add_field:逐字段打印写入 Generator 条目的字段名与下标
- StructGenMixin.find_struct_by_module:IN / HIT / MISS
- StructGenMixin.lookup_field(field=FuncGenBase):struct_ty 名、按 Ty 指针命中条目的
全字段名、以及结构体表内所有含 "Generator" 的条目
- VpiReader._inject_class_struct_declare:IN / EXISTING / RENUM-SKIP / EMPTY /
FIELD-FAIL / REGISTERED
- ClassGenDef.translate_class_def:EXISTING / REGISTER / DONE
目的:一次重建即可判定 Generator.FuncGenBase 查不到是"命中空/旧条目""Ty 错配"
还是"字段名悬空",并看清是哪条登记路径产出的条目。
|
2026-10-02 02:18:55 +08:00 |
|
TermiNexus
|
1ad7abf33d
|
refactor(TransPyV): 统一自举写法(novirtual / define / rawptr→* / 去续行反斜杠)
- @t.NoVTable class X → novirtual class X
- t.CDefine = N → define N
- rawptr[X]、X | t.CPtr → X*
- t.CPtr → rawptr(裸指针标记)
- t.Callable[...] → callable[...]
- 去掉 if/elif 条件的行续反斜杠(改单行写法)
- w32.win32file.X → win32file.X(已 import as)
- core/__init__.vp 去掉未使用的 import t, c / from stdint import *
涉及:CompilerFactory、IncludesScanner、Repl、core/__init__、
Gen/Call/{CallGenBase,CallGenCBuiltin,CallGenCall,CallGenDispatch,CallGenLeafKit}、
Gen/Class/ClassGenGeneric。
|
2026-10-02 02:16:37 +08:00 |
|
TermiNexus
|
7e82ed6940
|
chore(debug): 移除 [DBG-GEN] 一次性插桩(改走静态分析)
按用户要求撤掉 lookup_field 里的临时打印,恢复原函数体。
|
2026-10-02 02:14:54 +08:00 |
|
TermiNexus
|
1d1efc6288
|
debug(gen): 一次性插桩打印 Generator.FuncGenBase 字段查找上下文(用完删除)
AsyncGenMixin.vp:58 `self.Gen.FuncGenBase` 报「属性访问失败」,需确认
lookup_field 收到的 struct_ty 是谁、结构体表里 Generator 条目的 FieldCount/sha1,
以判断是字段缺失、Ty 身份不一致还是按到了空/错误条目。仅打印,不改行为。
|
2026-10-02 02:10:58 +08:00 |
|
TermiNexus
|
f865986675
|
fix(stub): App 预注册注入依赖 vpi 时跳过函数/方法 declare,避免打断多遍收敛
承接上一提交(App 预注册期开始注入依赖 vpi)。注入的依赖 vpi 里,函数/方法
declare 的形参/返回注解可能引用**本遍尚未注册**的类(跨文件注册顺序:被依赖模块
的类可能排在更后,需靠下一遍收敛),resolve 落空会在 declare 注入里 fail-fast,
直接打断 Phase A-pre 的多遍收敛。现场:App 预注册 AssignGenMixin.vp 注入
Translator.vpi 时,InjectTracebackInstallCtor 形参 rawptr[Translator] 解析失败
(Translator 结构体因字段引用尚未注册的 GenTypes 类而本遍未登记)。
改动:VpiReader._ParseVpiIntoModuleImpl 新增 pre_skip_fn_declares(仅当
trans._pre_allow_dep_inject != 0 即 App 预注册时置 1),在「第一遍 B 方法 declare」
与「模块级函数 declare」两处跳过注入。预注册的唯一目的是注册 struct/enum/union
(第一遍 A)与包重导出别名(ImportFrom 段),两者均保留;方法/函数 declare 写在
预注册的瞬时模块里、随即随 mb.reset_to 丢弃,无跨遍作用。全量翻译
(_declare_only==0)不跳过,仍 fail-fast。
|
2026-10-02 01:47:18 +08:00 |
|
TermiNexus
|
981af07d5c
|
fix(phase): App 预注册期注入依赖 vpi,修 list[ast.ClassDef*] 票名前缀分裂
Phase A-pre(App 预注册)此前不做导入处理、不注入依赖 .vpi,导致包重导出
类的字段注解在预注册期只能保留「包前缀」(1abcd…),并被冻结进结构体布局;
阶段 A 构造函数侧却能借包别名 entry 校正为真定义前缀(e70bd…),两处票名
分裂 ⇒「非基本类型指针不可隐式转换」(现场 ClassGenGeneric.vp:92)。
改动(只放开 App 预注册,不动 includes 预注册那条防依赖环自锁的约束):
- Translator 新增 _pre_allow_dep_inject 开关,并在导入处理门拆成两道:
①导入处理 + 自动容器可见性 + LoadDepVpiIntoModule —— 全量翻译与 App 预注册共用;
②模块级变量预注册 + 函数前向声明 —— 仍只在全量翻译做。
- BuildPipeline.TranslateFileGetTrans 新增 pre_allow_dep_inject 参数并写入 Translator。
- Phase2 App 预注册调用点传 1;includes 预注册保持默认 0。
|
2026-10-02 01:03:31 +08:00 |
|
TermiNexus
|
57f8c655c8
|
chore(debug): 移除 [DBG-P7] 一次性插桩(根因已定位)
定位结论见 Debugger/debug-nested-class-struct.md 的 P7:不是别名登记失败,而是
Phase A-pre(预注册 struct/enum/union,declare_only)解析类字段注解时,被 import
模块的 vpi 一概尚未注入 ⇒ 包重导出别名 entry 不存在 ⇒ 字段侧票名保留包前缀并被
冻结进结构体布局,与阶段 A 构造函数侧的真定义前缀分裂。
删除 96c1102 / 3b8a2b2 引入的全部临时打印(VpiReader.vp / TypeGenResolve.vp /
CallGenCtor.vp 三处),代码回到插桩前状态(-108/+0)。
|
2026-10-02 00:59:44 +08:00 |
|
TermiNexus
|
acd6c9a615
|
docs(expr): 去掉指向已删除的 wiki/14-oo-refactor.md 的注释引用
该文档(对象化重构计划)已完成并从 wiki 删除,注释只保留「对象化 P3」的来源标记,
避免留下悬空文档引用。
|
2026-10-02 00:47:17 +08:00 |
|
TermiNexus
|
3b8a2b225f
|
debug(stub): 补全 [DBG-P7] 插桩覆盖所有票名产生路径(定位后删除)
在 96c1102 基础上把"可能产出该票名"的路径一次打全,保证一次重建即可定死根因:
- TypeGenResolve._class_true_def_sha1:MISS 时额外 dump 结构体表里所有名字含
ClassDef 的条目(下标/名字/归属 sha1/Ty 的 IR 名前缀)——直接看出别名 entry
到底有没有、挂在哪个 sha1 上。
- TypeGenResolve.extract_class_name_from_annotation:AnnotClassName 通道算出的
泛型票名(含 ClassDef 才打)。
- TypeGenResolve._resolve_generic_subscript_ty:注解/字段侧算出的泛型特化名
gen_mangled(含 ClassDef 才打)。
- CallGenCtor._extract_type_args_from_slice:构造函数侧实参串的 raw/norm 两态。
- VpiReader._inject_class_struct_declare:进入 + 各出口
(already / renum_skip / field_unresolved / zero_fields / registered)。
- VpiReader._inject_reexport_class_declare:调用现场与四个出口
(already / no_src_entry / alias_reg_fail / alias_ok)。
|
2026-10-02 00:34:38 +08:00 |
|
TermiNexus
|
96c110242e
|
debug(stub): 一次性插桩定位 ast.ClassDef 票名前缀分裂(定位后删除)
9994d2e 改判据后现象不变,需要在一次重建里同时看到三处事实,避免反复猜:
- TypeGenResolve._class_true_def_sha1:cls 含 "ClassDef" 时打印 HIT/MISS 与候选
sha1、命中条目的 IR 名前缀(用 strstr 以便同时捕获 "ClassDef*" 形态);
- VpiReader._inject_reexport_class_declare:src/local 为 ClassDef 时打印调用现场
的「源 entry 是否已注册 / 别名是否已存在」(src_entry=0 ⇒ 别名必然建不起来);
- VpiReader 的 ImportFrom 分支:判定为包 __init__ 时各打印一行(模块名、包前缀、
子模块名与解析出的 sha1),确认包判定与子模块解析是否成立。
全部带 [DBG-P7] 前缀,便于 grep 与事后清除。
|
2026-10-02 00:32:05 +08:00 |
|
TermiNexus
|
9994d2e983
|
fix(stub): 包 __init__ 判定改按模块名,修 ast.ClassDef 票名前缀分裂
存量缺口:VpiReader 判定"本 stub 是否包 __init__"依赖 sha1→rel_path 反查
(strstr(rel_path, "__init__.vp"))。该反查在部分运行形态下取不到条目 ⇒ 判定恒
false ⇒ 包重导出类的别名 entry 静默不登记 ⇒ `ast.ClassDef` 这类限定名在泛型实参
里保留包前缀(幽灵名 `list[1abcd5277fa442de.ClassDef*]` 全产物恒 opaque),与构造
函数侧的真定义模块前缀(`list[e70bd9b4487d921d.ClassDef*]`)分裂成两个类型,报
「指针隐式转指针已禁止」(现场 ClassGenGeneric.vp:92 的 CastError)。
改法(不再依赖 rel_path 字段,均为模块名表的既有事实):
- StubMergerStore 新增 LookupModNameBySha1:按 SHA1 反查模块名(只读指针)。
- VpiReader 的 ImportFrom 分支:取 level>0 的兄弟模块 S,用其模块名去掉末段得到包
前缀 P;又因 Utils.PathToModuleName 把 pkg/__init__.vp 记成 "pkg",故
「本 stub 的模块名 == P」即证明本 stub 就是包 P 的 __init__ ⇒ is_pkg_init_rt=1,
同时直接用 P 拼出子模块全名(不再从 rel_path 反推目录名)。
- 模块名证据不足时仍回退原 rel_path 路线,行为不变。
|
2026-10-02 00:07:23 +08:00 |
|
TermiNexus
|
b91dfef777
|
feat(stub): vpi 注入侧递归登记嵌套类为扁平名 {外类}_{内类}
VpiReader 此前只登记顶层 ClassDef,跨模块引用 `外类.内类` 拿不到类型
(TPC 侧 stub.ll 已递归声明,双端不对齐)。现按定义端
ClassGenDef._translate_nested_classdefs 的命名口径补上:
- _inject_class_struct_declare 增加 name_prefix 形参,非空时算出扁平名
real_name;REPL 分支、已注册检查、命名结构体类型名、register_struct、
add_visible_struct 一律改用 real_name。
- 新增 _inject_nested_class_declares:遍历类体内缩进 ClassDef 子节点,
以 real_name 为前缀递归调用(多层嵌套自然展开为 A_B_C)。
- 嵌套登记后再次调用 mark_module_class 复原"正在定义类"窗口:否则内层
类名会顶掉 CurDefClassName,使外层字段注解的规则 5.5 自引用证据判错、
且 `外类.内类` 的守卫①失效。
|
2026-10-01 23:39:11 +08:00 |
|
TermiNexus
|
c3f554f1f5
|
feat(struct): 嵌套 class/struct 发射为独立结构体 {外类}_{内类}
用户 2026-10-01 定:struct 内允许叠加 struct(与 class 内写 class 同口径)。
此前类体里的嵌套 ClassDef 被**静默丢弃**(字段循环只认 AnnAssign、
_translate_oop_methods 只认 FunctionDef),现按 TPC 侧 union/renum 的
`{ClassName}_{Nested}` 命名先例发射为独立结构体,与 TPC 提交 5eef845e 同源。
- ClassGenDef.vp:新增 _translate_nested_classdefs —— 在 enum/union/renum/泛型/
异常分派之后、existing 检查之前(所有提前 return 之前,故 declare_only=1/0 都递归)
遍历类体 ClassDef 子节点,把子节点 name 临时改写为扁平名后递归
translate_class_def(本模块所有名字派生点都读 cd.name ⇒ 改名即全链路一致)。
两个护栏:扁平名分配在 PermPool(跨 Phase 存活);递归后还原 CurDefModuleSha1/
CurDefClassName(内层 mark_module_class 会覆盖,否则外层字段解析误判当前定义类)。
- TypeGenResolve.vp:新增 _resolve_nested_class_type 并在 Attribute 分支的
"base 不是模块" 出口前接上 —— 限定名 `外类.内类` 按扁平名查结构体表即可命中
(裸名 `外类_内类` 走既有 Name 分支天然命中)。判据两道:base 是已知类
(find_struct 命中,或正处于该类的定义窗口内);扁平名条目存在且 Ty 非空。
引用两种写法都可用:`外类.内类`、`外类_内类`;多层嵌套递归为 A_B_C。
|
2026-10-01 23:30:15 +08:00 |
|
TermiNexus
|
3ccc37ca3f
|
fix(type): 泛型实参归一先剥尾随星号,消除包前缀票名分裂
_norm_type_arg_name 规则 4 用 strchr('.') 切出 attr 时把尾随 '*' 一起带进了类名
('ast.ClassDef*' → attr='ClassDef*'),于是 _class_true_def_sha1 按名查不到
entry、真定义模块校正失效,留下包前缀:
字段侧 ClassGenBase.vp:123 → list[1abcd5277fa442de.ClassDef*](无定义的幽灵名,
全部产物里只有 = type opaque,从无 = type {...})
构造侧 ClassGenGeneric.vp:92 → list[e70bd9b4487d921d.ClassDef*]
⇒ ClassGenGeneric.vp:92 报「指针隐式转指针已禁止」。
TPC 侧名称域(SymbolUtils.ResolveTypeArgStr 的 BinOp 分支)本就是「先解析基类型 X,
再 AddPointerLayers 追加 '*'」→ {真定义sha}.X*,TPV 与之对齐。
新增规则 1.6:剥掉全部尾随 '*' → 递归归一基名 → 回贴同样多的 '*'。
i8** / int* / T* / 已带 SHA1 前缀的文本逐字不变。
|
2026-10-01 22:40:54 +08:00 |
|
TermiNexus
|
02b9429363
|
fix(type): void* 归并分支的 match 必须守 None,修 ASan 空指针崩溃
BinOp 的 CPtr 分支里,上一笔为 void* 归并新增的 match other_ty 未判空。
other_ty = resolve_annotation_type(另一边) 在 Phase 1a prescan 时**可以是 None**
(本分支下方既有代码就写着 if other_ty is None: ... 回退 Ptr(i8),正说明 None 是
期望值);对 None 做 REnum case 匹配会按其 tag 解引用空指针。
现场:TPV(ASan) 自举 Phase1 报 access-violation on address 0x0(READ),
栈 _prescan_funcdef_signatures → resolve_annotation_type;触发源是用户 WIP 里
新增的 X* 返回注解(parser 把 X* 展开成 BinOp X | t.CPtr,正好走本分支)。
改为 if other_ty is not None: 包住,None 继续走下方既有回退路径。
|
2026-10-01 22:07:41 +08:00 |
|
TermiNexus
|
be14fa5f94
|
fix(ctor): REnum 变体构造识别取错限定名,导致构造物化豁免失效
_ctor_call_agg_ty 从被调方沿属性链一路走到链根裸名,三段式
llvmlite.LLVMType.Struct(...) 于是被判成限定名 'llvmlite'(非 REnum 类)⇒
返回 None ⇒ ClassGenDef.vp:128 的 *existing.Ty = LLVMType.Struct(...) 被
「指针 → 非基本类型值」禁令拦下。改为取「变体名左边那一段」:两段式取裸名
(EnumType.Variant)、三段式取属性名(llvmlite.LLVMType.Struct → LLVMType)。
|
2026-10-01 21:44:55 +08:00 |
|
TermiNexus
|
2f6db41b11
|
fix(void): 形参与字段注解禁止 void,改为编译期 fail-fast
void 只允许用于 void* 与 typedef 不透明结构体别名(用户 2026-10-01 定)。
此前 def f(p: void) / class C: x: void 不走 translate_annassign,会按 LLVM void
直接建形参/字段槽,生成非法 IR 拖到 llc 阶段才暴露。现补 6 处形参落点
(FuncGenDef 前向声明/外部声明/函数体/alloca 各一、ClassGenVTable 签名/alloca 各一)
与 1 处字段落点(ClassGenDef),统一编译期 TypeError。
void* 已在上游归并为 i8*,不受影响。
|
2026-10-01 21:43:11 +08:00 |
|
TermiNexus
|
59865b2a3a
|
feat(TPV): void 值操作 fail-fast(声明 void 变量 / 把 void 值当值用一律报 TypeError)
承上一笔(裸名 void = t.CVoid 别名,仅 `void*` 与 `typedef 不透明结构体 = void` 可用):
- ExprGenBase.coerce_to_type 顶部:void 值被 coerce 到**非 void** 目标(赋值 / 传参 /
返回 / 二元运算对齐)直接 fatal_error(TypeError),不再按 LLVM void 硬拼出非法 IR
("load void" / "bitcast ... to void");void → void 属无值传递,放行。
- AssignGenMixin.translate_annassign:注解解析结果为 void 时禁止声明该变量
(否则会按 LLVM void 建槽)。
|
2026-10-01 21:39:48 +08:00 |
|
TermiNexus
|
e0bcf4bcef
|
feat(TPV): 裸名 void 作为 t.CVoid 的别名(void* = i8*)
用户 2026-10-01 需求:`void` 即 t.CVoid 的别名,只允许两种用法——`a: void*` 与
`typedef 不透明结构体 = void`(后者 `X*` 亦为 i8*)。
- TypeGenResolve 内置名表:新增 "void"(与 "CVoid" 同义 → llvmlite.Void)
- TypeGenResolve._is_cvoid_marker:裸名 "void" 与 "CVoid" 同判
- TypeGenResolve BinOp 联合合并:裸名 "void" 直接置 other_is_cvoid(无需 import t);
解析结果本身是 Void 时亦按 void* = i8* 归并,覆盖 `typedef X = void` 的 `X*`
(否则会拼出非法的 Ptr(void))
- VpiReader:注解文本里的裸 "void" 段与 "CVoid" 同判(has_cvoid → i8*);
has_cptr 分支对解析结果为 Void 的 first_ty 同样归并为 i8*(跨模块侧同口径)
TPC 侧无需改动:HandlesBase 的内置名表已有 'void': (t.CVoid, 0),
`void*` 经既有 CVoid+CPtr 合并即 i8*。
|
2026-10-01 21:37:40 +08:00 |
|
TermiNexus
|
21d5cd1cd1
|
fix(ExprGenBase): REnum 变体构造纳入「构造物化」豁免;错误报文只报问题本身
1) _ctor_call_agg_ty 增加 REnum 变体构造识别:`EnumType.Variant(...)` 的变体名不是结构体名
(find_struct 必 miss)⇒ 取属性链最右裸名,若判为基础枚举则返回该枚举的聚合类型。
否则 `*槽 = <boxed 变体>` 会被「指针 → 非基本类型值」禁令拦下——
现场 ClassGenDef.vp:128 `*existing.Ty = llvmlite.LLVMType.Struct(...)`。
2) 按用户要求简化 Error 输出:CastError 只报问题(原因 + 源/目标类型),去掉
";出错表达式: <形态>(行/列)源码: ..." 后缀(文件与行号已由 TypeGenErr 的 Traceback
帧给出,属重复展示),并删除随之失去调用点的 _cast_fail_where / _source_snippet。
|
2026-10-01 21:17:49 +08:00 |
|
TermiNexus
|
a714ec9d37
|
fix(VpiReader): 返回/形参注解切分只在顶层 | 处断段(括号感知)
_resolve_vpi_ret_annot_str 原按裸 `|` 切段,`list[ast.AST | t.CPtr] | t.CPtr` 会被切成
`list[ast.AST` / `t.CPtr]` / `t.CPtr`;首段再经 strrchr('.') 落到 `AST` ⇒ 定义侧类型解析成
`AST*`(元素指针),而正确答案是 list 专化结构体的指针。现场:跨模块调用 coerce 时报
"源类型 list[AST*]* → 目标类型 AST*"(CallGenLib._coerce_args_to_def_params 的 cargs 形参)。
现切分按 `[`/`]` 深度,只在顶层 `|` 处断段(与 _cache_vpi_param_annots_text 的顶层逗号
切分同口径)。改后该段解析不出 ⇒ 落 i8* 通配,与 `list[str] | t.CPtr` 等同形注解的既有
行为一致;配合 CallGen 侧的 bitcast 对齐(见上一笔)即可安全使用。
|
2026-10-01 20:45:21 +08:00 |
|
TermiNexus
|
8e3811c490
|
fix(CallGen): 跨模块调用的 declare 形参与实参统一以定义侧为准
问题一(declare 形参被首个调用点冻结):CallGenBase._ensure_method_declare 新建跨模块方法
declare 时形参类型取"首个调用点的实参类型",而这条 declare 被同模块所有调用点共用 ⇒ 后续
调用传入另一种具体指针类型时,被这条被冻住的形参类型 coerce,报"非基本类型指针间隐式转换"。
现场:VarGenMixin.repl_ensure_entry 的 node: ast.AST*,先被 translate_annassign 以 ast.AnnAssign*
建 declare,后 translate_assign 传 ast.AST* 即报"源类型 …AST* → 目标类型 …AnnAssign*"。
⇒ 指针形参与整数同口径,一律采用定义侧(.vpi 注解段)类型;解析不出指针时保留实参类型。
问题二(实参未对齐 declare):declare 改用定义侧类型后实参也必须对齐,否则首个调用点
(由它建立 declare、不走 coerce_to_type)原样传具体指针会与 declare 类型不一致(llc 报
argument type mismatch)。⇒ CallGenLib._coerce_arg_value_to_ty 的同层指针分支改为"类型内容
不一致即 bitcast 到定义侧类型"(原判据只覆盖一侧为 i8*、或模板注解来源两种情形)。
|
2026-10-01 20:29:15 +08:00 |
|
TermiNexus
|
93e983f74e
|
fix(TPV): 删除残留的"| t.CPtr struct 引用语义吸收"(T* 被降一层的真正根因)
现场(0a81e67 之后仍复现):Test/SlotsBugTest 编译 includes/_list.vp:54
TypeError: 下标赋值的左值元素是对象 'd1ed020479454541.AST'(48 字节),右值却是指向
'd1ed020479454541.AST' 的指针
elem_ptr[0] = item
关键事实:`T*` **不是** `rawptr[T]` 下标形——parser 把尾随 '*' 解析成
BinOp(`T | t.CPtr`)(includes/ast/parser.vp:1528-1556 `_make_ptr_type`、:2700-2707)。
所以它走 resolve_annotation_type 的 **BinOp 联合分支**,0a81e67 只修了
rawptr[T] / t.CPtr[T] 两条**下标**分支,覆盖不到这里。
链路(逐段在源码上核对过):
1. 泛型实参 `rawptr[AST]` 经 _norm_type_arg_name 归一为文本 `{sha}.AST*`;
2. `T` 走 Name 分支的泛型替换 → _parse_type_string 的 `T*` 反解析(:995-1018,
按尾随 '*' 层数包 rawptr[...])⇒ other_ty = Ptr(AST),本身正确;
3. BinOp 分支尾部的"struct 引用语义吸收":other_ty 已是 Ptr(已注册 struct)
⇒ 直接 `return other_ty`,**吞掉 CPtr 这一层** ⇒ `T*` 变成 AST*(应 AST**)。
改动:
- TypeGenResolve.vp BinOp 分支:删除该吸收,恒 `return Ptr(other_ty)`
(与 rawptr[T] / t.CPtr[T] 下标形、_parse_type_string 的 `T*` 反解析三处同口径)。
- VpiReader.vp:1614-1621 注入侧的同源吸收一并删除(维持"定义侧 / 注入侧 / 调用侧
三处指针层数口径同步")。
- 两处口径注释同步改为"`| t.CPtr` 恒追加恰好 1 层,无例外"。
安全性(该吸收已是死补偿):它是"裸类名自动升指针"时代的产物——当时裸类名解析成
Ptr(struct),所以要吸收;自 2026-10-01 起裸类名恒为原型 struct,`X | t.CPtr` 由
Ptr(struct) 天然得到 X*。json/__init__.vp:90 的引号注解 `'JsonValue' | t.CPtr`
现在 other_ty 就是 struct ⇒ 吸收本不触发,删除后行为不变(JsonTest 已实测翻译通过并
进入 llc 阶段)。`list[int]`(i32*)、`list[ast.AST]`(struct*)、裸类名 `X | t.CPtr`
(struct*)均不受影响。
待验证:重编译 TransPyV(自举两遍)→ SlotsBugTest / JsonTest / WebTest。
|
2026-10-01 17:46:53 +08:00 |
|
TermiNexus
|
0a81e67e89
|
fix(TPV/TypeGenResolve): rawptr[T]/t.CPtr[T] 恒追加 1 层,删除"裸类引用吸收"旧补偿
现场:Test/SlotsBugTest 编译 includes/_list.vp:54 报
TypeError: 下标赋值的左值元素是对象 'd1ed020479454541.AST'(48 字节),右值却是指向
'd1ed020479454541.AST' 的指针
源码: elem_ptr[0] = item
用户判定正确:`elem_ptr: T*` 与 `item: T` 同为 T,赋值本身合法;错在编译器把 `T*`
少算了一层——T 实例化为 rawptr[AST](= AST*)时,`T*` 应为 AST**。
根因:rawptr[T] / t.CPtr[T] 分支里有"切片是裸类引用(解析结果 Ptr(已注册 struct))
就吸收这 1 层"的旧补偿(_ptr_subscript_absorbs_class)。那是"裸类名自动升指针"时代的
产物——当时裸类名解析成 Ptr(struct),于是 rawptr[X] 会多包一层,需要吸收;
自 875a9be 起裸类名恒为**原型(struct 值)**,Ptr(struct) 天然就是 X*,补偿已无对象;
而**泛型形参实例化为指针类型**时(T = rawptr[AST]),切片的解析结果同样是
Ptr(已注册 struct) ⇒ 被误吸收:`elem_ptr: T*` 变成 AST*(应为 AST**)⇒ 左值元素被判成
48 字节的 AST 对象、右值是指针 ⇒ fail-fast。
改动:
- 删除 _ptr_subscript_absorbs_class,以及 rawptr[T] / t.CPtr[T] 两处调用,改为**恒追加
1 层**:`rawptr[T]` ≡ `t.CPtr[T]` ≡ `T*` ≡ `T | t.CPtr` 四种写法同型(用户口径),
不再有"裸类引用吸收"例外。
- 同步修正四处引用该函数的口径注释(:407 / :433 / :567 / :1000)。
- **保留** BinOp `| t.CPtr` 分支内的同名吸收:它只对**非裸名**侧可达(Constant/Attribute;
裸名侧在更早的"Name 必须已注册 struct"守卫处就改走其它分支),故
includes/json/__init__.vp 的引号注解 `'JsonValue' | t.CPtr` 行为不变。
仓库内也不存在 `rawptr['X']` / `CPtr['X']` 切片写法(仅注释提及),删除吸收无副作用。
已知遗留(本次未改,待你定夺):`T | t.CPtr` 这一写法在 T 实例化为指针类型或类类型时
仍会退化——Name 侧解析出的 Ptr(struct) 被丢弃,随后按名字 'T' 查 struct 失败 ⇒
返回 Ptr(i8)(位置:本文件 BinOp 分支的 keep_other_ty 判定,约 :3166-3194)。
当前仓库没有使用该写法的现场,故未一并改动。
待验证:重编译 TransPyV(自举两遍)→ SlotsBugTest / JsonTest / NoVTableCrossMixinTest。
|
2026-10-01 16:51:31 +08:00 |
|
TermiNexus
|
f748cae562
|
fix(TPV/CallGenCall): 判据化重加兄弟 Mixin 方法解析(修 NoVTableCrossMixinTest 未定义符号)
现场:Test/NoVTableCrossMixinTest 链接期报
ld.lld: error: undefined symbol: 1e19037e6cfdce36.BaseB.helper
>>> referenced by ...(1e19037e6cfdce36.BaseB.caller)
ld.lld: error: undefined symbol: 1e19037e6cfdce36.MixinC2.mid2
>>> referenced by ...(1e19037e6cfdce36.MixinC2.outer2)
这是 455c760 删除"兄弟 Mixin 兜底"的必然结果:NoVTable 多继承下,Mixin 内的
self.<兄弟方法>()(Combined(BaseA, BaseB) 中 BaseB.caller 调 BaseA.helper)本类
MRO 查不到、跨模块 stub 也没有 ⇒ 调用名退化成 {sha1}.BaseB.helper(该符号不存在)。
改动(不是恢复原兜底,而是**判据化解析**,不做"同名即绑"的猜测):
- CallGenCall._translate_method_call:在自身 MRO 查找失败后新增兄弟 Mixin 解析,
两条**正向判据**缺一不可:
① 接收类必须是某个已注册类的**直接父类**(它确实被组合使用,是真 Mixin)——
挡掉 includes/w32/fileio.vp 的 FileW.__init__ → self.seek() 误绑 File.seek
(FileW 无人继承,不是任何人的 Mixin);
② 候选类与接收类必须同处某个已注册**组合类的 MRO**(真·兄弟)。
命中后 found_func / mc_anc 都指向定义类 ⇒ 调用名用定义类 SHA1 前缀(符号存在),
this 由既有的 mc_anc this-adjust 分支按组合布局前移(该分支未改动)。
只取**本模块内已有函数**的候选(跨模块定义类需经其 text.ll 取签名,本轮不启用);
接收类为跨模块类时不启用(沿用原 sib_recv_local 守卫,避免误绑跨模块同名方法)。
- 新增两个判据辅助方法:_recv_is_mixin_base / _mixin_sibling_same_composite。
待验证:重编译 TransPyV(自举两遍)→ NoVTableCrossMixinTest / WebTest / FileIoTest。
|
2026-10-01 15:00:55 +08:00 |
|
TermiNexus
|
dc4e06d88b
|
fix(TPV): 本文件自己声明的 extern 裸名优先于依赖 vpi 注入的同名声明
现场:Test/WebTest 编译 includes/socket.vp:236 报
CastError: 指针隐式转指针已禁止:源 %"56d0ee99ecf0a0b5.SocketAddr"* →
目标 %"99c88d4cbd933ac6.WSASocketAddr"*
源码: result = connect(self.fd, c.Addr(addr), 16)
机制(**链接期无冲突**——两边都不是 export,@connect 是同一个 C 符号,最终只有
ws2_32 里一个定义;问题在"编译 socket.vp 时的同一个模块内"):
1. extern/state/export 声明的符号**不带 SHA1 前缀**(FuncGenDef.vp:172-173
`mangled_name = fd.name`)⇒ socket.vp 与 w32.winsock2 都产出裸名 @connect
(前者形参 SocketAddr|t.CPtr,后者 WSASocketAddr|t.CPtr)。
2. Translator 的 prologue 先注入依赖 w32.winsock2 的 vpi
(StubMergerBuild.LoadDepVpiIntoModule → VpiReader.ParseVpiIntoModule →
_inject_function_declare:create_declare + module_add_function),当前模块里
先出现了 winsock2 版的 @connect。
3. 随后 forward_declare_functions 处理 socket.vp 自己的 `extern def connect` 时,
find_func_in_module 命中已存在 ⇒ `continue`(FuncGenDef.vp:178-182)
⇒ **本文件自己的声明被静默丢弃**,调用点改按 winsock2 的形参 coerce
(报错里的目标类型 WSASocketAddr* 正是 winsock2 版的指纹)。
(同文件 send/recv/socket/listen 亦被顶掉,只是形参是 i8*/u64,不报错——
即 socket.vp 的 POSIX 分支本来就在调用 winsock2 的声明。)
改动(注入期跳过"本文件已声明的裸名",让本文件自己的声明优先):
- StructGenMixin:新增 FileFuncNames 表 + register_file_funcs(pool, tree) /
is_file_func(name),与既有的 FileClassNames / register_file_classes /
is_file_class 同规矩(键与表同池、每文件随 reset_visible_structs 重建)。
- GenApi:新增 register_file_funcs / is_file_func 委托包装。
- Translator._translate_module_level:在 register_file_classes 之后调用
register_file_funcs(三种模式共用、早于依赖 vpi 注入)。
- VpiReader._inject_function_declare:算出 mangled name 后,若 `use_bare_name != 0`
且 `is_file_func(fd.name) != 0` 直接返回(不注入)。判据只用**裸名**:带 SHA1
前缀的依赖函数名与本文件同名声明不会互相顶替,避免误跳过跨模块调用。
待验证:重编译 TransPyV(自举两遍)→ WebTest / JsonTest / FileIoTest。
|
2026-10-01 14:46:47 +08:00 |
|
TermiNexus
|
d979cc8c1f
|
fix(TPV/ExprGenName): 结构体值局部变量在使用处要求同型结构体值时 load 出值
现场:Test/WebTest 编译 includes/socket.vp:121 报
CastError: 非基本类型的值/指针隐式转换已禁止(构造物化除外):
不能把指针类型隐式转为非基本类型值(Foo* → Foo)
源类型 %"56d0ee99ecf0a0b5.SocketAddr"* → 目标值类型 %"56d0ee99ecf0a0b5.SocketAddr"
现场代码:
class SocketAddr: family: u16 / port: u16 / addr: u32 / zero: u64 # 纯结构体,无 __new__、无方法
def _MakeAddr(host: str, port: INT) -> SocketAddr:
addr: SocketAddr # 结构体值局部变量
string.memset(c.Addr(addr), 0, 16)
...
return addr # ← 第 121 行报错
根因:ExprGenName.translate_name_value 对"结构体值局部变量"的右值**恒返回 alloca 地址**
(原实现,注释解释为"对象即指针"语义,避免 ptrtoint %Struct 非法指令);而 _MakeAddr
的返回类型经 resolve_annotation_type 解析为**结构体值**。translate_return 会把函数返回
类型作为 target_ty 下传给 translate_value(StmtGenCifMixin.vp:557-558),于是 `addr`
求值出 %SocketAddr* → coerce_to_type 的"指针 → 非基本类型值"分支
(ExprGenBase.vp:954-970)只对"构造物化"豁免 → 报错。
标量局部变量无此问题(同函数内非 Struct 分支会 build_load 出值),属结构体值局部变量
独有的表示差异。
改动:ExprGenName.translate_name_value 的 Struct 分支增加 target_ty 判据——使用处
**明确要求同一非基本类型(非指针)**时(_same_agg_ty 判据:与"构造物化豁免"同一类型
匹配真源 AssignGen._stg_ty_equal),像标量一样 build_load 出值;否则维持既有"返回地址"。
- target_ty 为指针时不命中(裸类形参 lowering 为 Ptr(struct),见 FuncGenDef)⇒
Test/StructTest 的 point_sum(p) 这类实参传址行为不变。
- 字段访问基座(ExprGenAttr.vp:743-744,直接 lookup_var 取地址)、c.Addr 取址
(CallGenCBuiltin.vp:293)、方法接收者均不经本函数取地址,不受影响。
- 同时修正该处已失真的注释(原文举例 `x: Cls | t.CPtr` 实际解析为 Ptr(struct),
并非 Struct 值局部变量)。
待验证:重编译 TransPyV(自举两遍)→ WebTest / StructTest / ClassArrayTest / JsonTest。
|
2026-10-01 14:26:18 +08:00 |
|
TermiNexus
|
25c1c9875b
|
fix(TPV/VpiReader): 阻断 vpi 自注入(循环 import)+ __init__ 声明端与定义端同取 void
现场:Test/JsonTest 编译 includes/json/__parser.vp 后 llc 报
06cb4f5b8fd08841.ll:259:7: error: value doesn't match function result type 'i32'
ret void
(该函数是 define i32 @"06cb4f5b8fd08841.ParseState.__init__",函数体末尾却是 ret void)
根因两层,都在 vpi 注入侧:
1) 自注入:__parser.vp 与 json/__init__.vp 循环 import(__parser 顶部
`from . import (JsonValue, ...)`,__init__.vp 底部 `from .__parser import parse`)。
__parser 编译时,其**自身** vpi(06cb4f5b8fd08841.vpi 里有
`class ParseState: def __init__(self, src: str, pool: rawptr[...]): pass`)经依赖链
(deps: t c stdint memhub string json → json 的依赖含 json.__parser)被反向注入
⇒ 模块 IR 里先出现 `declare i32 @"06cb....ParseState.__init__"`(IsDeclared=1)。
该方法随后走 _translate_method 的"复用前向声明"路径,函数体按**定义端**语义发射
(__init__ → 末尾 ret void),而函数对象自身的 RetTy 仍是注入时的 i32。
2) 类型口径分裂:VpiReader._inject_method_declare 对"方法无返回注解"一律退 i32 默认,
而定义端 ClassGenVTable._translate_method 对 __init__ 恒 Void ⇒ declare i32 /
define void。此前只在跨模块出现(不同 .obj,链接器不校验类型,静默 ABI 不一致);
自注入把两者塞进同一个模块,才被 llc 拦下。
改动:
- VpiReader._inject_method_declare / _inject_function_declare:新增自注入守卫——
仅全量翻译阶段(trans._declare_only == 0)且 src_sha1 == trans.ModuleSha1 时直接返回。
本模块自己的 define 由 ClassGenVTable._translate_oop_methods / FuncGenDef 负责发射,
不需要也不允许经依赖 vpi 反向注入(注入侧类型可能与定义端不一致)。
- VpiReader._inject_method_declare:__init__ 无返回注解 → Void(与定义端一致),
消除 declare/define 返回类型分裂。__init__ 的返回值在三处调用点
(CallGenCtor.vp:227 / :589 / :1275)均未被使用,改 void 不影响调用方。
待验证:重编译 TransPyV(自举两遍)→ JsonTest / FileIoTest。
|
2026-10-01 14:11:45 +08:00 |
|
TermiNexus
|
2bfcb6ef6e
|
fix(TPV): 修 455c760 遗漏——args_node 必须声明在 decl_reuse 分支之外
现场:Test/FakeDuckTest 编译 includes/viperio.vp 第 12 行
self.data = data → NameError: 未定义名称 'data'
(Buf.__init__ 的第一个形参名在方法体里找不到。)
原因:455c760 把整段"参数创建块"置于 if decl_reuse == 0: 之下时,把
args_node: ast.Arguments* = fd.args 一并圈了进去;但函数体段的
"为其他参数创建 alloca 并 store"(ClassGenVTable.vp:904 起)仍要遍历
args_node。复用前向声明(decl_reuse==1,现已是常规路径)时 args_node
未定义 → 形参不进符号表 → 方法体引用形参名即报 NameError。
修法:把 args_node 的声明提到 decl_reuse 分支之前。该块内其余变量
(md_defaults/md_default_count/md_param_count/md_args_node/md_ags/
md_alist/md_dlist/max_funcs/first_pname/first_pname_buf/fd_ags/
fd_first_arg/ags/alist/an/start_idx/ai/arg/param_ty/resolved/pname/
i1_ty_si/i1_ptr_ty_si)已逐一核对,全部只在块内使用,无需外提。
待验证:重编译 TransPyV(自举两遍)→ FileIoTest / FakeDuckTest。
|
2026-10-01 13:57:04 +08:00 |
|
TermiNexus
|
455c7608b1
|
fix(TPV): 方法先声明后定义(消除方法查找的源顺序依赖),删除兄弟 Mixin 兜底
现场:Test/FileIoTest 编译 includes/w32/fileio.vp 报
CastError: 源 %"b0721da228be3d55.FileW"* → 目标 %"b0721da228be3d55.File"*
(指针隐式转指针已禁止:被指类型是非基本类型)
根因(有旧 IR 佐证,非本轮改动引起):FileW.__init__(源 304 行)里的
self.seek(0, SEEK_END) 被解析成 File.seek,而不是 FileW.seek:
1) _translate_method 只在方法体翻译时才 create_function,于是方法查找
(find_func_in_module)依赖方法在类体内的书写顺序:FileW.seek 在源 403 行,
晚于 __init__ → 查不到 → None;
2) MRO 无父类 → None;
3) 兄弟 Mixin 兜底随即遍历全部已注册 struct,取"本模块存在同名方法"的
第一个候选类 → 命中 File → 绑成 File.seek,self 再被 this-adjust
bitcast 成 File*。
旧 IR(TransPyV\.tpv_build\temp\b0\b0721da228be3d55.text.ll,mtime 9/27,
早于本轮全部改动)里就是:
%97 = bitcast %"...FileW"* %96 to %"...File"*
%98 = call i32 @"...File.seek"(%"...File"* %97, i32 0, i32 2)
即靠一层隐式跨类 bitcast 静默通过;指针规则收紧后以 CastError 报出。
(File.__init__ 的 self.seek 同样查不到,只是兜底恰好扫到 File.seek 而"碰巧正确"。)
改动:
1. ClassGenVTable._translate_oop_methods:翻译方法体之前,先对本类**全部方法**
跑一遍 sig_only=1 建前向声明(declare + 参数 + 函数表登记)——与
FuncGenDef.forward_declare_functions 对模块级函数做的事完全同构,
使方法查找不再依赖类体内的书写顺序。
2. ClassGenVTable._translate_method 新增 sig_only 形参:
· 签名部分改用 create_declare(IsDeclared=1),已存在同名前向声明则复用;
· 发射函数体前把 IsDeclared 清零转 define(对齐 FuncGenDef.vp:544-545),
否则打印端按 IsDeclared 输出 declare、函数体整体丢失;
· 复用声明时跳过重复的 add_param 与 add_func_to_table;
· 命中同名函数且 IsDeclared==0(函数体已发射)时直接返回,杜绝重复发射
(llvmlite.create_function 不做同名去重,旧写法会造 duplicate symbol)。
3. CallGenCall._translate_method_call:按"不兜底、fail-fast"决定,整块删除
兄弟 Mixin 兜底(遍历 struct 表猜候选类)及其死分支
(mixin_hit / mixin_ret_ty / mixin_anc_name / mixin_anc_sha1 的声明与消费点)。
方法未命中即为真未定义,交下方 text.ll / vpi / 本模块豁免路径
(CallGenCall.vp:962 起的 is_local_mod 分支,从已声明的本模块函数直接取
返回类型)处理,不再猜候选类。
4. 同步修正 ClassGenVTable 顶部 _translate_method 的注释块与函数文档串。
TPC 侧无需同步:TPC 的声明阶段把类成员全部登记进 SymbolTable,本就不存在
"方法查找依赖源顺序",也没有这段兄弟 Mixin 扫描(HandlesExprCall.py:3877-3914
的兜底带"调用类自身未声明该方法"守卫,与本次删除的 TPV 版不同)。
待验证(不自行执行编译命令):重编译 TransPyV(自举需编两遍),再跑
FileIoTest / NoVTableCrossMixinTest / DictTest / 泛型相关测试。
|
2026-10-01 13:45:10 +08:00 |
|
TermiNexus
|
875a9beb08
|
refactor(TypeGenResolve): 裸类名恒为原型(struct 本身),删除 5 处 HasNew 自动升指针
口径(用户 2026-10-01 定):**裸类名注解 = 原型(struct 本身,类型/布局语义)**,
堆对象引用必须显式写 `T*` / `T | t.CPtr` / `rawptr[T]`。旧行为"有 __new__ 的类
(堆对象)裸名 ⇒ Ptr(struct)"是为兼容 `d: dict = dict(bd)` 这类"裸名 + 构造"写法
而设,代价是同一类型两种写法分裂:
includes/json/__init__.vp:79 `def __getitem__(...) -> 'JsonValue' | t.CPtr`
左边(引号字符串注解)先被解析成 Ptr(struct),联合分支再包一层 ⇒ JsonValue**
而 `cur: JsonValue*` 是 JsonValue* ⇒ :90 `return cur` 报
「指针层数不同(源 1 级 → 目标 2 级)」(660427f 已在联合分支做过吸收,
本次从源头统一:裸名不再自动升指针,吸收那条规则对裸名侧自然不再触发)。
改动(resolve_annotation_type 的裸名/限定名分支,共 5 处,全部去掉 HasNew 分支):
1. `{16hex}.Class` 已归一前缀名分支(原 :2768-2770)
2. 本模块自有类分支(原 :2806-2814,删掉那段"有 __new__ ⇒ Ptr"的注释与分支)
3. from-import 归属分支(原 :2832-2834)
4. 可见结构体裸名分支(原 :2842-2844)
5. `mod.Class` 限定名分支(原 :3040-3044)
影响面盘点(静态扫描 474 个 .vp):本文件内"裸堆类名注解"16 处、跨文件候选 63 处
(含同名跨模块误报),典型:
includes/hashtable.vp:45 ht: HashTable = HashTable(mb)
includes/_dict.vp:29 d: dict = dict(mb)
Test/BuiltinDecoratorTest/App/main.vp:33/36/68/98/137/180/184/194/199/234/241/248
TransPyV/Test/App/new_test.vp:81/93/105
Test/{ClassArrayTest,StructTest,ClosureTest2,StringIterTest}/App/*.vp 若干
这些站点需按新口径显式补 `*`(或改用 `T | t.CPtr`);真实集合以编译器 fail-fast
报错为准(同名跨模块无法静态判定归属)。
TPC 侧核查结论:**无需改动,TPC 本就同口径**。证据:
1. 全仓 `HasNew|has_new` 仅 8 处,全在**构造路径**——HandlesAnnAssign.py:401
(`list[T] = [...]` 字面量构造)、HandlesExprCall.py:5105/5161/5170/5198/5235/5263
(`ClassName(...)` 构造,`_HandleClassNewLlvm`);**注解解析链上一处都没有**。
2. 规范注解解析 `TypeAnnotationResolver._from_node_name`(裸 Name)、
`_from_node_attribute`(mod.Class)、`_from_node_constant`('X' 引号注解)
全程不查 __new__,裸类名一律 PtrCount=0(原型)。
3. 局部变量路径 HandlesAnnAssign.py:678-683 显式把裸类名 PtrCount 由 1 改回 0
("纯结构体名注解应为值类型"),仅保留 vtable 类为指针;模块级全局
HandlesAssign.py:1840-1856 亦按 struct 值类型建 GlobalVariable。
4. 符号表类条目 PtrCount 默认 0(SymbolTable._InsertClassSymbol:489-518 从不设
PtrCount;TypeSpec.py:139 默认 0)。
因此 `d: dict = dict(mb)`(dict 有 __new__、非 vtable 类)在 TPC 侧本来就是
struct 值语义,与本次 TPV 改动后的口径一致。json/__init__.vp 的
`'JsonValue' | t.CPtr`(定义端 0+1 层、声明端裸类引用吸收 1 层)两侧都已是
`%"…JsonValue"*`(1 层),本次 TPV 改动后亦对齐。
待验证(不自行执行编译命令):先重编译 TransPyV,再跑
JsonTest / DictTest / StructTest / BuiltinDecoratorTest / ClassArrayTest
预期先出现一批"注解需补 `*`"的报错——那正是本次口径变更要求的显式化。
|
2026-10-01 12:38:24 +08:00 |
|
TermiNexus
|
660427f759
|
fix(TypeGenResolve): X | t.CPtr 的 struct 引用语义吸收这层指针,修 json __getitem__ 报 JsonValue** vs JsonValue* 层数不同
现象(TransPyV 编译 includes/json/__init__.vp):
line 90 return cur
CastError: 指针隐式转指针已禁止:指针层数不同(源 1 级 → 目标 2 级)
源 %"e966d554e91364bc.JsonValue"* → 目标 %"e966d554e91364bc.JsonValue"**
根因链(逐环取证):
1. includes/json/__init__.vp:79
def __getitem__(self, key: str) -> 'JsonValue' | t.CPtr:
注意左边是**引号字符串注解**(Constant),不是裸 Name。
2. JsonValue 是带 __new__ 的**堆类**(该文件 :34),按引用语义,裸类名注解在
resolve_annotation_type 的 Name/Attribute 分支直接给 Ptr(struct)
(:2806-2813 注释「有 __new__ 的类(堆对象)注解 → Ptr(struct)(引用语义,对齐 TPC)」,
Attribute/sha1 前缀/from-import 各分支同口径)。
3. 于是 BinOp(`| t.CPtr`) 分支里 other_ty 已经是 Ptr(JsonValue);而 :3176 那段
「Name 且未注册 struct 才丢弃」的守卫只认 Name —— Constant 绕过了它,
带着 Ptr(struct) 走到 :3264 `return llvmlite.Ptr(pool, other_ty)` 再包一层
⇒ JsonValue**。
4. 裸名写法(不带引号)不会暴露:它会在 :3222-3239 被判 td_res_is_ptr=1 →
other_ty 置 None → 走 :3254 回退取 struct 再包一层,恰好抵消。
⇒ 同一类型两种写法产出两个层数(`JsonValue*` vs `JsonValue**`),与用户
2026-09-30 定的统一口径冲突:T* ≡ rawptr[T] ≡ t.CPtr[T] ≡ T | t.CPtr。
改动(TypeGenResolve.resolve_annotation_type 的 BinOp(|t.CPtr) 分支):
- 在 :3264 包装前落实本文件 :3219-3221 注释里早已写明、但此前**未实现**的那条
规则:「| t.CPtr 恒为追加 1 层,唯一例外是 struct 引用语义时吸收这 1 层
(判据 = Ptr 的 pointee 是已注册 struct,find_struct_by_type 命中即吸收)」。
- 即:other_ty 已是 Ptr(已注册 struct) 时直接返回 other_ty,不再加一层。
- 副作用(同步修正同族写法):引号字符串写法、以及 Attribute 分支在
find_struct_by_module 命中 HasNew 时返回 Ptr(struct) 的那条路径
(:3040-3044),都从「多一层」收敛为 T*。
- 不影响的既有例外:VOIDPTR/CVoid|CPtr 等「指针别名」侧解析出的是 Ptr(i8)
(i8 非 struct,命中不到 find_struct_by_type)⇒ `VOIDPTR | t.CPtr` 仍是
i8**(追加一层),与 VpiReader 侧口径一致。
仅 TPV 侧(TPC 侧走 SymbolUtils.AddPointerLayers 的另一套口径,本次不动)。
待验证(不自行执行编译命令):先重编译 TransPyV,再跑
TransPyV.exe --project ./Test/JsonTest/project.json --clean --clear-cache --rebuild-includes --traceback
预期 :90 不再报层数不同;若还有同族报错请把栈贴回。
|
2026-10-01 00:51:51 +08:00 |
|