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 |
|
TermiNexus
|
3329c9beae
|
fix(TPV/CallGenBase): text.ll 返回类型的命名指针不再坍缩成通用 i8*,修 FakeDuck parts[0] 报整数隐式转指针
现象(TransPyV 编译 Test/FakeDuckTest):
main.vp:115 p0: str = parts[0]
CastError: 整数隐式转指针已禁止…出错表达式: 下标表达式 Subscript
(parts = s1.split(','),s1: str,split 由 includes/_fakeduck.vp 的 _str 提供)
根因链(逐环取证,均落在产物文件上):
1. _fakeduck.vp:273 `def split(self, delimiter: str) -> list[str]*`。
2. 定义侧产物正确:temp/88/884eaabef9bd161c.text.ll:1775
define %"b0798adca340002b.list[str]"* @"884eaabef9bd161c._str.split"(...)
(884eaabef9bd161c = includes/_fakeduck.vp,b0798adca340002b = includes/_list.vp)
3. 调用侧 declare 走了 vpi 注解:temp/88/884eaabef9bd161c.vpi:27
def split(self, delimiter: str) -> list[str] | t.CPtr: pass
该联合在 stub 侧解析不出 `list[str]` 这个泛型特化名 ⇒ 坍缩成 i8*(既有设计已知的
「跨模块 declare 的 list[T] 返回类型被简化」),故 _translate_fakeduck_call 里那条
「从定义模块 text.ll 读精确返回类型」的兜底(CallGenFd.vp:134-142)必须生效。
4. 但该兜底读到的 `%"b0798adca340002b.list[str]"*` 又被本函数坍缩回 i8*:
CallGenBase._ParseLLVMRetTyStr 的「含 * 者一律返回通用 Ptr(Int8)」分支
(原注释:"包括 i8*, i32*, %"name"*, { i32, i8 }* 等")。
5. 于是 parts 的 alloca 退化为 i8* ⇒ parts[0] 走字节下标取到整数 ⇒ 赋给 str 报
「整数隐式转指针已禁止」(报文指不到真因,正是本问题最难查的地方)。
改动(CallGenBase._ParseLLVMRetTyStr):
- 新增「命名类型 `%"name"*` / `%name*`」分支:剥引号/空格与尾随 `*`(支持多级),
先 GenApi.get_struct_type(name)、未命中再 GenApi.get_enum_base_type(name),命中即
按星号层数包 Ptr 返回真实结构体/枚举指针;查不到登记项时才保持原来的通用 Ptr(Int8)
行为(名字可能来自尚未登记的模块,不引入新的静默降级面)。
- 同步更新该函数顶部说明(原写「含 * 者返回通用 Ptr(Int8)」,现区分字面量结构体 /
命名类型 / 其余)。
- 收益面不限 FakeDuck:所有经 text.ll 取返回类型的方法调用(CallGenCall / CallGenDispatch
/ CallGenProp / CallGenFd 等)都从「指针一律 i8*」变为「命名类指针精确」,
调用方 alloca 与下标/字段语义不再退化。
待验证(不自行执行编译命令):用 TransPyV.exe 重跑
--project ./Test/FakeDuckTest/project.json --clean --clear-cache --rebuild-includes --traceback
预期 115 行不再报错;若仍在 parts2.get(0)(131 行)等处冒新错,请把栈贴回来。
|
2026-09-30 23:53:18 +08:00 |
|
TermiNexus
|
f2f3e5b7bf
|
fix(TypeGenResolve): 裸名内建类型统一为 t.X/c.X,消 CPtr 与 t.CPtr 的分裂与误报 ERROR
内建伪模块 t/c 没有模块 SHA1(规则 5 的模块名→sha1 表查不到),于是 from t import CPtr 之后的裸名 CPtr 被原样保留,而规则 3 保留的是 t.CPtr ⇒ 同一类型两种票名(list[CPtr] 与 list[t.CPtr] 分裂),并额外刷 ERROR [类型实参归属] 裸类名 CPtr 保留裸名(现场 Test/NewAstTest/App/main.vp,log 里 from_imports 明写 CPtr:t)。新增规则 5.2:from_imports 命中模块 t/c 且 map_t_type 认该名 ⇒ 返回 t.X/c.X(规则 3 已定的规范形)。只对"本名就是 t/c 已知内建类型名"生效,别名写法不猜真实符号名、维持原样。
|
2026-09-30 22:59:01 +08:00 |
|
TermiNexus
|
79f044bc47
|
fix(TypeGenResolve): _class_true_def_sha1 只取 hex 段,修双点前缀 d1ed…461..AST*
GenApi.sha1_prefix_len 返回含末尾 "." 的 17(其文档写明),前一版按 17 拷贝 hex 段后再交 _concat_sha1_class 拼 ".",得到双点前缀 %"….d1ed020479454541..AST*" ⇒ parser.vp:3355 return scratch.children 处 coerce 报 CastError。改为按 17 判形、比对与拷贝都用 16(hex 段本身)。
|
2026-09-30 22:45:26 +08:00 |
|
TermiNexus
|
7b0c05b70b
|
fix(TypeGenResolve): 类名前缀校正为真定义模块,消 ast.AST(包) 与裸 AST 的前缀分裂
规则 4b 对 ast.AST(模块限定属名)走"模块名→SHA1"表,对包名回退到 ast/__init__.vp 的 sha1 1abcd5277fa442de(re-export 模块),而裸名 AST(stmts.vp 字段注解)经规则 5 后缀匹配得到真定义模块 d1ed020479454541(ast/base.vp)⇒ list[1abcd….AST*] 与 list[d1ed….AST*] 两个特化体并存,main.vp:63 classify_list(ifn.orelse,…) 报"指针隐式转指针已禁止"。新增 _class_true_def_sha1:在 cand 名下精确找登记项(find_struct_by_module,不按名回落,避免同名类跨模块误改),取其结构体 IR 名 %"<sha>.{类名}" 的前缀作真定义模块(不能取 entry.ModuleSha1——包 re-export 的别名 entry 记的是包 sha1、Ty 复用源 entry);无证据或前缀相同则原样返回 cand(已一致情形逐字不变)。接线:规则 4a/4b/5 各一行。
|
2026-09-30 22:16:15 +08:00 |
|
TermiNexus
|
0f6e102e02
|
fix(TypeGenResolve): rawptr[T] 下标形漏折叠致两个 list 特化体(修 _list.vp:83 return self 的 CastError)
前一版把 rawptr 从 _is_ptr_marker_text 移除(避免裸 rawptr 参与联合时名说 T*、类型说 T),但下标容器分支复用了同一判据 ⇒ rawptr[T] 完全没折叠,只有 T|t.CPtr 折叠:现场同时存在 list[<sha>.AST*] 与 list[rawptr[<sha>.AST]] 两个结构体,_list.vp:83 return self 的 self(前者)被 coerce 到返回注解(后者)时报 CastError。新增专用判据 _is_ptr_subscript_container_text(rawptr/t.rawptr/c.rawptr/CPtr 一族),下标分支改用它;联合分支仍用 _is_ptr_marker_text 保持与类型域 _is_cptr_marker 同口径。
|
2026-09-30 21:39:21 +08:00 |
|
TermiNexus
|
b289e93650
|
fix(泛型实参 T* 形): 补齐 T* 消费侧(VpiReader 段解析 / AnnotClassName 提取 / 构造推断)
唯一规范形 T*(rawptr[T] ≡ t.CPtr[T] ≡ T|t.CPtr,见 83baf5a/2b2b70e)落地后,
所有"读**已归一实参文本**或**结构体名**并做文本解析/嗅探"的点都必须接受 T* 形,
否则会**静默**走错分支(不是报错,更难发现):
- VpiReader._resolve_single_vpi_type_str:尾随 * 段按层重写回 rawptr[...] 文本形
再走原分支(与既有 rawptr[ 分支逐字等价)。必须补的原因:_subst_template_arg
用特化类名 [...] 内的**已归一实参**替换模板注解里的 T,喂进来的就是 {sha}.AST*;
旧代码只认 rawptr[ / t.CPtr[ / 裸 t.CPtr ⇒ 落到 strrchr('.') 取末段 "AST*"、
查 struct miss ⇒ 返回 None/i8*,跨模块参数/返回宽度被悄悄收窄。
- ExprGenCls / AssignGenMixin 的 _extract_annot_class_name(各 2 处):段尾剔除集
补 '*',剥后再 find_struct(旧形态 {sha}.AST|t.CPtr 按 '|' 分段能命中,新形态
不剥则 miss ⇒ 返回 None ⇒ 链式 .get(0).kind() 分派退化)。
- CallGenCtor._infer_generic_ctor_type_arg:新增 _ptr_layer_type_arg —— 先经
_norm_type_arg_name 归一(保证类名带定义模块 SHA1,否则裸 "AST*" 无法再归一、
反而新分裂),再按 VarEntry/FieldEntry 的 Spec.PtrLevel 补 '*',使构造侧推出的
类型实参与注解侧同票名(否则 Box(x) 这类隐式特化分裂成两个结构体)。
- CallGenDispatch.__sizeof__:'*' 判据由 strrchr 改为**尾随**判定 —— 原写法会把
list[{sha}.AST*](元素为指针的容器)误判成指针并返回 8。
现场:Test/AstTest/App/main.vp:21 的 list[ast.AST | t.CPtr] | t.CPtr 特化链
(→ includes/_list.vp:36 T.__sizeof__())。
|
2026-09-30 21:16:48 +08:00 |
|
TermiNexus
|
2b2b70e636
|
fix(CallGenDispatch): __sizeof__ 认归一后的指针规范形 T*(尾随 * 一律按 8)
泛型实参归一为 T* 后,T.__sizeof__() 的实参串如 {sha}.AST* 既不命中 | 也不命中 rawptr[ 前缀,落回把接收者 Name(T) 当实例翻译 → NameError: 未定义名称 T(现场 Test/AstTest/App/main.vp:21 特化 list[ast.AST|t.CPtr] → includes/_list.vp:36)。在既有两条指针判据旁补尾随 * 判据(同一处、同一顺序,均在 dot-strip 之前)。
|
2026-09-30 20:58:02 +08:00 |
|
TermiNexus
|
83baf5a4b6
|
fix(TypeGenResolve/ExprGenName): 指针类型实参统一为 T*,消泛型特化名分裂(假报错 CastError)
用户定口径:t.CPtr[T] / rawptr[T] / T|t.CPtr ≡ T*(与 TPC 侧
SymbolUtils.ResolveTypeArgStr+AddPointerLayers 逐字同形,两侧必须同票名)。
- _norm_type_arg_name:联合一侧为裸 CPtr 标记 ⇒ 折成 <另一侧>*;单实参的
指针标记容器 rawptr[T]/t.CPtr[T] ⇒ 折成 <实参>*(新增 _is_ptr_marker_text /
_ptr_star_text;刻意只认 CPtr 一族,与类型域 _is_cptr_marker 同判据,
避免名字说 T*、类型说 T 的不一致)
- _parse_type_string:能反解析尾随 '*'(按层包回 rawptr[...],供 ClassGenGeneric
克隆注解时替换实参文本)
- ExprGenName._list_elem_obj_ty_from_struct_name:元素段剥尾随 '*' 后再查结构体
(否则对象元素还原失败、静默退回 Ptr(i8) 丢元素类名)
现场:Test/AstTest/App/main.vp:63 classify_list(ifn.orelse, ...) 源
list[rawptr[<sha>.AST]] vs 目标 list[<sha>.AST|t.CPtr] ⇒ 严格指针规则按
「不同非基本类型」拒绝(假报错);改后同票名 ⇒ 同一结构体。
注意:特化名进结构体名与方法符号名 ⇒ 必须全量重编 includes
(--clean --rebuild-includes --clear-cache)。
|
2026-09-30 20:19:42 +08:00 |
|
TermiNexus
|
f3c708613f
|
refactor(TransPyV): 统一自举写法(字段默认值/novirtual/define/enum/指针注解)
- CallGenBase:字段声明处直接给默认值,InitCallGen 不再逐字段赋值
- CallGenFd/CallGenDispatch:@t.NoVTable 改 novirtual,清理过时注释
- VLogger:LogLevel 改 enum、t.CDefine 改 define 关键字、Logger|t.CPtr 改 Logger*、longjmp 用 rawptr
- Generator:_g_gen 由 Generator|t.CPtr 改为 Generator*
- CallGenProp:合并续行
|
2026-09-30 19:09:22 +08:00 |
|
TermiNexus
|
849001ae9e
|
fix(AssignGen): 禁止注解声明类型被右值继承上转窄化
TPV 侧「注解退化修复」只挡了裸泛型基类降级,漏挡「注解写明基类、右值是派生类」的上转窄化:node: rawptr[AST] = Name(...) 会把 alloca 重建成 Ptr(Name),随后 node = <返回 rawptr[AST]> 变成被禁止的父→子下转(includes/ast/parser.vp:1919 报 指针隐式转指针已禁止:%AST* → %Name*)。补上与 TPC HandlesAnnAssign._rb_is_upcast 同判据的守卫(复用 ExprGenBase._is_inheritance_upcast)。
|
2026-09-30 19:08:58 +08:00 |
|
TermiNexus
|
a92b38e826
|
fix(Translator): 文件级类名预登记覆盖三种 _declare_only 模式(修 Phase 1a 的类型实参裸名分裂)
类别:a(编译器缺陷)
现象:编译 includes/ast/base.vp 报
ERROR [TypeGen]: [类型实参归属] 裸类名 'AST' 本次保留裸名(可能与带前缀形式分裂):
entry_present=0 entry.Ty=None cur_def_mod=d1ed020479454541 cur_def_cls=ASTFlag
is_module_class=0 find_struct_by_module=0 from_imports=*:stdint TokOp:ast.tokens
file=./includes/ast/base.vp
根因链(逐条对应报文):
报文来自 TypeGenResolve._norm_type_arg_name 规则 5.5:五类证据全落空即返回裸名。
- ④ entry_present=0 / ① find_struct_by_module=0:'AST' 尚未 register_struct
(AST 在 base.vp:313;本次归一化发生在更早的模块级函数签名处)。
- ② is_module_class=0:'AST' 的 mark_module_class 尚未执行(类定义入口按 AST 顺序走)。
- ③ cur_def_cls=ASTFlag:CurDefClassName 停在更早的 enum ASTFlag(类结束后不复位),
与裸名 'AST' 逐字不同 ⇒ ③ 不适用(该值同时证明本次不是"泛型特化平移窗口")。
- ⑤ is_file_class + get_file_module_sha1 本应兜住"本文件自己声明的类名",但
register_file_classes 的调用被 `if self._declare_only == 0:` 整块门住;而本次是
Phase 1a(_declare_only == 1)——TranslatorGenMixin 在 1a 会调用
_prescan_funcdef_signatures **预解析模块级函数签名**(含注解归一化)⇒ 证据⑤ 恒落空。
⇒ 该实参特化名被冻结成**裸名**版本,与 1b 全量翻译期解析出的带 SHA1 形式分裂成两个
特化结构体名,后续以"非基本类型指针不可隐式转换"报出(同类旧现场 base.vp:359)。
修复:把 GenApi.register_file_classes(pool, self.ModuleSha1, tree) 从 `_declare_only == 0`
块内提到 _translate_module_level 开头,三种模式(1a=1 / 1a-pre=2 / 全量=0)共用。
该登记只依赖 tree + 本文件模块 SHA1,与导入、类定义窗口、类定义顺序都无关;
reset_visible_structs 在每个模式的 translate 之前调用(BuildPipeline:226 /
Phase1Main:643),FileClassNames 与键同池创建,无悬空风险。未放宽任何 fail-fast。
|
2026-09-30 17:43:15 +08:00 |
|
TermiNexus
|
1cce6c4a47
|
fix(TypeGenResolve): 「保留裸名」误报的第二入口——逐实参归一时跳过定长数组的元素个数位 + CDefine 名不再算类名
类别:a(编译器缺陷)。`ef4421d` 只补了 `_norm_type_arg_name` 规则 1.5 的"跳过第 2 实参",
但那条规则**拿不到容器上下文**的入口不止一个,实测 still 报:
├ ERROR [TypeGen] [类型实参归属] 裸类名 'TRACEBACK_FRAME_BUF' 本次保留裸名 …
entry_present=0 entry.Ty=None cur_def_mod=ba7cdbd0dec2aef8 cur_def_cls=TracebackState
… file=./includes/traceback.vp
两处修(互为补充,判据都指向同一条事实:定长数组的第 2 实参是**常量**,不是类名):
1) `extract_class_name_from_annotation` 的 **Tuple 分支**(:2156/:2167,本函数自己按
`,` 把实参拆开逐个归一,规则 1.5 在这里根本不生效):
`TracebackState.FrameAddr: t.CArray[uint64, TRACEBACK_FRAME_BUF]`
⇒ 先按 `_is_count_arg_container(base_name)` 判容器是 t.CArray/list,是则第 2 实参
(`ti_sn == 1`)**原样保留、不调用归一**(长度计算与拼接两个循环同步改)。
2) `_is_non_class_type_name` 增 **⑤ CDefine 名**:`NAME: t.CDefine = 128` 是编译期常量,
名域就是它自身,永远不是类名 ⇒ 命中 `TypeGenCDef.lookup_cdefine_constant` +
`is_cdefine_found()`(-1 也是合法值,必须看标志)即豁免"保留裸名"取证。
这条判据落在**所有入口共用**的函数上,彻底覆盖其余"逐实参归一"的点
(如 CallGenCtor:768 的泛型实参提取)。
静态核验:同形语句片(`self.Gen.TypeGenCDef.lookup_cdefine_constant(...)` 丢弃返回值、
`elt_name: str = raw` 后条件重赋值、`range`/`len` 循环)过 `lib.vast` 解析。
生效需重新自举 TransPyV.exe。
|
2026-09-30 16:05:29 +08:00 |
|
TermiNexus
|
2a798dd643
|
fix(类型转换): int→i1 目标改为真值归一化 != 0,不再 trunc 取最低位
类别:a(编译器缺陷)。`b: bool = f()`(f 运行时返回偶数非零,如 2)此前经
coerce_to_type 的窄化分支走 trunc ⇒ 最低位 0 ⇒ false,而同一值在 `if 2:` /
`bool(2)`(icmp ne 0)为真 —— 两处判据相反(静默语义分裂)。
- ExprGenBase.coerce_to_type:整数窄化分支前先判目标位宽 == 1 ⇒ `icmp ne x, 0`
(C 6.3.1.2 的 _Bool 转换语义)。归一化不丢位,故对 i1 目标不再适用下方
「窄化截断溢出」常量诊断(先返回)——`b: bool = 2` 由编译期 OverflowError
变为正确的 true。
- CallGenCtor._translate_t_type_cast:显式 `t.CBool(x)` 与隐式落存储同一判据。
判据与 bool(x)(CallGenDispatch.vp:255-281)、条件归一化(AsyncGenMixin.vp:1611
_normalize_cond)、and/or 操作数三处统一。App/ 与 includes/ 全量检索未见
`: bool = …(& | >> | // | |)` 位提取写法,既有代码无依赖 trunc 取最低位的点。
生效需重新自举 TransPyV.exe(并清缓存)。
|
2026-09-30 15:14:32 +08:00 |
|
TermiNexus
|
ef4421db20
|
fix(TypeGenResolve): 定长数组容器的「元素个数」实参不参与类名归属归一(消「保留裸名」误报)
【b 机制漏豁免】`_norm_type_arg_name` 规则 1.5 把 `Name[...]` 的**每个**顶层实参都递归
归一(目的是把类名统一成 `{定义模块SHA1}.类`)。但定长数组容器 `t.CArray[T, N]` /
`list[T, N]` 的**第 2 实参是元素个数**(编译期整数:CDefine 名 / 字面量 / 常量表达式,
依据是 TPC 侧 t.CArray 的定义原文"第一个参数为元素类型,第二个参数为数组大小(整数或
常量名)",lib/includes/t.py),对它做类名归属归一既无意义,又会落进规则 5.5 的
"保留裸名"取证 ⇒ 误报"类名归属缺失"。
现场:编译 includes/traceback.vp 时 TracebackState 的字段注解
`t.CArray[uint64, TRACEBACK_FRAME_BUF]`(traceback.vp:532),第 2 实参
'TRACEBACK_FRAME_BUF' 是 traceback.vp:482 的 `TRACEBACK_FRAME_BUF: t.CDefine = 128`
⇒ 每次编译刷
"[类型实参归属] 裸类名 'TRACEBACK_FRAME_BUF' 本次保留裸名…"ERROR。
修法:新增 `_is_count_arg_container(container)`(按**容器短名**判定,兼容 `tt.CArray`
这类别名;只认 CArray / list,泛型类 GSList[T]/Box[T] 的实参全是类型名不受影响),
规则 1.5 的实参拆分循环按序号跳过第 2 实参 —— 原样保留、不递归。
归一结果逐字不变:常量名与字面量既非类名也非 CTypedef,归一恒返回原串;TPC 侧
`ResolveTypeArgStr` 对同位置同样原样保留(Name→NormalizeGenericArgName / Constant→
unparse),两侧仍一致。改变的只是不再触发该取证日志。
配套:上一提交 d63787f 的 `_is_non_class_type_name` 覆盖同注解的**第 1 实参**
(`uint64` = builtins.vp 的 typedef)——两条判据互补:类型位放行非类名,个数位不归一。
未验证:需重新自举 TransPyV.exe 才生效。vast 解析通过。
|
2026-09-30 14:05:03 +08:00 |
|
TermiNexus
|
d63787f8fc
|
fix(TypeGenResolve): 「保留裸名」取证对 CTypedef/内置标量/泛型形参不再报 ERROR
【b 机制漏豁免】取证日志(df1244d 加入)的前提是"这是个**类名**":只有类名存在
"{定义模块SHA1}.类" 这第二个 mangling 形式,留裸名才可能与它分裂。CTypedef /
语言内置标量 / 泛型形参的名域就是它自身,保留裸名即规范形式(TPC 侧
SymbolUtils.NormalizeGenericArgName 同口径),对它报 ERROR 是纯噪声。
现场:编译 includes/traceback.vp 时,TracebackState.FrameAddr 的注解
`t.CArray[uint64, TRACEBACK_FRAME_BUF]`(traceback.vp:532)经规则 1.5 递归规范化
实参 'uint64' ⇒ 规则 5.5 取不到 SHA1 ⇒ 每次编译刷一条
"[类型实参归属] 裸类名 'uint64' 本次保留裸名…"。'uint64' 是 includes/builtins.vp 的
`typedef uint64 = t.CUInt64T`,不进类归属是预期行为,不是缺陷。
修法:新增 `_is_non_class_type_name(pool, name)`(正向白名单,不猜):
① CTypedef 动态表命中(Phase1 1b register_ctypedef_from_source 文本扫描注册);
② builtins 兜底 `_lookup_builtins_typedef`(与 resolve_typedef_or_map 同一口径:
builtins 始终在编译链内,但其 typedef 不随 from_imports 注入 ⇒ 表可能 miss;
命中即幂等注册进表);
③ 语言内置标量/字符串(int/char/bool/float/double/str/bytes/void,与
_resolve_annot_type_name 的跳过清单同口径);
④ 泛型形参名(单字母大写 T/U/V…,特化前出现在实参位属正常)。
门控只对「结构体表里根本没有该名」(_bare_entry is None)豁免:若它确是已注册的类
(.vpi 半条目)只是缺定义模块 SHA1,那是真正的归属缺口,照旧报出,不被同名 typedef 掩盖。
未验证:本改动需重新自举 TransPyV.exe 才生效(TPC 侧无对应逻辑)。vast 解析通过。
|
2026-09-30 13:51:22 +08:00 |
|
TermiNexus
|
0e5ebd07ba
|
fix(TypeGenCType): 撤销在子类类体重复声明父类字段(TypeGenBase 已声明),修指针隐式转整数误报
上一版(6a287b9)为修 Repl.vp:802 在 TypeGenCType 类体补了 5 个字段,但这 5 个
(CTypedefNames / CTypedefTypeStrs / CTypedefNameIdx / CTypedefNameIdxCap /
CTypedefNameIdxBuilt)**本就由父类 TypeGenBase 在类体声明**(TypeGenBase.vp:73-84),
属重复声明(c 源码违规)。
后果(有实证):这 5 个名字进入子类"自有字段"后,HandlesImports._FlattenExt 的
继承前缀前置过滤器(HandlesImports.py:2516-2521,为防重复前置而按名字过滤)
把**同名继承项整条丢弃** ⇒ class_members['TypeGenCType'] 变成 [36 继承项]+[5 自有项]。
被丢掉的 5 项(继承下标 22/23/25/26/27)都排在 LastBuiltinsTypedefResult
(继承下标 32)之前,使其表内下标降为 27;NoVTable 类 base=0 ⇒ 命中 body 槽 27
= CTypedefNameIdxBuilt(i32) ⇒ TypeGenResolve.vp 的
`self.Gen.TypeGenCType.LastBuiltinsTypedefResult = "t.CPtr"` 触发
"指针隐式转整数已禁止:不能把指针类型 i8* 赋给整数类型 i32"。
该重复声明还会让父类方法(TypeGenBase.vp InitTypeMixinFields 等)与子类方法
访问同一字段落到不同槽(split-brain)。
撤销后:子类自有字段=0,继承前缀 41 项按原顺序保留,LastBuiltinsTypedefResult
回到表内下标 32 = body 槽 32(i8*,与 TypeGenBase 声明的 str 一致)。
说明:Repl.vp:802 的真实根因(引用模块里继承前缀是否可达)尚未定论,本次只撤销
误修、不掩盖;该类属性链失败现已由 TPC 侧新增记账(a18ca4da)逐条给出失败原因链。
|
2026-09-30 10:46:43 +08:00 |
|
TermiNexus
|
6a287b955e
|
fix(TypeGenCType): 跨模块可见字段改为在类体声明(修 Repl.vp:802 属性链求值为空)
类别:c 源码违规(跨模块读得到的字段必须在类体声明)
现象:TPC 编译 TransPyV/App/lib/core/Repl.vp:802
ct_names: list[str]* = GenApi._g_gen.TypeGenCType.CTypedefNames
报「带注解赋值表达式 …(Attribute 形态)编译期求值为空(表达式未解析出目标、无值可存),
赋值将被跳过、变量保持未初始化」。
判据(.vpi 与定义侧不同源,实证):
· TypeGenCType 类体**一个字段都没声明**:CTypedefNames / CTypedefTypeStrs / CTypedefNameIdx
/ CTypedefNameIdxCap / CTypedefNameIdxBuilt 全部只以方法体里的裸 `self.x = ...` 出现
(:184 `self.CTypedefNames = tn`、:185、:66-73、:118-121)。
· 声明存根(.vpi)只携带**类体 AnnAssign 字段**与 `__init__` 里**带注解**的 self.x;方法体
里的裸赋值只被**定义模块自己**的成员收集(HandlesClassDef 的 self.x 扫描)收录
⇒ 同一字段"定义模块成员表里有、引用模块没有"(实证:temp/05d515186a7c3668.vpi 内不含
CTypedefNames 条目)⇒ 引用模块的属性链在第三级断掉,整条带注解赋值被判"无值可存"而终止。
修法:把这 5 个字段在**类体**显式声明(类型取自各自赋值处的真实类型):
CTypedefNames / CTypedefTypeStrs : list[str] | t.CPtr (:177-178 的 tn / ts 即 list[str]*)
CTypedefNameIdx : sizet* (:64 / :71 的 idx)
CTypedefNameIdxCap / CTypedefNameIdxBuilt : int
声明后定义侧与 .vpi 两侧字段集一致(类体 AnnAssign 先收集,方法体 self.x 扫描按名去重不再
重复登记)⇒ 布局同源。注意:该类的字段顺序/类型与旧构建不同(字段从"仅扫描收集"变为
"类体声明"),需要清缓存重编译。
附带(另一仓 commit):TPC 侧 `_handle_attr_nested` 的 7 处静默 return 已补 `_NoteAttrNone`
记账(含内层失败原因链),下次同类报错会直接给出"读取侧原因=…"。
|
2026-09-30 09:59:54 +08:00 |
|
TermiNexus
|
c1a22411ca
|
fix(TypeGenResolve): 规则 5.5 增「本文件顶层类名」证据,模块级早于类定义的窗口不再留裸名
类别:a 编译器缺陷(TPV 侧;补齐"第二个裸类名窗口")
现象(与上一轮 e1bb42f 同一现场、不同窗口):编译 includes/ast/base.vp 时 :359
`_append_child(self.children, node, self.pool)` 报"指针隐式转指针已禁止(被指类型是
非基本类型…)",源 list[rawptr[AST]]* 与目标 list[rawptr<定义模块SHA1>.AST]* 差在实参的
SHA1 前缀。
判据(第二个窗口 = 模块级语句早于类定义):
· Translator.translate 的 prologue 先跑模块级 AnnAssign/Assign(Translator.vp:592-599)
与 forward_declare_functions(:601),**之后**才 translate_children(:602) 逐个翻译类;
而"正在定义类"窗口(CurDefModuleSha1/CurDefClassName)只在类定义入口
(ClassGenDef.vp:50)或 .vpi 注入(VpiReader.vp:2659)才建立 ⇒ 前者解析注解时窗口为
None ⇒ `_norm_type_arg_name` 规则 5.5 的 ①②③④ 全落空 ⇒ 注解里的裸类名(base.vp:148
`_append_child(..., lst: list[rawptr[AST]])` 的形参即此窗口)以**裸名**形式被首次注册,
并被后续复用(首写者胜:StructGenMixin 按 Ty 去重、ClassGenDef existing 早退不重算)
⇒ 与同一特化在类定义期解析出的带 SHA1 形式分裂。
修法(正向事实,不猜;与窗口/类定义顺序无关):
1. `StructGenMixin` 增文件级登记:字段 `FileClassNames`(本文件顶层 ClassDef 类名表,
表与键同池、每文件随 `reset_visible_structs` 重建)+ `FileModuleSha1`(本文件模块
SHA1),以及 `register_file_classes` / `is_file_class` / `get_file_module_sha1`。
键从 AST 的 name **复制到 pool** 后再登记(AST name 零拷贝指向 src_buf,跨阶段可能
失效,直接当表的键会 strcmp 到悬空内存)。
2. `Translator.translate` prologue:在模块级变量/前向声明**之前**调用
`GenApi.register_file_classes(pool, self.ModuleSha1, tree)`(GenApi 增同名委托)。
3. `TypeGenResolve._norm_type_arg_name` 规则 5.5 增**第五类证据**:①②③④ 全落空时,
若 `is_file_class(name)`(该裸名确由本文件声明)且本文件模块 SHA1 已知 ⇒ 归属本文件。
验证:TPV 侧改动需重新自举 TransPyV.exe 后生效;本轮以代码级证据链
(Translator.vp:592-602 / ClassGenDef.vp:50 / TypeGenResolve.vp 规则 5.5 闸门)自证。
TransPyV 仓另有他人未提交文件,本次只提交本改动的 4 个文件。
|
2026-09-30 00:23:43 +08:00 |
|
TermiNexus
|
e1bb42fade
|
fix(ClassGenGeneric): 泛型特化不再平移"类定义窗口",裸类名实参不再冻结成裸名
类别:a 编译器缺陷(TPV 侧)
现象(反复出现 4 轮):编译 includes/ast/base.vp 时 :359 `_append_child(self.children, node,
self.pool)` 报
「指针隐式转指针已禁止(被指类型是非基本类型…):源类型 %"…list[rawptr[AST]]"* →
目标类型 %"…list[rawptr<定义模块SHA1>.AST]]"*」——同一泛型特化被写成两种拼名(实参一侧
裸类名 `AST`、另一侧带定义模块 SHA1 前缀)。
判据(结构缺陷,代码级可证):
· `_norm_type_arg_name` 规则 5.5 判定"裸类名归属"依赖两个**全局窗口变量**
`StructGen.CurDefModuleSha1` / `CurDefClassName`(证据 ② `is_module_class`、
③ `CurDefClassName` 逐字相同),入口闸门是 `_def_mod is not None`。
· `ClassGenGeneric._specialize_generic_class` 在 :715-720 把 `trans.ModuleSha1` 临时切到
**泛型模板定义模块**,再于 :729 调 `ClassGenDef.translate_class_def`;后者在
`ClassGenDef.vp:50` 会 `mark_module_class(pool, trans.ModuleSha1, class_name)`
⇒ **窗口被覆盖成"模板模块 + 特化类名"**。原实现返回时只恢复 `trans.ModuleSha1` 与
`_imported_modules`(:733-735),**没有恢复这两个窗口变量**。
· 后果:调用方文件在此之后解析任何裸类名时,证据 ②③ 都在对着"模板模块 / 特化类"判 ⇒
全落空 ⇒ 该实参以**裸名**形式被首次注册并被后续复用(首写者胜:`StructGenMixin.vp:455`
按 Ty 指针去重、`ClassGenDef.vp:100-150` existing 早退不重算)⇒ 与同一特化在别处解析出的
带 SHA1 形式分裂成两个名字 ⇒ 被"非基本类型指针不可隐式转换"拦下。
修法:
1. `ClassGenGeneric.vp`:窗口与 `ModuleSha1` **同进同出** —— 在切 ModuleSha1 之前保存
`CurDefModuleSha1`/`CurDefClassName`,:744 之后一并恢复(嵌套特化不再污染调用方窗口)。
2. `TypeGenResolve.vp` 规则 5.5 的取证日志扩展:除原有"命中 struct 条目但 entry.ModuleSha1
为空"外,**新增触发条件"窗口存在却属于另一个类"**(`_def_mod` 有值且
`CurDefClassName` 与裸名不同)——正是"窗口被特化平移/污染"或"前向引用未登记类"的签名;
报文补出 `entry_present` 与 `find_struct_by_module` 两项事实,一轮即可定位来源是否缺失。
验证:TPV 侧改动需重新自举 TransPyV.exe 后生效;本次以静态证据链(上述行号)与取证日志
自证。注:TransPyV 仓另有 7 个他人未提交文件,本次只提交本文件与 TypeGenResolve.vp。
|
2026-09-30 00:20:30 +08:00 |
|
TermiNexus
|
31f341cf6f
|
fix(transpyv): vpi 注入期登记「本模块声明的类」,裸类名实参不再冻结成裸名
类别 a(编译器缺陷):_norm_type_arg_name 规则 5.5 的入口闸门是
`_def_sha1 is None and _def_mod is not None`(_def_mod = CurDefModuleSha1),而
VpiReader._inject_class_struct_declare 是在**注入期**解析字段注解的——此刻既没有
"类定义窗口"(CurDefModuleSha1=None ⇒ 闸门整条关闭、四条证据一条都不查),被注入的类
也尚未 register_struct ⇒ 注解里的裸类名实参取不到定义模块 SHA1 ⇒ 特化名被冻结成
**裸名版本**,与该类在自身翻译期(类已注册)解析出的带前缀形式分裂成两个特化名,
最终以"非基本类型指针不可隐式转换"报出。现场:includes/ast/base.vp:359
_append_child(self.children, node, self.pool)
源 %"…list[rawptr[AST]]"* vs 目标 %"…list[rawptr<定义模块SHA1>.AST]"*
这也解释了前两轮修复为何无效:③(自引用判据)依赖 CurDefClassName、④(entry.Ty 取
前缀)依赖 struct 条目,而注入期两者都不可用,且此时连日志条件(entry 命中)都不成立。
- GenApi:新增 mark_module_class 委托(与 add_visible_struct / find_struct_by_module 同款)。
- VpiReader._inject_class_struct_declare:在解析字段注解之前调用
GenApi.mark_module_class(pool, src_sha1, cls_name) —— 一次调用同时完成
① 登记"{src_sha1}.{cls_name}"(名字归属,与 struct 注册状态无关);
② 把 CurDefModuleSha1/CurDefClassName 指向本次注入的模块与类(打开规则 5.5 的闸门)。
|
2026-09-29 22:29:48 +08:00 |
|
TermiNexus
|
df1244d6f4
|
fix(transpyv): 裸类名归属补「符号名真源」(entry.Ty 的 {SHA1}.{类} 前缀)+ 取证日志
类别 a(编译器缺陷):_norm_type_arg_name 规则 5.5 判定裸类名归属只认三条证据——
struct 注册表的 ModuleSha1、ModuleClasses 登记表、以及"正在定义类"。Phase A-pre 没有
"类定义窗口"(CurDefModuleSha1=None),而 .vpi 注入的类条目常常 ModuleSha1 为空 ⇒
三条全落空 ⇒ 实参保留裸名,与后续(类已注册时)解析出的带前缀形式分裂成两个特化名
⇒ 被"非基本类型指针不可隐式转换"拦下。现场:includes/ast/base.vp:359
_append_child(self.children, node, self.pool)
源 %"…list[rawptr[AST]]"* → 目标 %"…list[rawptr<定义模块SHA1>.AST]"*
- 规则 5.5 新增证据 ④(表/窗口都不可用时的**符号名真源**):结构体自身的 IR 名本就是
"{定义模块SHA1}.{类名}"(与本仓全部 mangling 同源:ClassGenDef/ClassGenVTable/
VpiReader 的 Stub 构造)⇒ 打印 entry.Ty 并取回其 sha1 前缀(复用
_is_sha1_prefixed 这一唯一判据,不另写判定)。
- 同一处补取证日志:命中 struct 条目却一条 SHA1 证据都取不到时(可疑子集:
entry.ModuleSha1 为空),把 entry.Ty / cur_def_mod / cur_def_cls /
is_module_class / from_imports / file 一次打出(只加日志,返回值语义不变)。
|
2026-09-29 21:28:18 +08:00 |
|
TermiNexus
|
bbd0cdbf62
|
fix(transpyv): 自引用类名归属加「表无关」判据,字段与形参不再分裂成两个特化名
类别 a(编译器缺陷):_norm_type_arg_name 规则 5.5 判定"正在定义的类"的裸名归属
时只认两条证据——struct 注册表(find_struct_by_module)与 ModuleClasses 登记表
(is_module_class)。自引用字段(includes/ast/base.vp `AST.children:
list[rawptr[AST]]`)在类定义体内解析时本类尚未 register_struct,而 ModuleClasses
的键是 pool 字符串,登记/查询受"表未就绪、键随 pool 回收"影响 ⇒ 两条都可能落空
⇒ 实参留在裸名 `list[rawptr[AST]]`,与同一注解在形参处(类已注册)解析出的
`list[rawptr<定义模块SHA1>.AST]` 分裂成两个特化名 ⇒ 被"非基本类型指针不可隐式
转换"拦下(现场:includes/ast/base.vp:359
`_append_child(self.children, node, self.pool)`,源 %"list[rawptr[AST]]"* →
目标 %"list[rawptr<sha1>.AST]"*)。
- StructGenMixin:新增 CurDefClassName —— 与 CurDefModuleSha1 同源同生命周期,
由 mark_module_class 在类定义入口(ClassGenDef 第 50 行,早于字段注解解析)
一并记录;InitStructGen / reset_visible_structs 同步清空。
- TypeGenResolve._norm_type_arg_name 规则 5.5:新增证据 ③(表无关)——查询名与
正在定义的类名逐字相同即判为本类,用 CurDefModuleSha1 加前缀。类名直接来自类
定义入口、不经任何表 ⇒ 自引用窗口内必然可判;证据 ② 失败时不再退回裸名。
|
2026-09-29 20:16:05 +08:00 |
|
TermiNexus
|
1b2324edab
|
fix(transpyv): 修正 mark_module_class 的表生命周期(ASan 悬空键崩溃)
类别:a(编译器缺陷 —— 上一提交自引入的跨文件悬空 HashTable)
现场:ASan access-violation(READ @0x1),rcx=0x1
string.strcmp (includes/string.vp:86)
→ HashTable._find_slot (_resize) → __setitem__ → set_int
→ StructGenMixin.mark_module_class → ClassGenDef.translate_class_def
→ TranslatorGenMixin.translate_children → Translator.translate → RunPhase1 → main
根因:`ModuleClasses` 原先在 `mark_module_class` 里**懒创建**,并长期挂在 Gen 上;
表体与键都取自当次文件的 pool,而 pool 在文件/遍切换时会被 reset ⇒ 下一个文件里
`_resize` 重新散列旧键时 strcmp 读到已回收内存(0x1)⇒ 崩溃。
改动(与既有 `VisibleStructs` 同口径:表与键同池、同文件生命周期):
1. `ModuleClasses` 改由 `reset_visible_structs`(每文件翻译前调用)**无条件新建**
(不再区分 strict 分支),与键同池 ⇒ 无悬空。
2. `CurDefModuleSha1` 指向 `trans.ModuleSha1`(同一 pool 的串),同样在该函数里
清空,避免下一次 strcat/strcmp 读已回收内存。
3. `mark_module_class` 不再懒建表:池或表缺失时只记 `CurDefModuleSha1`、跳过登记
(宁可退化为改前行为,也不冒悬空风险)。
语义不变:规则 5.5 的证据链仍是 ① 结构体表按名(跨文件/跨遍)→ ② 正在定义类所属
模块 + find_struct_by_module → ③ 本文件已声明类归属表(自引用字段窗口 —— 登记与
查询在同一文件同一遍内,正是该表的作用域)。
|
2026-09-29 19:14:10 +08:00 |
|
TermiNexus
|
2b8cc2a69b
|
fix(transpyv): 特化名规范化下沉到唯一生成器,裸实参路径不再造第二个名字
类别:a(编译器缺陷 —— 特化名生成点不止一处,实参在"裸名/带前缀"两态并存)
背景(命名源审计,两个独立检索子代理收敛到同一清单):`_norm_type_arg_name`
是唯一规范化器,但"拼 Class[a0,a1]"的构造点有 20+ 处,其中 6 处绕过它。
本轮把规范化**下沉到唯一生成器**,让所有调用方自动同源 —— 该函数对已规范化的串
是幂等的(规则 2/3/6 原样返回,嵌套 rawptr[X] 递归同形)。
改动:
1. ClassGenGeneric._mangle_generic_class_name 增 from_imports 参数:逐实参经
TypeGenResolve._norm_type_arg_name 归一后再拼串(长度计算与拼接同用归一后列表)。
唯一调用点 _specialize_generic_class 传 trans._from_imports。
2. ClassGenBase._get_base_name 增 from_imports 参数:Subscript 分支的类型实参
(原为裸 Name.id)同样归一 —— 该函数产出的父类特化名要拿去 find_struct_by_module
查、并写入 entry.ParentName,而注册名由生成器产出,不归一必然对不上
(父类 GSListNode[Value] vs 注册的 GSListNode[{sha1}.Value])。
三处调用点(_get_parent_class / _collect_parents / _trigger_base_specialization)
传 trans._from_imports;递归调用透传。
3. _trigger_base_specialization 本身无需改:它的裸实参进入 _specialize_generic_class,
已由第 1 条统一归一。
收敛效果(连带):_specialize_generic_class 的 spec_name 与
TypeGenResolve._resolve_generic_subscript_ty 自拼的 gen_mangled 现已同形(后者本就
归一),源码注释里"gen_mangled 与特化名可能不一致 ⇒ 用 spec_name_chk 重查"那条
隐性双名自然不再触发。
遗留(未动,见审计清单):ExprGenConst.translate_list_literal /
CallGenCtor._infer_generic_ctor_type_arg 传的内建名不受影响(规则 6 原样保留),
但其"类名"实参现由生成器统一归一;CallGenCall/CallGenDispatch 从已注册名回拆
"[...]" 时用 strchr 按首个逗号切分(深度不敏感)另计。
影响面:ABI 可见(结构体名 / 方法符号后缀段);需 TPV 自举重建 + 回归验证,
重点观察 VpiReader 的泛型键匹配(其键以 T 占位符,初判不受影响)。
|
2026-09-29 18:53:58 +08:00 |
|
TermiNexus
|
868d48ae22
|
fix(transpyv): 自引用字段的特化名不再留在裸名(新增"本模块声明类"归属表)
类别:a(编译器缺陷 —— 字段类型在类注册前被冻结成裸名版特化名)
现场(上一轮未修掉的那一处):includes/ast/base.vp:357
if self.children is None: self.children = list[rawptr[AST]](self.pool, 8)
CastError:源 %"7e2b6dda6e423bfb.list[rawptr[d1ed020479454541.AST]]"*
→ 目标 %"7e2b6dda6e423bfb.list[rawptr[AST]]"*
根因:字段 children: list[rawptr[AST]] | t.CPtr 写在**类 AST 自己体内**(自引用),
其类型在 translate_class_def 的字段循环里解析,而本类的 register_struct 在该函数
**末尾**才执行 ⇒ 解析时 struct 表里没有 AST ⇒ 上一轮 5.5 的两条查法
(find_struct 按名 / find_struct_by_module)全部落空 ⇒ 实参仍留裸名 rawptr[AST],
字段类型被冻结成 list[rawptr[AST]](第一遍 A-pre 即发生);而 :357 的构造调用发生在
类注册之后 ⇒ 带 SHA1 ⇒ 两侧分裂。(同一分裂在 stmts.vp:60 表现为形参侧/实参侧,
本处表现为字段侧/构造侧。)
改动:
1. StructGenMixin 新增"本模块声明类"归属表 ModuleClasses(键 "{模块SHA1}.{类名}")
与 CurDefModuleSha1(正在定义类所属模块 SHA1,登记时同步记录):
- mark_module_class(pool, sha1, name) / is_module_class(pool, sha1, name)
- 键含 SHA1 ⇒ 与翻译顺序/模块切换无关、无需每文件重置,也不会把别的模块的类
错认成本模块。
2. ClassGenDef 类定义入口(add_visible_struct 之后、枚举/联合分派之前)登记
mark_module_class(pool, trans.ModuleSha1, class_name),覆盖 class/enum/union/
renum 全部类种类。
3. TypeGenResolve 规则 5.5 补齐证据链:① 按名取 StructEntry.ModuleSha1;
② struct 表暂无条目时用 CurDefModuleSha1 走 find_struct_by_module;
③ 仍无条目(正是自引用窗口)时查归属表 ⇒ 加 SHA1 前缀。
CurDefModuleSha1 取代 CurrentModuleSha1 作为"当前定义模块"真源——后者在
A-pre/StubMerger 路径未设置或留着上一文件旧值(只有 Translator.ModuleSha1 权威)。
影响面:ABI 可见(特化名);需 TPV 自举重建 + 回归验证。
|
2026-09-29 18:47:35 +08:00 |
|
TermiNexus
|
dddaba3254
|
fix(transpyv): 5.5 步补「类定义中」回退,字段侧特化名不再留在裸名
类别:a(编译器缺陷 —— 同一特化在字段侧/构造侧仍分裂,方向相反)
现场:includes/ast/base.vp:357
if self.children is None: self.children = list[rawptr[AST]](self.pool, 8)
CastError:非基本类型指针不可隐式转换
源(构造调用结果) %"7e2b6dda6e423bfb.list[rawptr[d1ed020479454541.AST]]"*
目标(字段声明类型) %"7e2b6dda6e423bfb.list[rawptr[AST]]"*
上一处(stmts.vp:60)是"形参侧裸名 vs 实参侧带前缀",本处反向:**字段侧**
仍是裸名。字段 children: list[rawptr[AST]] | t.CPtr 写在**类 AST 自己体内**
(自引用),解析该字段类型时类正在定义中:find_struct('AST') 按名查不到(登记项
尚未命名)⇒ 5.5 首条查法落空 ⇒ 仍返回裸名;而 :357 的构造调用发生在类已注册之后
⇒ 带前缀,两侧再度分裂。
改动:5.5 步在 find_struct 未命中 / ModuleSha1 为空时,回退用与
resolve_annotation_type 的 Name 分支**同一处证据**认定本模块类:
find_struct_by_module(name, self.Gen.TypeGenBase.CurrentModuleSha1) 命中即以当前
模块 SHA1 加前缀。对同一模块的类,"按名取定义模块 SHA1"与"当前模块身份"给出同一
SHA1,故不引入新分裂。文档串规则表同步补该回退。
|
2026-09-29 18:38:52 +08:00 |
|
TermiNexus
|
65d7f7cc31
|
fix(transpyv): 泛型实参里的「本模块裸类名」也加定义模块 SHA1,特化名不再分裂
类别:a(编译器缺陷 —— 同一类型在本模块与被引用模块得到两个特化名)
现场:includes/ast/stmts.vp:60
_set_parent_list(targets, self)
CastError:非基本类型指针不可隐式转换
源 %"7e2b6dda6e423bfb.list[rawptr[d1ed020479454541.AST]]"*
目标 %"7e2b6dda6e423bfb.list[rawptr[AST]]"*
外层特化前缀相同,只有类型实参里的类名一个带 SHA1、一个裸名 ⇒ 同一个
list[rawptr[AST]] 变成两个结构体 ⇒ 被"非基本类型指针不能隐式转换"拦下。
根因:_norm_type_arg_name 的第 5 步只查 from_imports(可见性表);**本模块自己
声明的类**不在表内 ⇒ 落到第 6 步原样返回裸名,而被引用模块解析同一类型时第 5 步
命中(from-import 归属模块)带 SHA1 ⇒ 两侧对同一类型产出两个名字。
改动(_norm_type_arg_name 新增 5.5 步):
- 简单裸名(不含 '[' / '.')先经结构体表 find_struct(name) 取该类的
**定义模块 SHA1**(StructEntry.ModuleSha1)加前缀 —— 与"当前模块"无关,
故本模块内与跨模块得到同一票名;仅当登记项存在且 ModuleSha1 非 None 时生效。
- 文档串规则表同步补 5.5;第 6 步措辞改为"内置类型名等"。
与第 5 步同口径(都只处理简单裸名):泛型特化名 list[...] 与模块限定名
mod.Class 各有自己的分支,不在 5.5 重复加工。
注:TPC 侧同名规则源(SymbolUtils.ResolveTypeArgStr)是否需要同步,待该现场
回归通过后再核。
|
2026-09-29 18:31:52 +08:00 |
|
TermiNexus
|
8e7d7feb57
|
fix(transpyv): rawptr[T] / t.CPtr[T] 对裸类引用吸收一层指针(不再多包一层)
类别:a(编译器缺陷 —— TPV 注解解析与「联合写法 / TPC 两侧」口径分裂)
现场:includes/ast/tokens.vp:217
ptr: rawptr[Token] = pool.alloc(Token.__sizeof__())
CastError(TPV ExprGenBase.vp:746-753):指针层数不同(源 1 级 → 目标 2 级);
源类型 i8* → 目标类型 %"…Token"**。
根因链:
1. 本文件 Name 分支(:2269-2277):有 __new__ 的堆类裸名注解解析为 Ptr(struct)
(引用语义,注释明写「对齐 TPC」)⇒ Token → %"…Token"*。
2. rawptr[T] 分支(原 :2865-2871)与 t.CPtr[T] 分支(原 :2928-2939)只做
Ptr(resolve(T)),不含「裸类引用吸收一层」⇒ %"…Token"**(2 级)。
3. 同一语义的其余实现都有该规则,唯此两处缺失:
- 联合写法 X | t.CPtr 的 BinOp 分支(:2682-2684 的判据注释 + :2703-2720 回退)
得 1 级;
- TPC 侧 LLVMTypeMapper._rawptr_subscript_type_str(内层映射成 %…* 即吸收)
与 HandlesTypeMerge._MergeAllComponentTypes(IsStruct 时吸收一层)。
规则真源见 TPC SymbolUtils.IsPtrSubscriptNode 文档:「内层 T 为类引用时该层被
结构体自身吸收('<sha1>.X*'),其余(标量 / 已是指针的 typedef / 泛型容器特化 /
嵌套指针下标)逐层外包」。
改动:
1. 新增判据 _ptr_subscript_absorbs_class(slice, resolved):切片**非**用户写明的
指针包装(联合 BinOp / 嵌套 rawptr[...]、t.CPtr[...]、裸名 CPtr[...])且解析
结果已是 Ptr(已注册 struct)(find_struct_by_type 命中,与 BinOp 分支同一判据)
⇒ 返回 1(吸收该层)。纯判据,不发射类型。
2. rawptr[T] 与 t.CPtr[T] 两个分支接入该判据。
逐条核对保持不变的形态:rawptr[int]→i32*、rawptr[str]/rawptr[bytes]→i8**、
t.CPtr[t.CPtr]→i8**、rawptr[rawptr[X]]→X**、t.CPtr[int]→i32*、
rawptr[Point(无 __new__ 的栈类)]→Point*。
影响面:ABI 可见(字段 / 形参 / 局部变量类型),需 TPV 自举重建 + 整轮回归验证。
|
2026-09-29 18:07:37 +08:00 |
|
TermiNexus
|
c2d7480f3d
|
fix(transpyv): 槽视图统一 cast 到声明类型(47 处,含 codegen 自身)
同 includes 的同类修正:把一级指针 i8* 隐式塞进二级注解(i8** / str*)。
TransPyV 侧 coerce(ExprGenBase._ptr_cast_reason)没有 TPC 那样的「值侧是显式
指针 cast ⇒ 按 bitcast 重解释」豁免,故一旦用新构建的 TransPyV 编到这些文件
必然 fail-fast(回归测试首爆点在 includes/llvmlite 侧,本仓同形态站点随后必然
同样触发)。
涉及的两种形态:
· `slot: str | t.CPtr = (t.CPtr)(addr)` —— cast 目标是一级 t.CPtr
· `nm_slot: str* = (t.CPtr)(addr)` —— 注解 str* 即 i8**
统一改为 cast 到声明类型:`(str | t.CPtr)(addr)` / `str*(addr)`(后者与
includes/sys.vp `argv_arr: str* = str*(...)` 同一写法)。
本仓 47 处 / 6 文件:
App/lib/core/Gen/VarGenMixin.vp 3
App/lib/core/Gen/TranslatorGenMixin.vp 8
App/lib/core/Gen/Func/FuncGenMixin.vp 13
App/lib/core/Gen/AsyncGenMixin.vp 15
App/lib/core/Gen/DebugInfoGen.vp 6
App/lib/Stub/StubGen/Converter.vp 2
Converter.vp:107 的 `_g_pyi_cdef_names: str | t.CPtr = None` 保持原样
(None 即空指针,任何指针类型均可,不属本类问题)。
只提交本 6 个文件;本仓其余未提交改动(CallGenBase/CallGenDispatch/CallGenFd/
CallGenProp/Generator/Translator/VLogger)与本迁移无关,保持不动。
|
2026-09-29 15:10:33 +08:00 |
|
TermiNexus
|
07f2f2e9fc
|
fix(transpyv): CallGenCBuiltin 的 clobbers 改为单级 t.CPtr,并同步该文件语法迁移
【类别 c 源码违规】clobbers 声明的指针层数与 alloc/memset 不一致。
现象:
翻译 App/lib/core/Gen/Call/CallGenCBuiltin.vp 报
「指针隐式转换已禁止(层数不同):不能用指针类型 i8* 初始化 clobbers: i8**」
出错表达式 'pool.alloc(8 * ASM_MAX_CLOBBERS)'(Call 形态,CallGenCBuiltin.vp:955:33)。
判据(三条,缺一不可):
1. memhub.MemBuddy.alloc(size: sizet) -> t.CPtr(includes/memhub.vp)即 i8* 单级;
2. str | t.CPtr 是 i8**(CChar + PtrCount 2),即字符串指针数组视图;
3. MemoryOps._ClassifyPtrImplicitConvert 判定顺序为**先比层数**,层数不同直接禁,
通用指针通配(void*)不跨层。
故 i8* 结果不能隐式初始化 i8** 变量 —— 与是否同名 str 无关。
取证补充:同函数下一行 string.memset(clobbers, 0, ...) 首参同样是 t.CPtr
(includes/string.vp: memset(ptr: t.CPtr, value: int, num: sizet)),
即便只给 clobbers 加 cast,memset 一样会挂 —— 必须把声明本身改回单级。
修法:clobbers 声明改回单级裸缓冲 t.CPtr,每槽按 8 字节字符串指针的写入沿用
下方既有的显式 cast 槽视图写法
(cl_ptr: str | t.CPtr = (str | t.CPtr)(cl_addr)),
与 includes/_dict.vp 的「缓冲单级 t.CPtr、槽视图 str | t.CPtr 显式 cast」范式一致。
此改**不引入新 cast、不绕过检查**,只是把声明修正到与真实分配/清零层数相符。
同类扫描:全 App + includes 内 str | t.CPtr = *.alloc(...) 形态仅此一处;
includes/sys.vp 两处早已是显式 str*(...) 转换。
同时并入本文件他人已完成的语法迁移(同文件合并提交):
- 常量声明 t.CDefine: T = 值 → define NAME = 值 语法糖(_CEXPORT_MAX /
ASM_MAX_OPERANDS / ASM_MAX_CLOBBERS / ASM_TEXT_BUF_SIZE / ASM_CONST_BUF_SIZE /
ASM_ARGS_BUF_SIZE / ASM_LINE_BUF_SIZE / LLVMIR_MAX_OPS / LLVMIR_TEMPLATE_BUF);
- @t.NoVTable + class → novirtual class;
- 删除常量块内已失效的注释与多余空行。
1 file changed, 17 insertions(+), 18 deletions(-)
|
2026-09-29 14:47:42 +08:00 |
|
TermiNexus
|
1f93550b6d
|
revert(transpyv): 还原 *existing.Ty = <boxed 变体构造>(c.DerefAs 是绕过自家检查)
a9e4aaf 把 `*existing.Ty = llvmlite.LLVMType.Struct(...)` 改写成
c.DerefAs(existing.Ty, ...)。但 DerefAs ≡ *p = a(_HandleCDerefAsLlvm 的
「整对象拷贝」分支就是 load + store),二者语义完全等价 —— 换写法只是绕开了
*槽 = <boxed 变体> 触发的严格规则③,并未解决根因。
根因在编译器侧:「构造物化」豁免漏了 REnum 变体构造这一形态。已在 TPC 侧修好
(fix(tpc): 「构造物化」豁免覆盖 REnum 变体构造),本处源码随之还原为直白的
`*槽 = <boxed 变体>` 写法,不再用内建绕开严格检查。
|
2026-09-28 23:21:36 +08:00 |
|
TermiNexus
|
a9e4aafae1
|
fix(transpyv): ClassGenDef 用 c.DerefAs 物化 REnum 变体(替代 *ptr = <boxed 构造>)
c 源码违规:`*existing.Ty = llvmlite.LLVMType.Struct(...)` 把 **boxed 变体指针**
赋给了值槽(指针→值,严格规则禁止)。REnum 变体构造返回 boxed 指针,仓库既定
写法是用 c.DerefAs(ptr, <boxed 变体>) 做整对象物化(includes/llvmlite/__types.vp:195
的同款 `c.DerefAs(ptr, LLVMType.Struct(fields, fcount, name))`),
_HandleCDerefAsLlvm 的"整对象拷贝"分支正是为此(HandlesExprCall.py:4718-4740)。
用 DerefAs 而非改成 `existing.Ty = <新指针>`:本段的目的就是修 Phase 1a 遗留的
**悬空 Name**(注释 L97-101),Phase A 已把该指针登记进 named-type 表;换指针会让
旧条目继续指向悬空 Name,in-place 覆盖才保留指针同一性、真正修掉悬空。
现场报错:非基本类型的值/指针隐式转换已禁止(构造物化除外):
不能把指针类型 %"50741ad4b4b0934d.LLVMType"* 隐式转为值类型
%"50741ad4b4b0934d.LLVMType"
|
2026-09-28 23:15:46 +08:00 |
|
TermiNexus
|
fddadf9d56
|
fix(transpyv): 修正 _PyiClass 的 type_params 局部变量注解(list[ast.AST*]* → list[str]*)
c 源码违规(注解写错,被严格指针规则抓出):ClassDef.type_params 的真身是
rawptr[list[str]](**名字串**列表,见 includes/ast/stmts.vp:475-483 与
parser.vp:3619-3663 的 `list[str](ps.pool, 8)`);`list[rawptr[AST]]` 是
decorator_list 的类型。Converter._PyiClass 把局部变量注解从 decorator_list
抄错成 list[ast.AST*]* ⇒ `.get()` 被解析到 list[ast.AST*].get,而实参是
list[str]* ⇒ fail-fast:
调用 650c1c3366d09e39.list[10f3f43ddd447eec.AST*].get 第 0 个实参
%"650c1c3366d09e39.list[str]"* 不能隐式转为形参
%"650c1c3366d09e39.list[10f3f43ddd447eec.AST*]"*
已核对全仓其余 8 处 type_params 用点(VpiReader.vp:2253/2274/4345、
Phase2/__init__.vp:317、Phase1Scan.vp:153/318、ClassGenDef.vp:69、
CallGenMixin.vp:415)均写作 list[str]*,本次与之对齐。
|
2026-09-28 22:54:50 +08:00 |
|
TermiNexus
|
aa52cf157d
|
revert(transpyv): 回滚跨模块链表 Next 改访问器(改由编译器沿继承链解析字段名)
回滚 13080f6 的 110 处访问器调用,恢复裸字段访问 `x.Next`。
理由:该批访问器是把访问移到定义模块内执行,**绕开**了"继承字段名解析",
属于规避而非修复;缺陷本体在 TPC 侧(导入侧继承展平把泛型基类的继承字段
记成 __inherited_N 占位名,名字丢失)。TPC 已按语义修正:
· e6451a07 继承展平沿继承链取真实字段名(泛型特化回退模板名),
展平表直接落 `[("Next", <槽位类型>), ...]`,属性访问是普通表命中;
· 3ca46c01 顺带修掉 _get_or_create_struct 里"同名枚举成员遮蔽类定义"的 i32 出口。
因此源码侧恢复为唯一写法(裸字段访问),由编译器负责解析。
注:本 commit 只回滚访问器;13080f6 里夹带的 CallGenProp.vp 续行合并(非访问器改动)
已在工作区保留(未提交)。
|
2026-09-28 21:48:53 +08:00 |
|
TermiNexus
|
13080f646f
|
fix(transpyv): 跨模块链表 Next 字段改用访问器(消除 __inherited_N 占位名 fail-fast)
c 源码违规:llvmlite 的 Value/ParamNode/Function/Param/GlobalVariable/PhiIncoming/
SwitchCase 的 Next 继承自泛型基类 GSListNode[T],而其泛型特化体不在任何 .vpi 中
⇒ 导入侧 class_members 只有 __inherited_N 占位名;严格属性解析(回退已移除)下
裸写 `x.Next` fail-fast。现场:CallGenCall.vp `cur_fb = cur_fb.Next` 报
"[fast-fail] 属性 Next 在类 ParamNode 中找不到(class_members=[__inherited_0, Ty])"。
按仓库既有约定(_Type.md:链表遍历用 paramnode_get_next/paramnode_set_next;
VarGenMixin/TypeSpec/StructGenMixin/VpiReader 等已如此书写)统一改为访问器:
value_get_next/value_set_next、paramnode_get_next/paramnode_set_next、
function_get_next、param_get_next、globalvariable_get_next、
phiincoming_set_next、switchcase_set_next
覆盖 24 个文件共 110 处(含 CallGenProp.vp:122 的嵌套读 cur_arg_pc.Next)。
访问器在 includes 侧为定义模块内直通实现(None 守卫 + x.Next),语义等价、零行为
变化。已全量扫描 core\Gen 全 47 文件与 Stub/Phase/core/main:App 侧已无裸继承字段
访问(剩余 .Next 命中全部在注释里)。
|
2026-09-28 21:20:58 +08:00 |
|
TermiNexus
|
75ea6fb9b2
|
fix(transpyv): 消除隐式向下转型(ast.AST* 实参 → 派生 AST 形参)
c 源码违规(严格指针规则:基类指针传派生类形参属向下转型,须显式转换):
1) TranslatorGenMixin._prescan_funcdef_signatures:形参由 ast.FunctionDef* 改为
ast.AST*,函数体内显式 `fd: ast.FunctionDef* = ast.FunctionDef*(node)`。
理由:模块级调度器只持有 ast.AST* 子节点,同一处调用的
translate_function_def / translate_class_def / _register_cexport_from_funcdef
形参一律是 ast.AST*,本函数是唯一例外(报错现场:第 2 个实参 %"..AST"* 不能
隐式转为形参 %"..FunctionDef"*)。改为与兄弟入口同口径,调用点无需改动。
2) CallGenDispatch len() 内置分支:_is_list_builtin_receiver 第 5 形参是
ast.Call*(仅用于 D25 fail-fast 定位节点),实参 len_arg_node 声明为基类
ast.AST* ⇒ 显式窄化 `len_arg_cl: ast.Call* = ast.Call*(len_arg_node)`。
附:对 App\lib 全量静态扫描(core\Gen 全 47 文件 + Stub/Phase/core/main)确认
此类「基类指针实参 → 派生形参」的隐式向下转型仅此两处,其余调用点均为同类型
或向上转型(规则允许)。
同文件另含仓库内既有书写整理(续行合并),无行为变化。
|
2026-09-28 20:20:56 +08:00 |
|
TermiNexus
|
af5fba81c5
|
fix(transpyv): 严格指针规则下的源码级窄化与跨层指针写法修正
c 源码违规(按新严格指针规则的显式书写):
1) AssignGenMixin.vp 属性赋值:target 是基类 ast.AST*,而
CallGenProp._try_property_setter 形参是 ast.Attribute*。基类指针传派生类形参属
向下转型,严格指针规则下禁止 ⇒ 在 ASTKind 判据确定为 Attribute 后显式窄化
`at_tg: ast.Attribute* = ast.Attribute*(target)`,并复用到 fd_an(不再重复窄化)。
2) TypeGenResolve.vp `return (str | t.CPtr)(v)`:`(str | t.CPtr)` 语义是 i8**(char**),
而该函数声明返回 i8*,声明/返回层数不符 ⇒ 改为 `t.CPtr(v)`(i8* 显式转换)。
同文件另含仓库内既有书写统一(ast.OpKind.USub 全限定名、rawptr(...) 取代
(str | t.CPtr)(...)、空行/续行缩进整理),无行为变化。
|
2026-09-28 19:40:42 +08:00 |
|
TermiNexus
|
825fe6d326
|
fix(TransPyV): 指针 cast 的跨层 idiom 修正:(str | t.CPtr)(x) → rawptr(x)
c 类(源码违规):(str | t.CPtr)(x) 按既定语义 = i8**(char**,指针的指针),
而这些位置要的是 i8*。TPC 的 return/赋值检查现在按声明精确校验(本次即
TypeGenResolve.vp:1221 `return (str | t.CPtr)(v)` 声明返回 i8* 却 return i8** 被抳下),
该 idiom 在旧的无条件 bitcast 下一直不可见。
改法:86 处 (str | t.CPtr)(X) → rawptr(X)(rawptr 是 t.CPtr 的内置名,同为 i8*;
整数操作数走 inttoptr,指针操作数走 bitcast)。不用 str(X):整数操作数会编译成 itoa
(Gen/FuncGenMixin.vp:1159 注释已记录该陷阱),精确类型仍由使用处的 `: str` 标注承担。
保留 4 处本就该是 i8** 的用例(未改):Converter.vp:820(_g_pyi_cdef_names 声明为
str | t.CPtr 的指针数组)、CallGenCBuiltin.vp:1194/1215(声明即 str | t.CPtr)、
1411(先 cast 再 [0] 取首元素)。
另:Gen/Type/TypeGenResolve.vp:1221 手工改为 return t.CPtr(v)(该文件含你的未提交改动,未一并提交)。
|
2026-09-28 18:43:59 +08:00 |
|
TermiNexus
|
d579d70113
|
fix(TransPyV): 修正形参/字段链节点的注解为 llvmlite.ParamNode*
c 类(源码违规):这些变量由 new_param_node 构造、或取自 get_struct_fields /
param_list_append / function_get_param_head,实际是 llvmlite.ParamNode 链节点,
注解却写成 llvmlite.Function*。旧的无条件指针 bitcast 掩盖了该错误,严格指针规则下暴露。
涉及:VarGenMixin / CallGenVt / VpiReader / ClassGenEnum / ClassGenVTable /
ExprGenName / FuncGenMixin / FuncGenDef / TypeGenResolve / TypeSpec /
StmtGenCifMixin / AssignGenMixin(纯注解替换,零语义变化)。15 行。
|
2026-09-28 17:54:13 +08:00 |
|
TermiNexus
|
70448f4590
|
fix(CallGenLeafKit): 闭包/函数指针调用的形参链表误注解 Function* → ParamNode*(Vipeye 600/814/818)
param_node/pn_tail/pn_new(600 的 Func 实参、593 的 pn_tail.Next)与 fp_first/fp_prev/pn2(814 paramnode_set_next、818 Func 实参)均为 ParamNode 链节点,原先误注解 llvmlite.Function*(不相关类)→ 严格指针规则下四处实参/字段赋值被判 struct↔struct 隐式转换禁止。改注解即根治。
|
2026-09-28 17:50:05 +08:00 |
|
TermiNexus
|
29acf97dbc
|
fix(CallGenCBuiltin): 多输出 asm 返回 struct 的字段链表误注解 Function* → ParamNode*(Vipeye 1268)
out_pn_head/out_pn_last/pn5 与 new_param_node 的返回、Struct(fields: rawptr[ParamNode]) 形参、ParamNode.Next 语义一致,原先误注解 Function*(不相关类)⇒ out_pn_last.Next = pn5 / Struct(pool, out_pn_head, ...) 被判 struct↔struct 隐式转换禁止。改注解即根治。
|
2026-09-28 17:18:41 +08:00 |
|
TermiNexus
|
eb1065f387
|
fix(CallGen): Function 的 Param 形参链与 llvmlite.Func 的 ParamNode 构造链不可互传(Vipeye 329/401/1065)
① 新增 CallGenBase._FuncTyFromFunction(pool, f_ref):Function.Params 是 Param 链(__function.vp),LLVMType.Func 的类型构造链是 ParamNode 链(__types.vp,new_param_node/paramnode_set_next),两者是不相关 class ⇒ 严格指针规则下 Func(pool, ret, p_head, cnt) 的实参传递直接报错。改为逐个 new_param_node 重建 ParamNode 链(语义等价,只取各参数类型)。CallGenCBuiltin 329/401 + ExprGenOps 878(第 3 处同型缺陷)三处统一走该 helper。
② CallGenCBuiltin 1065 asm-out 全局变量回退:原把 find_global_in_module 的 GlobalVariable* 直接赋给 llvmlite.Value* 变量(不相关类;且 GlobalVariable 字段序为 Name→Ty,Value 为 Ty→Name,旧无条件 bitcast 会让 .Ty 读到 Name,后续 alloca.Ty.Pointee 全是错位数据)⇒ 改走 c.Addr(模块全局) 分支同款写法 make_global_ref(pool, Name, Ty) 构造带引号的 Ptr(Ty) Value 引用,同时修掉该错位读取。
|
2026-09-28 17:16:57 +08:00 |
|
TermiNexus
|
23428b63a5
|
fix(CallGenCall): 虚表/函数类型参数链表节点误注解 Function* → ParamNode*(Vipeye 143/146/179/184)
includes/llvmlite/__types.vp: new_param_node -> rawptr[ParamNode]、paramnode_set_next/Struct/Func 的 params 形参均为 rawptr[ParamNode];本处 vt_first/vt_prev/pn/fp_first/fp_prev/fpn 误注解为 llvmlite.Function*(不相关类)⇒ paramnode_set_next / Struct / Func 三处实参被判 struct↔struct 隐式转换禁止。
修法:6 处注解改 llvmlite.ParamNode*(改类型即根治,不用强转)。
|
2026-09-28 17:04:57 +08:00 |
|
TermiNexus
|
4807012bd8
|
fix(CallGenBase): struct 字面量字段链表节点误注解 Function* → ParamNode*(Vipeye 922/927)
事实:includes/llvmlite/__types.vp 里 new_param_node -> rawptr[ParamNode]、paramnode_set_next(node: rawptr[ParamNode], nxt: rawptr[ParamNode])、Struct(fields: rawptr[ParamNode], ...),而本处 th_st/tt_st/en_st 被注解成 llvmlite.Function*(Function 与 ParamNode 是不相关类)⇒ 严格指针规则下这两处实参传递被判「struct↔struct 隐式转换已禁止」。
修法:把注解改成真实类型 llvmlite.ParamNode*(不需要、也不应该 t.CPtr 强转——变量本来就是 ParamNode,强转只是把类型错误重新掩盖)。
|
2026-09-28 17:02:35 +08:00 |
|
TermiNexus
|
9c427aa548
|
fix(CallGenCall): 拆开 vtable_base 类型推断的变量复用(LLVMType* 与 StructEntry* 不可同一变量)
严格指针规则下 struct↔struct 隐式转换已禁止(仅允许派生→基类上转),原写法把 get_struct_type_from_value 的返回(LLVMType*)赋给 vc_entry: StructEntry* 再转手交给 find_struct_by_type,靠的是旧的无条件 bitcast。
改为各用独立变量(vb_ty / sp_ty),语义与改前逐字一致(仅去掉两次隐式 bitcast)。
|
2026-09-28 16:54:25 +08:00 |
|
TermiNexus
|
3bed3a70a6
|
docs(len): len() 两条 fail-fast 报文措辞与 TPC 逐字对齐(行为零改动)
补上「只支持 定长数组/数组指针、i8*(str/bytes)、带 __len__ 的结构体」+「非 i8 裸指针没有长度语义」的正确做法提示,与 TPC HandlesExprBuiltin._LEN_SUPPORTED_HINT 一致,便于用户对照两侧报文。
|
2026-09-28 15:53:09 +08:00 |
|
TermiNexus
|
be1acdb602
|
feat(cast): 放行数组退让([N]T* → T* 单向),与 TPC 同口径
新增 _is_array_decay(复用 is_array_type + LLVMType.Array 解构 + AssignGen._stg_ty_equal),在 _pointee_convert_reason 的非基本分支里紧接 _is_inheritance_upcast 之后调用
与 TPC 真值表一致:数组→元素指针 ALLOW、反向 DENY、多维只退一层;其余规则(通用指针/层数/完全相同/None/构造物化/标量无损/继承上转)未动
|
2026-09-28 15:38:42 +08:00 |
|
TermiNexus
|
e2c4c7645e
|
fix(cast): 补继承上转豁免(Derived*→Base* 放行),与 TPC 同口径
新增 _class_name_of_ptr_pointee(复用 StructGen.get_class_name_by_type)与 _is_inheritance_upcast(复用 StructGen.get_mro_chain:目标类名命中源类 MRO 链自身之后的祖先即放行,含多级)
在 _pointee_convert_reason 落入“非基本类型”分支前插入上转豁免;其余规则(通用指针通配/层数不同即禁/完全相同放行/None 任意/构造物化豁免/标量无损)未动;Base*→Derived* 与无关结构体仍禁
注:本提交顺带带入 App/main.vp 的既有版本号改动(0.0.5-dev.479,非本次会话产出)
|
2026-09-28 15:29:42 +08:00 |
|
TermiNexus
|
f03aea15c7
|
fix(cast): 规则③两侧对齐——聚合值↔指针也上闸,仅豁免构造物化(p: Point = Point())
TPV 的 coerce_to_type 两条“聚合值↔指针”路径不再无条件放行:新增 _ctor_call_agg_ty(AST 层识别构造调用,经 _value_node_of 下沉 + find_struct 取聚合类型)与 _same_agg_ty(委托 _stg_ty_equal);非构造物化一律 fatal_error,报文前缀与 TPC 逐字一致
无损口径以本文件 _scalar_convert_reason 为真源(int↔int 全向、float↔float 全向、int→float 需目标浮点位宽≥源整数位宽、float→int 有损),未动
已知未覆盖:泛型构造(Box(42))静态拿不到特化 struct 名 ⇒ 不豁免;部分 coerce 调用点不传 node ⇒ 可能误报(需实机确认)
|
2026-09-28 15:17:37 +08:00 |
|
TermiNexus
|
ee50ce61fe
|
feat(cast): 指针隐式转换按“同级+被指类型无损”判定(通用指针 t.CPtr/i8* 通配),并修诊断错位
_ptr_cast_reason 统一判据:层数不同→禁;完全相同类型→放行;任一侧通用指针(i8*/t.CPtr)→放行;否则按被指类型:非基本类型→禁,基本标量按既有无损规则(int↔int、float↔float、int→float 需目标浮点位宽≥源整数位宽、float→int 有损)
4 处禁令与新增的“指针→指针”处统一走 _value_node_of/_cast_fail_where:外层 Assign(kind=3) 下沉到真正被转换的值节点;列号按有符号打印(-1/未知打 -,不再出现 4294967295);附源码片段
未动“聚合值↔指针”那条路径(构造返回指针 load 回结构体,如 p: Point = Point()):LLVM 层无法与真实 Foo*→Foo 区分,禁止会直接编不过;规则③在该轴上的收紧待 AST 层区分构造调用后另做
|
2026-09-28 15:10:30 +08:00 |
|
TermiNexus
|
59a9fc5b1f
|
fix(cast): None 允许隐式转换为任意类型(修 p.fd_used[fd] = None 被“指针隐式转整数已禁止”拦下)
coerce_to_type 顶部新增单一短路判据 IsNoneValue(val, node):AST 为 CONST_NONE,或已物化的 null 常量(实机报错里 node 是外层 Assign kind=3、col=-1,拿不到 None 字面量节点,故以值判定为主)
指针目标保持既有 bitcast 形态(与 T* x = None 初始化一致);非指针目标按目标类型物化零值:整数 0 / 浮点 0.0 / 聚合与其余用 ConstZero
覆盖范围:App/** 下真正 fatal 的指针/整数禁令只有 coerce_to_type 内 4 处,均在短路之后;CallGenDispatch/ExprGenAttr/CallGenLib 等命中都是注释或不报错的原样返回,无遗漏
未动指针层级/被指类型的转换规则(待确认后另行实现)
|
2026-09-28 14:59:31 +08:00 |
|
TermiNexus
|
dfae2f090c
|
refactor(return): 移除 @c.CReturn 处理,改为遇到即 fatal_error(只保留 -> tuple[...])
FuncGenBase:整体删除 _resolve_creturn_ret_ty,新增 RejectCReturnDecorator(兼容 @c.CReturn(...) 与裸 @c.CReturn 两形态;命中即 TypeGenErr.fatal_error,报文指向 -> tuple[ty1, ty2, ...])
FuncGenDef:前向声明与定义两处调用点改为调用 RejectCReturnDecorator,删除随之失效的注释;周围类型解析主干(-> 注解、State/CExport、无注解 fail-fast)逐字未动
Converter:删除 _PyiCreturnArgs 与其“无 -> 注解则合成 -> tuple[...]”的调用点,改为 _PyiRejectCReturnDecorator(vpi 中仍带 @c.CReturn 即报错,提示用 --clean 重新生成该 .vpi)
注:TPV.vp.txt 是生成的单文件打包产物,需重新生成(本次未手改)
|
2026-09-28 13:57:05 +08:00 |
|
TermiNexus
|
d06c4d2c0e
|
refactor(main): 旧写法 a: static int 迁移为前置形式 static a: int
static 修饰符改为语句起始前置(TPC 与 includes 同步改动)后,本文件是 TPV 自身源码,必须一并迁移,否则新编译器编不过自己
|
2026-09-28 13:49:30 +08:00 |
|
TermiNexus
|
f2d7b748ea
|
fix(func): 末尾收尾的可达性判据只认 _ctrl_merge_reachable(删掉“穷尽通配臂即不可达”的错误推断)
症状:includes/llvmlite/__types.vp::_TypePrintDepth 末句 match ty:(各臂只 snprintf 后 br 到 merge)被生成 match.end: unreachable;llc 不给可达 unreachable 生成任何指令 ⇒ 执行掉进布局紧随其后的同一 switch 跳转表,用上一条 snprintf 的返回值 3 当 tag 取 table[3]=Array 臂 ⇒ 把 Int 的 Bits(32) 当指针递归解引用 ⇒ AV at 0x20(裸 0xC0000005;ASan 下同一崩溃被转为 0x80000003 = -2147483645)
根因:last_is_ctrl and (_ctrl_merge_reachable == 0 or MatchHasWildcardArm(...)) 的“追加92”通配臂子句——穷尽性只保证匹配总能命中某臂,不保证各臂都终止且不 br 到 merge;而 _ctrl_merge_reachable 恰是逐臂真正 br end_bb 时才置 1 的精确信号(MatchGenMixin:717 写回)
修法:两处收尾判据(FuncGenDef 模块级函数 / ClassGenVTable 方法)都只在 _ctrl_merge_reachable == 0 时 build_unreachable;merge 可达时走既有分支正常收尾(void→ret void;无注解→ConstZero;有非 void 注解→fail-fast,不发明返回值)
删除随之失效的 MatchHasWildcardArm 与其私有 helper _IsWildcardPattern(全仓已无引用)
|
2026-09-28 12:41:04 +08:00 |
|
TermiNexus
|
5e100e2195
|
fix(match): REnum 变体字段绑定不再静默跳过(__types.vp bits NameError)
根因:_handle_renum_match step6 用 renum_name 查 struct 且不校验 Ty;拿不到 entry/Ty 时 step7 的 _bind_variant_fields 被整段静默跳过 -> case 绑定名在 body 里未定义,最终只报 NameError(bits),真因藏到下游
1) 名字回退:变体表与 struct 注册都按裸类名,而 renum_name 来自注解 SourceName(Attribute 可带模块限定名)-> 精确查找失配;与 tag 查表同一裸名推导(tag_cls_bare)
2) 新增 StructGenMixin.find_struct_entry_with_ty:跳过 D30 重注册时就地中和的旧 entry(Name[0]=0/Ty=None/FieldCount=0),避免命中它拿到 Ty=None
3) 禁止静默:仍有 REnum 判据为真却无法绑定时 fail-fast,打印 class/查表名/entry/FieldCount/ty_present(对齐 D30/D32 的响亮失败口径)
|
2026-09-27 23:58:15 +08:00 |
|
TermiNexus
|
a79e723e8d
|
fix(dwarf): DIFile 改用绝对路径,栈转储显示完整路径并回读源码行
根因:CurrentFile 是项目相对路径(./Test/LLvmLiteTest/App/main.vp),LLVM 把该目录写成 CU 的 DW_AT_comp_dir,主文件条目用 dir_index: 0 指向 comp_dir;stackmap 写入端只解析 --debug-line(无 comp_dir)⇒ 行记录退化成裸名 main.vp,运行期既显示不全也无法按路径重读源码行
改法:DIFile filename 保留整条绝对路径(相对路径先经 w32file.GetCurrentDirectoryA 前置 CWD,与 Repl.vp 同款低层调用,不经 os._mbuddy);directory 另存目录前缀。无论 LLVM 保留整条 name 还是拆成 dir+basename,写端都得到绝对路径,故无需改写入端
|
2026-09-27 19:18:16 +08:00 |
|
TermiNexus
|
bb864dff6f
|
fix(traceback): stackmap 的文件名全部退化为 ?? —— _tb_parse_dec 不跳前导空格
dwarfdump 的方括号索引右对齐(file_names[ 1] / include_directories[ 12]),_tb_bracket_idx 把 ' 1]' 交给 _tb_parse_dec,首字符非数字使循环体一次不进 -> 全部 pidx=0;行记录 fidx=1..N 永不匹配 -> 每条记录落到 '??'(实证 9146/9146 条共用同一个 '??' 串,而函数名/行号均正确)
_tb_parse_dec 增跳前导空格与制表符(修复文件名与目录索引两处)
dir_index: 偏移 st+9 指向冒号本身,恒解析为 0 -> 相对文件名拼不出绝对路径;改为 st+10
|
2026-09-27 19:01:23 +08:00 |
|
TermiNexus
|
31898ab4a5
|
fix(stubmerger): define→declare 降级时剥掉行尾函数级元数据附加(!dbg !N)
llc 对 declare 不接受元数据附加,报 expected = here(实证 LLvmLiteTest 949685246c8e241c.ll:898:104 的 declare ... !dbg !71)
根因:降级只删尾部 ' {',源 define 头行的 ' !dbg !71' 被原样抄下;declare 无函数体,!dbg 无意义(FunctionPrint 对 declare 从不打印 !dbg)
判据:参数表之后、括号深度 0、不在双引号内的 ' !';连同前导空白一起截断
|
2026-09-27 18:30:39 +08:00 |
|
TermiNexus
|
66e697e8df
|
feat(codegen): 模块级 extern 全局生成外部声明(@裸名 = external global T)
注解含 t.CExtern/t.State → is_global_extern:裸名(无 SHA1 头)、Linkage=external、不写初始值、不建 storage
与 export 全局(本模块定义 + 裸名)区分;配合 includes f854f7e 的 export/extern 变量语法
|
2026-09-27 17:56:51 +08:00 |
|
TermiNexus
|
d82f24e17a
|
fix(diag): AST 解析失败日志行内联 行/列 + 原因
四处解析失败上报点(Phase2 的 [Phase A-pre-vpi]、Phase1 的 [Phase 1b-pre] 与单文件、main.vp 单文件)此前只打 AST 解析失败,看不到定位与原因;现内联 第 N 行第 M 列: <原因>,与 dump_parse_traceback 的完整 traceback 同源(原因由 includes/ast/parser.vp 的 _record_* 与 parse_tokens 出口兜底补记提供)。另:App/main.vp 同时带上你工作区既有的 define 迁移/版本号改动。
|
2026-09-27 17:32:34 +08:00 |
|
TermiNexus
|
e65f04f16b
|
fix(codegen): 字段表↔槽位一致性护栏豁免联合体
union 的字段表有 N 条(每成员一条)但 LLVM 布局只有 1 个槽位(成员全偏移 0、按最大成员定宽),二者本不相等;字段访问走 bitcast 到字段类型后的 GEP,不依赖槽位下标。误报实证:EdgeCaseTest 的 class Data(t.CUnion)(i_val/f_val 两成员 → 1 槽)被护栏拦下。
|
2026-09-27 17:26:04 +08:00 |
|
TermiNexus
|
0279965074
|
fix(codegen): 指针强转基座 T*(x) 的字段读写补按需过滤类名通道
(ast.Call*(vinner)).IsVolatile 报属性写入失败:T*(x) 被 parser 的 _consume_ptr_suffix_call 解析成 (T | t.CPtr)(x) 强转调用,结果类型是联合简化后的 i8*,lookup_field(i8,...) 必失败,而按需过滤的类名提取只认 Name/Attribute。新增 _base_class_from_cast_base:从强转注解(func 是 BitOr 联合)取裸类名,读路径、写路径、属性链递归父节点三处接入。取裸名而非模块限定名——lookup_field_by_class 的模块限定分支对「包名可解析、类注册在子模块」的形态会 fail-fast。
|
2026-09-27 16:02:04 +08:00 |
|
TermiNexus
|
beccb36b66
|
feat(codegen): 单目 & 支持对构造调用/函数调用结果取址
&ViperKernel() 此前被左值检查拒绝(只在 Name/Attribute/Subscript 放行)。构造调用 _translate_struct_ctor 返回的就是入口 alloca 的栈存储指针,取址即原样返回该指针;其它返回值落到入口临时槽 alloca+store。复用 translate_unaryop 已求值结果,避免构造被求值两遍(__before_init__/__init__ 跑两次)。
|
2026-09-27 15:15:59 +08:00 |
|
TermiNexus
|
4255ab9d32
|
fix(fstr): f-string 改回每站点栈缓冲 + 禁止逃逸,逃逸点改 stdlib 拷贝
ExprGenFstr._fstr_finalize:结果缓冲改回每站点栈 alloca(线程安全、零运行时依赖;每站点各建一个,站点之间不再共享),docstring 与文件头写明语义:f-string 结果是当前函数内的临时值。
GenApi 新增唯一判据 fail_if_fstring_escape 与唯一拷贝出口 escape_fstring_copy(stdlib.malloc + string.strcpy);逃逸位置接护栏:translate_return(函数返回值)、translate_assign(字段/元素/全局变量赋值)、handle_module_level_var(模块级 AnnAssign 初始化)。
编译器自身 7 处逃逸点(ExprGenBase._cast_fail_where 6 处、AssignGenMixin.const_assign_msg 1 处)改为 escape_fstring_copy 显式拷贝——正是造成 ASan stack-buffer-underflow in vsnprintf 的那条路径。
残留(已在 GenApi 头注释诚实记录):间接逃逸(把 f-string 传进会保存它的函数、或放进容器后带走容器)静态判不出;类字段默认值路径未接护栏。全仓自查:TransPyV/App、includes、ViperApps 均无 容器/字段/全局 存 f-string 的写法,也无残留 return f-string。
|
2026-09-27 14:45:28 +08:00 |
|
TermiNexus
|
72a3c483e4
|
fix(fstr): f-string 结果缓冲改为模块级全局,修 return f-string 的悬空栈指针
现象:--asan 下 ASan stack-buffer-underflow(READ size 1,地址落在栈左红区)in vsnprintf,栈为 ExprGenBase.coerce_to_type:409 的 f-string 报文;非 asan 构建表现为随机乱码或 0xC0000005。
根因:_fstr_finalize 用 _alloca_at_entry 在当前函数开一个 [FSTR_BUF_SIZE x i8] 栈缓冲并返回其指针;而 f-string 结果在全仓被大量 return 带出函数(ExprGenBase._cast_fail_where、AssignGenMixin.const_assign_msg、CallGenLib 报文构造等),返回后再作 %s 喂给 snprintf 即读已弹栈的帧;且同一函数内多个 f-string 共用同一个 entry alloca 会互相覆盖。
修法:结果缓冲改为每个 f-string 站点一个模块级可写全局 internal unnamed_addr global [N x i8] zeroinitializer,经 bitcast 取 i8*(与 ExprGenConst.create_global_string 同一构造路径,符号链接期解析)。被否决的中间方案记录在注释里:编译期池缓冲 + inttoptr 常量地址会把编译进程的宿主地址烘进 .ll,对产出程序无效,绝不可用。
已知取舍(注释中写明,与 C 的 static char buf[N] 惯用法同):同一站点反复求值且同时保留多个结果时后者覆盖前者;多线程避免共享同一站点结果。彻底消除需运行时字符串分配器(当前无)。
|
2026-09-27 14:33:54 +08:00 |
|
TermiNexus
|
ca5473304f
|
fix(gen): 结构体字段表与 LLVM 槽位一致性 fail-fast 护栏
新增 StructGenMixin.verify_field_slot_consistency:字段表条数必须等于结构体槽位数,且每条目 Ty 与 Index 槽位同类(指针性/整数位宽/浮点位宽);不一致即 fatal_error 并指名 类/字段/下标/两侧类型。由 lookup_field 第一遍调用。
背景(真实崩溃):模块 8a96a2885bae09ca(ExprGenOps)把 ast.Name.id 编译成 GEP 下标 9(该槽是 ctx,i32),同一次构建里 320b55907b889d59(AssignGenMixin)用下标 8(i8*),两者共用同一 %struct 布局。后果:nm.id 读成 ctx(ASTCtx.Store=1)- inttoptr i32 1 - strlen(0x1) - ASan access-violation at 0x1。
|
2026-09-27 14:00:18 +08:00 |
|
TermiNexus
|
12bd7b7a16
|
fix(gen): 收敛 static 跨模块拦截为独立方法,消除类型推断污染
新增五个独立方法承载 static 检查与登记:_CheckStaticCrossModule(mod.name 取值)、_CheckStaticCallCrossModule(mod.fn 调用)、_CheckStaticFromImport(from-import)、_RegisterStaticModuleVar(模块级变量登记)、_RegisterStaticFunc(函数登记)。调用点只保留一行调用——内联新增分支会改变超大函数的类型推断,曾导致 translate_attribute 后续 match obj_ptr.Ty 报指针隐式转整数已禁止。
删除 _resolve_module_attribute_global 内与入口检查重复的 static 拦截(其两个调用点均在 _CheckStaticCrossModule 之后)。
|
2026-09-27 13:12:22 +08:00 |
|
TermiNexus
|
dd56580855
|
feat(gen,static): static 符号禁止跨模块使用(定义侧登记 + 引用侧三处拦截)
语义 = C 的 internal linkage:static 符号(函数/变量)只在定义模块内可见,任何跨模块引用一律 fail-fast(NameError)。
- 登记表:CallGenBase 新增 StaticSha1Arr/StaticNameArr/StaticCount(PermPool 定长槽,与 CexportSha1Arr 同款)+ RegisterStaticSymbol/IsStaticSymbol(按 (符号名, 模块 SHA1) 精确配对,避免跨模块同名误判)。
- 定义侧登记:FuncGenDef 识别注解形态(-> t.CVoid | t.CStatic)与装饰器形态(@t.CStatic;裸 static def 已由解析层归一为装饰器)→ 登记函数名;TranslatorGenMixin.handle_module_level_var 识别注解形态(static x: int 已归一为 t.CStatic | int)→ 登记变量名。
- 引用侧拦截(三处,覆盖全部跨模块形态):ExprGenAttr.translate_attribute 入口统一拦截 mod.name(含 import 别名还原);CallGenMixin.translate_call 入口拦截 mod.fn(...) 调用(按 AST 形态一次覆盖 found_func/vpi/裸名兜底各分支);ImportsGenMixin.translate_import_from_names 拦截 from mod import name。
- 性能:三处检查均以 StaticCount > 0 快速短路——项目中无 static 符号时零开销(不触碰逐条线性扫描与 sha1 解析)。
- 同模块自引用(sha1 相同)与非模块基座(self.method / obj.field / Class.static_method)一律放行。
|
2026-09-27 12:58:51 +08:00 |
|
TermiNexus
|
424dbd7379
|
chore(gen): 加 [MODSHA1] 临时诊断定位 string.split 模块名解析失败(定位后删除)
在 translate_call 的模块限定分支加两条探针:
- [MODSHA1]:mod_ret_sha1 为 None 时打印 mod_path_ret / func_name / exact / suffix / ctrl_stdint(对照模块,必在 includes)——可区分 store 整体为空 与 store 有内容但缺该模块。
- [MODSHA1-D]:裸名兜底分支里,若 cl.func 仍是 Attribute(模块限定却解析不出模块的异常组合)则打印 mod_path_ret 与 func_name——覆盖 mod_path_ret 为 None 的情形。
同时把 mod_path_ret 的声明从 if 块内移到 if 外(与 mod_ret_sha1 一致),避免下游分支读未声明局部取到栈垃圾。
证据链:报错来自本函数 861 行(全仓唯一 fatal_if_unknown=1 的调用点),条件恒为 _resolve_module_sha1 对 string 返回 None;但 _sha1_map.txt 有 includes/string.vp、其 vpi 有 def split -> int、Phase1Main:390 是唯一写 map 处 ⇒ 静态无法解释,需运行时诊断。
|
2026-09-27 12:52:03 +08:00 |
|
TermiNexus
|
87f5b1026c
|
chore(gen): 删除 CallGenDispatch 的 [MDISP] 临时探针及其专用 import stdio
该探针(并排取证 __with_ctx.__enter__ 与 pool.alloc 的 H6 判据命中差异)为定位 MpoolOopTest 的「跨模块调用 pool.alloc 找不到模块 SHA1」临时加入,现缺陷已定位,探针与其唯一使用者 import stdio 一并移除;非 local 对象分派逻辑不变。
|
2026-09-27 12:32:52 +08:00 |
|
TermiNexus
|
9455db0eec
|
feat(gen,type): callable[] / callable[[]] / callable[[A,B],R] 与 t.Callable 逐点等价
- 判据单一真源:_SubscriptAttrIsCallable 扩为 _IsCallableSubscriptValue,同时认 Attribute(attr=Callable) 与裸名 Name(callable | Callable)。
- Subscript 分支在 Name 路径(泛型特化 / CArray / builtins typedef 兜底)之前拦截裸名 callable/Callable → i8*;否则 callable[] 会先撞 slice=None 的 fail-fast、callable[[]] 会被当泛型类名查空。
- TypeGenErr.try_extract_callable_ret 改用同一判据:callable[[A, B], R] 现在也会注册返回类型 R(可间接调用),无签名形态([]、[[]])仍返回 None。
|
2026-09-27 12:30:47 +08:00 |
|
TermiNexus
|
a76cf55a2d
|
feat(gen,type): 注解位置的小写裸名 callable 等价 t.Callable(i8*)
支持 func: callable = 函数名 的写法:Name 分支兜底 map_t_type 命中 callable → Ptr(Int8),与 t.Callable / t.Callable[] / t.Callable[[]] 同一 LLVM 表示(无签名函数指针,只取地址不作间接调用)。
同时明确大写裸名 Callable 同时服务 from t import Callable 与 Attribute 分支的 t.Callable。
|
2026-09-27 12:28:58 +08:00 |
|
TermiNexus
|
c387926977
|
feat(gen,type): 支持无签名函数指针 t.Callable / t.Callable[] / t.Callable[[]]
三种写法统一解析为 i8*(与带完整签名的 t.Callable[[A,B], Ret] 同表示;函数值按 TPV 惯例 bitcast 为 i8* 存储):
- map_t_type 新增 Callable → Ptr(Int8):裸 t.Callable 此前落空导致 AnnAssign 注解类型解析失败。
- resolve_annotation_type 的 Subscript 分支:slice 为 None 时先放行 Callable(t.Callable[] 走空下标解析),其它类型仍 fail-fast 缺少 slice。
- 新增 _SubscriptAttrIsCallable 判据。
无签名形态不注册返回类型(try_extract_callable_ret 对非 Tuple slice 返回 None)⇒ 只适用于取地址/内联汇编操作数,不作编译器间接调用。
|
2026-09-27 12:25:52 +08:00 |
|
TermiNexus
|
7c53a8744d
|
fix(gen,match): 穷尽 match 不再误报流程掉出末尾;default 臂直译不再经 def_arr 反查
现象:函数末句为 match 且含 case _: 穷尽臂、各臂均 return 时,仍报 TypeError 函数流程掉出函数末尾(ioctl 4 具体臂 + case _)。
- FuncGenDef / ClassGenVTable:收尾判据由「_ctrl_merge_reachable == 0」扩为「或末句 match 含无 guard 的 case _ 通配臂」。穷尽 match 不存在全臂不命中的路径,与 If/While 全分支 return 同语义,应生成 unreachable 而非 fail-fast。
- MatchGenMixin 新增 MatchHasWildcardArm / _IsWildcardPattern:识别 MatchAs(pattern=None)(含 as/or 组合),带 guard 的 case _ if c 不算穷尽。
- MatchGenMixin:_handle_simple_match / _handle_renum_match / _handle_sequence_match 三条路径改为 pass1 显式记录 default_case_node,default 块直译该节点;原实现经 def_arr[di] 反查 cases_list[di],collected 下标与原始下标在「有臂被跳过」时错位 → default_bb 空转 → merge 误判可达(同时 case _ 臂不生成 IR)。
|
2026-09-27 12:17:14 +08:00 |
|
TermiNexus
|
cf815b17de
|
feat(gen): volatile 构造写入落 LLVM volatile(逐字段 store + 构造三方法屏障)
值位置 volatile 前缀(a: int = volatile f() / a: S = volatile S(...))此前只在调用点无落点。LLVM 的 call 指令没有 volatile 限定符,故语义只能落在内存存取上:
- AssignGenMixin:赋值目标的结果槽按 volatile 存取(本次 store 立即带 volatile,并登记 VarEntry.IsVolatile 使后续 load/store 亦带);对已存在的 global/nonlocal/mod_glob 条目在分支前统一登记。
- CallGenCtor:_translate_struct_ctor / _translate_struct_ctor_kw / _translate_renum_construct / _apply_struct_defaults 增加 is_volatile 参数,清零、tag、默认值、逐字段 store 全部带 volatile;_translate_generic_ctor_call 直接从 cl.IsVolatile 取。
- CallGenCall._call_method_on_ptr 增加 is_volatile 参数:__new__/__before_init__/__init__ 的写入发生在被调函数内部,调用点无法逐条附加 volatile,故在调用后对该 self 指针追加一次 i8 volatile load 作为内存屏障,使构造写入不被优化器消除或跨越重排。
- CallGenMixin / CallGenDispatch:结构体、关键字、泛型、REnum 构造调用点统一透传 cl.IsVolatile。
|
2026-09-27 12:01:22 +08:00 |
|
TermiNexus
|
7d28c9649e
|
feat(gen,err): CastError 定位到出错表达式;vpi 生成 fail-fast;函数属性接受直接形态
- ExprGenBase:新增 _cast_fail_where,指针/整数隐式转换失败时打印出错表达式与列号(多实参调用可定位到具体实参,如 Name 'toggle_ptr')
- Converter:import / from-import 别名列表为空、Alias 指针为空、name 为空分别 fail-fast,不再写出 import , 这类残缺 vpi 行(该残缺会让包重导出注册失效,报出与根因无关的 NameError)
- FuncGenBase.extract_func_attrs:接受直接 @t.attr.<name> 装饰器形态(与类侧 _has_decorator 同口径),使 inline def 在无 import c 的文件里也生效
- 附:CallGenDispatch 内保留一处临时 [MDISP] 探针(MpoolOopTest pool.alloc 定位用)
|
2026-09-27 11:41:11 +08:00 |
|
TermiNexus
|
f084da7c01
|
feat(gen): 重复声明改为无条件失败(不再比较类型),global 后再注解同样报错
- 判据改为:模块级已有同名变量 + 函数内再次用注解声明同名变量 ⇒ TypeError 重复声明,不再比较注解类型是否与全局一致(此前仅在类型不一致时报错)
- 有 global/nonlocal 声明后再带注解声明同名变量也报错(注解与既有全局声明重复)
- 检查点前移到注解解析之前(紧跟 REPL 分支),保证优先于 coerce_to_type 报错
- 合法写法只剩两种:global + 无注解赋值修改全局;或换不重名的局部变量
|
2026-09-27 08:55:08 +08:00 |
|
TermiNexus
|
78fc7313fb
|
feat(gen): 同名全局 + 注解冲突优先报重复定义
- translate_annassign: 函数内(无 global/nonlocal、非模块级)再次注解同名变量时,若注解类型与模块级变量类型内容不一致 ⇒ TypeError 重复定义 fail-fast,不再延后到 RHS 的 coerce_to_type 报无关的「指针隐式转整数」(PointerTest/App/main.vp:46 _g_ptr: int = None,全局已是 t.CUInt32T | t.CPtr)
- 注解与全局一致时仍按 Python 语义遮蔽为独立局部变量(既有行为不变)
- 该检查走 _stg_ty_equal 内容比较(TypePrint),非地址比较,避免 Int32()/Ptr() 新实例造成误判
|
2026-09-27 08:50:18 +08:00 |
|
TermiNexus
|
f0309e4904
|
fix(gen,renum): 指针操作符目标写入落盘 + REnum tag 三侧口径统一,修 kind() CastError
- AssignGenMixin: 补 UnaryOp(Deref) 赋值目标分支(*p = v / *&x = *&y),非 Deref 的 &x/-x/~x fail-fast;*p += v 真正实现;Tuple/List 目标合并
- CallGenDispatch: kind() 改四级 REnum 判据(变体表 / struct __tag / pointee 带 __tag / X.field 声明类型反推);修正 build_load 第一参数误传指针类型 rk_tag_p(生成 load i32*, i32* 使返回值 Ty 为 i32*,导致 CallGenLib.vp:355 vk_a: int = val.Ty.kind() 报指针隐式转整数的 CastError),rk_load 分支同步改 rk_ty.Pointee
- CallGenCtor / MatchGenMixin: __tag 读/写/比统一取字段声明类型 FieldEntry.Ty
- Test/FieldReadTest: 字段读取探针
|
2026-09-27 00:19:44 +08:00 |
|
TermiNexus
|
bcf66edebe
|
fix(vpi): 防环访问表表满不再静默丢标记,改为 ×2 扩容 + fail-fast
表满时曾静默 return(丢标记)⇒ 防环失效 ⇒ 递归闭包反复重解析同一批 .vpi,每个 vpi 的 Lexer/Token/AST 都从池分配且本段不回收 ⇒ 单次 translate 吃数百 MB ⇒ 1 GiB 主池 OOM
改为可扩容(ResetVpiTypedefVisited 同步复位容量),分配/扩容失败立即报错终止
|
2026-09-26 21:25:23 +08:00 |
|
TermiNexus
|
373a20c3e5
|
perf(prof,gen): 编译热点优化 + 内存池 OOM 诊断接线 + REnum 指针载荷修正
CallGenBase: 模块返回类型文本表改单趟登记+查找,find_func_in_module 合并为单趟链表遍历(PROF 热点)
BuildPipeline: ensure_dir 增加快速路径(已存在目录直接返回)
AssignGenMixin/Translator: alloc 失败打印 Pool/PermPool 统计与阶段上下文(SetAllocCtx)
CallGenCtor: REnum 指针载荷补显式 build_ptrtoint 再 coerce/store;新增 DebugInfoGen.vp
其余为历史累积改动一并入库
|
2026-09-26 19:27:23 +08:00 |
|
TermiNexus
|
676c19c362
|
feat(asm,err,typedef): 支持 __asm__/__llvmir__ 裸名与 typedef 语法糖;解析报错统一 Python 风格 traceback
CallGenCBuiltin/CallGenDispatch: __asm__/__llvmir__ 裸名调用,asminp/asmout/irinp/irout 与裸 ASM_DESCR。
AssignGenMixin: 支持 define NAME: T = V 形式的 CDefine 浮点值恢复;负浮点(-1e308)剥一层 UnaryOp(USub)。
Phase1Main/Phase2: AST 解析失败改调 GenApi.dump_parse_traceback(Traceback + File/行 + 源码行 + caret)。
TypeGenResolve/TypeGenCType: typedef 文本扫描统一支持 typedef 语法糖(builtins/库/单文件三处共用同一解析)。
|
2026-09-25 13:11:16 +08:00 |
|
TermiNexus
|
a7af34bd7e
|
修正了部分代码的表达方式,最后可用版本,mlirlite 已基本完善
|
2026-09-23 17:41:49 +08:00 |
|
TermiNexus
|
951b89be36
|
修正了部分代码的表达方式,最后可用版本,正在为 mlirlite 做准备
|
2026-09-23 16:09:32 +08:00 |
|
TermiNexus
|
a5ceb3d4eb
|
增加 JIT REPL
|
2026-09-21 16:17:19 +08:00 |
|
TermiNexus
|
9910e05760
|
修复了一些错误,更改了一点语法
|
2026-09-18 20:00:40 +08:00 |
|
TermiNexus
|
9e2ccbfab7
|
将部分 | t.CPtr 修正为 rawptr[T]
|
2026-09-18 17:56:24 +08:00 |
|
TermiNexus
|
eb01a45024
|
修复了一些问题
|
2026-09-17 14:51:18 +08:00 |
|
TermiNexus
|
cb0836de8a
|
清理了 t.CVoid
|
2026-09-16 16:06:48 +08:00 |
|
TermiNexus
|
9a191daa8d
|
错拼 rowptr 改为 rawptr
|
2026-09-16 11:42:28 +08:00 |
|
TermiNexus
|
7cba4cbc95
|
chore: 清理超长历史注释,并一并提交并行会话的代码改动
注释清理(65 文件 / 约 -2578 行 / 约 516 处):删除/压缩叙述式历史注释——多行根因叙事、工作代号段(D25/D30/N11/B5/S4/阶段E 等)、改前改后与先例叙述、逐条推导块,压成一行讲清作用信息;契约类注释(用途、参数与返回、关键约束与不变量、IR 结构说明)与被注释掉的代码一律保留
存疑 标记 6 处一字未动:StubMergerStore.vp、VpiReader.vp、VLogger.vp、AssignGenMixin.vp、CallGenLib.vp、CallGenLeafKit.vp
本次一并带入并行会话的代码改动(同批文件,按文件粒度无法拆分):fileio.File -> rowptr[fileio.File] 等
已知副作用/残留:① CallGenDispatch.vp 有 2 行非注释行的行尾被 LF->CRLF 规范化(纯字节变化,无文本改动);② core/Gen 区约 24 处压缩因并行会话整文件覆写被写回原样,尚未生效(StmtGenCifMixin/ClassGenVTable/FuncGenDef/ClassGenEnum/StructGenMixin/TypeSpec 等)
清单与复跑判据见 Debugger/comment_cleanup_summary.md(该目录不受版本控制)
|
2026-09-16 11:27:05 +08:00 |
|
TermiNexus
|
b28f20cce7
|
chore: 清理调试打印与失效 import
CallGenCall.vp: 前次清理 DBG 打印后 import stdio 已无使用者,删除(该文件全文无 stdio. 调用,亦无经本模块的外部访问)
Test/App/nested_match_test.vp: 删除 _init_mbuddy 与 test_single_match 中的 8 处 [DBG] 进度打印;该测试的判定只看 --- Test N --- / OK / FAIL 行,test_main.vp 亦只取返回码,无断言引用这些文本
未改动任何逻辑(保留 FAIL: malloc for arena failed 等错误分支的真实输出)
|
2026-09-16 10:32:40 +08:00 |
|
TermiNexus
|
429de97083
|
fix(call): 泛型特化类跨模块 declare 按模板 vpi 注解对齐形参口径
特化名({sha}.list[str].__init__)在 vpi 参数注解缓存中无精确键——键段取自 class 行文本,只存模板 list[T]——定义侧形参注解取不到,调用点 declare 停在调用点实参口径(elem_size 字面量 i32 vs 定义侧 t.CSizeT=i64;池实参 MemBuddy*/i8* vs 定义侧 MemManager*),并经 .stub.ll 传播到未调用该函数的消费方模块
新增 VpiReader._resolve_vpi_param_annot_seg_template:按 {sha1}.{base}[T].{method} 定位模板条目、用特化实参替换段内类型形参 token 后再解析,未命中返回 None 不兜底;_coerce_args_to_def_params 在精确键未命中且类名含 [ 时改走模板退查并置 tpl_src,使 _coerce_arg_value_to_ty 对同为具体结构体指针但基类型不同补 bitcast;_call_method_on_ptr 的跨模块分支补建 declare 前的 coerce(先例 a83d183 的三处调用点)
同时把 {sha}.{cls}.{method} 的切分由首个 . 改为末个 .(CallGenLib/CallGenBase 两处):method 不含 .,首个 . 会把含模块限定名的类型实参截断(list[3571eabe5a83d798.AST|t.CPtr] 截成无 ] 的类名 ⇒ 模板退查必 miss)
另修 VpiReader 一处 double-free:_subst_template_arg 早退分支返回入参本身,替换前释放原缓冲需先判同一性(三条路径各释放一次)
效果: 危险级签名不一致 TransPyV 8->4->0、Test/AstTest 6->2->0,ZlibTest/WebTest/FakeDuckTest/ListTest/GenericTest2/VectorGenericTest 保持 0;4 个目标符号 define/declare 共 148 处全部统一为 MemManager*+i64(0 处旧口径);自举达全树逐字节不动点(exe sha256 相同、temp/** 635 文件零差异);AstTest 及既有测试全 PASS 且无 ASan 报告
|
2026-09-16 09:31:57 +08:00 |
|
TermiNexus
|
a83d183abb
|
fix(gen/call): 跨模块调用 SSA 整型实参按定义侧形参扩宽
declare 由调用点实参链建立,而 _coerce_arg_value_to_ty 对非常量(SSA)整型此前原样返回,导致 declare/call 停在调用点窄宽度(string.strncpy 第三参 i32),与定义侧(vpi 注解 n: t.CSizeT => i64)不一致,并经 .stub.ll 传播到未调用该函数的消费方模块
现按源符号性 zext/sext 扩宽(真源 ExprGenBase._zext_or_sext_val,先例 CallGenCtor._translate_t_type_cast),实参 AST/trans 下传;self_off 模块级 0、方法 1
效果: WebTest 危险级签名不一致 1 => 0
|
2026-09-15 23:58:40 +08:00 |
|
TermiNexus
|
31b8dccffd
|
fix(stub): declare 侧识别 t.CPtr[...] 段,与定义侧指针层级口径对齐
t.CUInt8T | t.CPtr[t.CPtr] 在定义侧(TypeGenResolve._is_cptr_subscript)按指针层级合并得 i8**,但声明侧段判据只认整段等于 t.CPtr/CPtr,下标段落入普通段解析后取首段 => i8,造成跨模块 define/declare 签名不一致(实参 1 字节 vs 写入 8 字节)
新增 t.CPtr[/c.CPtr[ 段的识别与递归解析(与同文件 rowptr[...] 分支同构),数外层 Ptr 层数 N 后按 Ptr^N 合并;裸 t.CPtr 段路径未动,未放宽 fail-fast
注: TPC 侧 LLVMTypeMapper._resolve_bitor 与 SymbolUtils.IsCPtrNode 同源缺陷未改,两套编译器需同时修以免产物分叉
|
2026-09-15 23:58:39 +08:00 |
|
TermiNexus
|
de86a1ed70
|
fix(gen/for): 负数字面量 stop 的 range 循环退回有符号谓词,修复 _find_provider 死循环
stop 边界为负数字面量(如 range(top - 1, -1, -1))时,3.6 的边界推导把无符号 start(UINT64 字段)判为无符号循环,负步长分支随即由 sgt 覆盖为 ugt;而比较在 stop 类型(i32)上进行,-1 在无符号域是 UINT32_MAX,条件恒假 => 循环体成为死代码。_withcontent._find_provider 因此恒返回 NULL,with 上下文的 __mbuddy__ 注入永不生效(FakeDuckTest Test 9 FAIL,随后 _str.upper 解引用 NULL vtable 触发 ASan READ)
新增 3.7: stop 为负数字面量时撤销无符号谓词(判定与既有 step_neg_const 同口径),退回 slt/sgt;正步长非负 stop 的既有 ult 优化与 range(stop) 单参形态不受影响
|
2026-09-15 22:45:28 +08:00 |
|
TermiNexus
|
296f6a739e
|
fix(gen/renum): REnum 补齐 Assign 形式无载荷变体的变体表注册
根因: _translate_renum_def / _register_renum_variants 只认嵌套 ClassDef 变体,Empty = 1 / None_ = 0 这类无载荷 Assign 变体既不计入 variant_count 也不写变体表 => match 查不到 tag(-1) => 本会话硬校验 fail-fast,此前则静默丢 case(Test\EdgeCaseTest 旧产物 ac0d686cb2cc783b.text.ll:117-119 仅 1 个 case,臂体 match.case.11.1 结构性不可达)
修复: 按 TPC 口径(HandlesClassDef._EmitREnumLlvm / SymbolExtractor)两遍处理——先取 Assign 显式值上界,ClassDef 变体从 max(显式值)+1 起编号(避免与显式值撞号),Assign 变体 tag = 显式整数值;表槽号与 tag 值解耦。纯 ClassDef REnum(含 LLVMType)生成结果不变。硬校验保留不动
|
2026-09-15 22:45:28 +08:00 |
|