TermiNexus
|
2b4679073e
|
维护基线
|
2026-10-17 23:27:00 +08:00 |
|
TermiNexus
|
15f77da9d3
|
chore: 改名同步 TransPyV -> ViperC(源码/配置内的纯替换)
|
2026-10-12 15:06:48 +08:00 |
|
TermiNexus
|
5a0eecc22f
|
feat(core): 栈地址逃逸检查(LifetimeError)与标量→聚合 fail-fast
- MemoryOps._IsFrameStackAddr 判据 + HandlesReturn/HandlesAssign 汇点挂钩:禁止栈地址逃逸(&local 与数组退让);新增 LifetimeError(FailFastError) 承载该错误类。 - MemoryOps._coerce_value:标量(整数/浮点)不得初始化/赋值给聚合类型,改为 FailFastError(旧行为让 _store 抛 TypeError,非 strict 下被静默吞掉,聚合未初始化)。
|
2026-10-08 12:10:24 +08:00 |
|
TermiNexus
|
9656bb161a
|
feat(codegen): 值引用自动取址收口到 _adjust_args,补齐 vtable/方法/构造等路径
查表键统一为真实发射出的函数名:FuncGen._adjust_args 开头以 func.name 调用 _apply_auto_addr,于是 direct/vtable 虚分派/构造/静态/__call__/下标赋值/c.Addr 构造/闭包/泛型/方法兜底全部自动取址,不再依赖每个调用点手写;同时删除 16 处冗余显式取址(t.CAutoPtr 的 always 模式不幂等,重复应用会多包一层指针)。登记侧:HandlesImports 把模式登记提前到 FuncName-in-Gen.functions 早退之前并按 func.name 主键写表,_TryLoadStructFromStub 改为无条件调用;HandlesFunctions 在函数对象就绪后按真实名登记,并在 _EmitFunctionForwardDeclLlvm 把逻辑名下的模式播种到 MangledName,覆盖同模块先调用后定义的场景。
|
2026-10-07 19:59:36 +08:00 |
|
TermiNexus
|
2514cee4c9
|
feat(lang): 同步 cif/celif/celse、值引用注解与 assert 改译 testcheck.check
vast 双路径(Python Parser/ExprParser 与 C 扩展 vast_c.c)新增 cif-celif-celse 语句族与 &T / &temp T 参数注解解析,_parser.pyd 已同步重编。HandlesIf 改认 @CIf 标记并做编译期常量求值,含运行时变量一律 fail-fast,同时删除 c.CIf 家族(c.py)。HandlesAssert 合成 testcheck.check(cond, None, msg) 调用,非字符串字面量消息报 TypeError。FuncGen 调用点按形参模式自动取址(ref 仅接受左值,右值 fail-fast;temp 物化临时栈),SymbolUtils/TypeAnnotationResolver 提供模式识别;t.py 删除 CNeedPtr。
|
2026-10-07 19:03:29 +08:00 |
|
TermiNexus
|
ecd336771f
|
fix(FuncGen): base/字段偏移一律按"重名条目不占槽位"算,修 MatchCase 偏移 6(应为 7)
类别:a(编译器缺陷)
现象(早前现场,本轮定位):
TypeError: [fast-fail] len(mcc_pre.children) 分派 'list[….AST*].__len__' 失败:
类='MatchCase' 偏移=6 接收者类型=i32
判据(磁盘实证):
· MatchCase 的 body 在 temp 与**全部** output stub 中都是 **10 槽**
(vtable + AST 的 7 字段 + pattern/guard)⇒ `children` 的正确偏移 = base(1) + 表内下标(6) = **7**。
· 观测到 6 ⇒ base 被算成 0 ⇒ `_member_base` 的 `_Delta = 槽数 - 表长` 为 0,
即**表长 = 10**(9 个不同字段 + 1 条重名条目),而不是 9。
· 重名条目是**产物**:源码层面的字段名遮蔽已由 HandlesClassDef 的
"字段名遮蔽 fail-fast"(:1083)拦下 ⇒ 表里的重名只可能来自"展平残留
(半截祖先块,已由 2e7bac18 在插入点剥除)/ 同一字段被两条收集路径各登记一次"。
修复(与 `_get_member_offset` 配对路径已有的"重名条目不占槽位"同口径,全线统一):
· `_member_base` 的长度校准改用**去重名数**(`_Delta` 不再被重名条目冲掉 ⇒ base 正确);
· 新增 `_MemberSlotIndex(Members, FieldName)`:取"首个同名的**去重**下标"
(重名条目不计槽位),并把 `_get_member_offset` 中**全部 12 处** "base + 表内下标"
站点改为调用它(含继承链回退、REnum 变体搜索、stub 重载后、_PreRegisterClassMembers
之后等分支);"最后回退"里的 `_num_members_final` 同步改为去重计数。
· 对无重名的表,取值与改前**逐字相同**(去重下标 == 原始下标)。
核验:py_compile + compileall 全 lib 通过;离线冒烟(真实方法、未绑定实例调用):
含 1 条重复 'children' 的表上 `children -> 6`、`guard -> 8`、缺名 -> -1;
去重名数 9 ⇒ `_Delta = 10 - 9 = 1` ⇒ base=1 ⇒ `children` 偏移 7(与 body 10 槽一致)。
未放宽任何 fail-fast。
|
2026-09-30 18:44:48 +08:00 |
|
TermiNexus
|
49930c56c7
|
fix(LLVMCG/HandlesExprAttr): REnum 变体字段按唯一变体键取槽 + 修 _PointeeMatchesStruct 的「同模块前缀」误判
【a 编译器缺陷】两处根因,同一现场(CallGenDispatch.vp:787
`len_ap: llvmlite.LLVMType* = len_val.Ty.Pointee`):
1) `_PointeeMatchesStruct` 只比 sha1 前缀 ⇒ 把**同模块的兄弟类**当成同一个类
(`50741ad4b4b0934d.ParamNode` 与 `50741ad4b4b0934d.LLVMType` 前缀相同,同出
includes/llvmlite/__types.vp)。结构体分支迭代 Gen.structs 时先命中 ParamNode
(它在 __types.vp 里声明更早)⇒ `_get_member_offset('Pointee','ParamNode')`
直接 fast-fail,报出与真因无关的类名。判据收紧为:**同一对象** 或 **IR 全名逐字相同**
(前缀标识的是模块,不是类)。同短名不同前缀(同一类的另一模块实例)仍由调用点的
`_UniqShortCN`(同短名候选唯一)放行,不受影响。
2) REnum 的变体字段在旧路径上无处可取:'Pointee' 只属变体键 'LLVMType_Ptr',
而主类 'LLVMType' 的成员表为空(HandlesClassDef:716)⇒ 即使接收者判对类名也必 fail-fast。
新增 `FuncGen._RenumVariantFieldOwner`,在 `_get_member_offset` 里当"主类不声明该字段"时改按
变体键取偏移。判据(逐条可查):① 主类经 `_IsRenumLayoutClass`(唯一判据源)判为 REnum;
② 变体键固定 `<主类短名>_<变体名>` 且成员表**首项恒为 `__tag`**(唯一产源:
HandlesClassDef._EmitREnumLlvm 与 HandlesImports 的 REnum 跨模块注册);
③ 恰有**一个**变体声明该字段(多个 ⇒ 不猜,照常 fail-fast);④ 变体 struct 已注册。
槽位正确的依据:变体 struct 的 body 是**主 REnum 镜像** `{i32 __tag, <max_variant_payload>}`,
变体成员表 `[__tag] + 载荷` 与主 REnum 槽位一一对应。
3) 载荷槽按**最大变体**宽度物化('Pointee' 槽是 i64),而字段本身声明为指针 ⇒
新增 `HandlesExprAttr._RenumVariantPayloadType` / `_CoerceVariantPayload`,在
`_gep_and_Load_member` 载入后按字段声明类型收口(int→ptr: inttoptr;ptr→ptr: bitcast;
int→int: trunc/zext;不可转换原样返回,交下游照常 fail-fast)。非 REnum 变体键逐字不变。
冒烟(临时脚本已删):_PointeeMatchesStruct 5 例、_RenumVariantFieldOwner 7 例、
载荷类型与转换 6 例、_get_member_offset 钩子(绑定真实方法)5 例 —— 全部通过。
|
2026-09-30 12:46:37 +08:00 |
|
TermiNexus
|
a1c43a7b3b
|
chore(诊断): MemberLookupFailFast 补取证——字段所有者、类键/实例名、登记为该类的变量与实际 pointee
现场:CallGenDispatch.vp:787 `len_ap: llvmlite.LLVMType* = len_val.Ty.Pointee`
报 "[fast-fail] 属性 'Pointee' 在类 'ParamNode' 中找不到(class_members=2 个:
['Next','Ty'])"。'Pointee' 实际属 LLVMType 的 REnum 变体镜像字段(LLVMType.Ptr.Pointee),
而 ParamNode 只有 Next/Ty ⇒ 说明**读取时的接收者类名被判成了 ParamNode**
(`len_val` 的注解与 RHS 都写的是 `llvmlite.Value*`,Value.Ty 才是 rawptr[LLVMType];
ParamNode.Ty 是裸 rawptr = i8*)。
本轮只补取证、不改行为,让下一轮能一次定位"是谁把接收者记成了 ParamNode":
① 本类键 → struct 实例 IR 名(键/实例名不一致 ⇒ 同一类名两份实例);
② 其它**声明了该字段**的类键列表(唯一者即"本该用的类");
③ var_struct_class 中登记为**本类**的变量(封顶 6 个)及其实际 pointee IR 名
—— 记录类名与实际 IR 类型不一致时,直接圈定记录点。
验证:py_compile 通过。
|
2026-09-30 12:26:05 +08:00 |
|
TermiNexus
|
a43513c9a7
|
fix(FuncGen): 成员表与 body 等长时不再做类型对齐校准(base 恒为 0),修 TypeGenMixin 字段偏移平移
判据:_member_base 的 delta 长度启发式在 _Delta == 0 时给出 base=0(FuncGen.py:441),
而 base=2 **只可能**来自其后的"类型一致性校准"(:446-480,对 b∈{0,1,2} 逐项比类型取高分)。
但该校准用的是**严格类型相等**:声明侧的联合类型(如 `list[str] | t.CPtr`)可能被记成
折叠后的 i8*,而 body 槽仍是具体指针(`%list[str]*`)⇒ b=0 丢掉这些匹配,某个平移 b
却能靠指针槽互相撞分拿到更高分。
_Delta == 0(成员表项数 == body 槽数)本身就是"逐位对齐"(定义端 body 由成员表生成;
跨模块端 body(.stub.ll) 与 .vpi 同一声明顺序)⇒ base 必须为 0,此时不应再校准。
现场(本次):TypeGenMixin 41 成员 / 41 槽(@t.NoVTable,_Delta=0),base 被抬到 2 ⇒
Generator.vp:136 `SubTypeGen.Gen = self`(Gen 声明 `%"47382dc8277c9d28.Generator"*`、
正确槽为 0)写到槽 40(`%"6fbe68e8fca81223.TypeSpecArena"*`)⇒
"指针隐式转换已禁止(非基本类型(结构体/类/联合)):不能把指针类型 … 隐式转为 …"。
(该报文本身是上一提交 909d8ff0 补的"成员槽来源明细",这次正是靠它直接读出了
base/下标/声明槽类型/布局槽类型四项事实。)
附带:成员槽失败报文再补"名序"(_DescribeMemberSlot 打印 index:name 全表)——偏移算错时
第一现场就是"名序与 body 布局不同源",逐项列出即可直接判定是哪一侧漂移,不必再猜。
验证:py_compile 通过。_Delta != 0 的既有校准现场(ast.Constant 的 `cnst.lineno` 落到
pool 槽等)不受影响(本次只加前置条件,未改校准逻辑本身)。
|
2026-09-30 11:15:58 +08:00 |
|
TermiNexus
|
4d14334bd2
|
fix(LLVMCG): 成员表对齐改为「前缀锚 vs 尾部锚」按类型可写入性打分,修 Generator.vp:164 误报
类别:a 编译器缺陷(TPC 侧;修正 1776dfa6 / b06dac1d 的过宽判据)
现象:翻译 TransPyV/App/lib/core/Gen/Generator.vp 时 :164 `SubTypeGenErr.Gen = self` 报
「指针隐式转换已禁止:不能把 %"47382dc8277c9d28.Generator"* 隐式转为
%"6fbe68e8fca81223.TypeSpecArena"*」—— 目标类型是槽 41 的 Specs,而 Gen 的真身在槽 0。
判据:TypeGenErr 继承 TypeGenBase(41 槽)且只有 1 个自有字段 ⇒ body 42 槽;其成员表只含
['Gen'] 一项(**残缺前缀**,真身在 body 头部)。上一轮"尾部对齐"的前置校验(前缀数 == 父类
struct 槽数)在本例**巧合成立**:42 - 1 == 41 ⇒ 该表被锚到槽 41(Specs)⇒ 取到错误槽类型。
同族上一例为 Generator.vp:136(TypeGenMixin,已由 1776dfa6 挡住,但同类巧合仍会复现)。
修法:不再用"长度关系 / 父类槽数"去断言表的对齐方式(那是猜),改为**比较两个候选锚**的
逐项得分(判据与建 body / 存储侧同一套 `_MemberSlotAccepts`):
· 前缀锚 `_BaseNow()` —— 展平表 / 残缺前缀;
· 尾部锚 `len(body) - len(表)` —— 仅自有字段(父类前缀未补齐,真身在 body 尾部)。
只有尾部锚**严格更高分**才采用它;同分/更低一律保持原行为(配对 → 下标法)⇒ 对既有正确
布局零行为变化,同时消除"巧合成立"的假阳性。命中尾部锚时每类留一次告警(报出两锚得分)。
验证:5 例冒烟全部通过 ——
A TypeGenErr(声明类型分别为通用指针 / Generator*,body 42 槽).Gen → 0(修前 41);
C AnnAssign 仅自有字段表 → target/annotation/value/simple = 8/9/10/11(尾部锚仍生效);
D ExceptHandler 重名表 + 联合类型 children → name = 9(布局配对仍生效);
E 自洽展平表 .value → 10(行为不变);FuncGen.py py_compile 通过。
|
2026-09-30 00:39:06 +08:00 |
|
TermiNexus
|
1776dfa60a
|
fix(LLVMCG): 尾部对齐加「前缀数 == 父类 struct 槽数」前置校验,修正 Generator.vp:136 误报
类别:a 编译器缺陷(TPC 侧;修正 b06dac1d 引入的过宽判据)
现象:翻译 TransPyV/App/lib/core/Gen/Generator.vp 时 `SubTypeGen.Gen = self`(:136)报
「指针隐式转换已禁止(非基本类型):不能把 %"47382dc8277c9d28.Generator"* 隐式转为
%"6fbe68e8fca81223.TypeSpecArena"*」。
判据(事实链):
· SubTypeGen 静态类型 = rawptr[TypeGenMixin.TypeGenMixin],Gen 字段声明在基类 TypeGenBase;
该 struct 41 槽:槽 0 = Generator*(Gen),槽 40 = TypeSpecArena*(Specs)。
· 抛错点 `_StoreWithCoerce` 用的是 **GEP 出来的槽类型**(TargetType = Ptr.type.pointee)
⇒ 报错里的 TypeSpecArena* 说明 "Gen 的偏移被算成了 40"(Specs 那一槽),而不是 0。
· 成因:b06dac1d 的「尾部对齐」在"成员表短于 body 字段区"时按 `len(elements) - len(表)`
求前缀数;TypeGenMixin 的表只有 ['Gen'] 一项(且其声明类型已退化成通用指针 ⇒
类型自校验被放行),于是被锚到 body 末尾 = 槽 40。
修法:尾部对齐加**必需的前缀校验**——前缀数必须等于**父类 struct 的槽数**(展平前缀就是
父类整份布局,含其继承链);父类 struct 不可得(跨模块未加载 / opaque)时**不介入**。
TypeGenMixin:40 ≠ len(TypeGenBase)=41 ⇒ 不介入,落回下标法得 0(Generator*,赋值合法)。
(正面场景仍生效:AnnAssign 表仅 4 项自有字段、body 12 槽、父类 Stmt 8 槽 ⇒ 8 == 8。)
验证:冒烟两例——反例 TypeGenMixin.Gen → 0(修前 40);正例 AnnAssign 仅自有字段表仍得
target/annotation/value/simple = 8/9/10/11;FuncGen py_compile 通过。
|
2026-09-29 23:58:09 +08:00 |
|
TermiNexus
|
bd92dfdadf
|
fix(LLVMCG): 成员表重名/联合类型字段不再打断布局配对,ExceptHandler.name 取到槽 9
类别:a 编译器缺陷(TPC 侧)
现象:翻译 TransPyV/App/lib/core/Gen/AsyncGenMixin.vp 时 `self._add_local(trans, hd.name)`
(:667)的第 2 个实参求值失败并终止编译。基址诊断给出的事实链:类 ExceptHandler
(%"831ce86a2fd82c0..." 即 astaux.vp)成员表 10 项 =
['parent','pool','lineno','col_offset','end_lineno','end_col_offset','children','children','type','name']
('children' 重复一次),struct body 10 槽 =
[i8*, AST*, MemManager*, i32×4, list*, AST*(type), i8*(name)],字段 'name' 计算偏移 = 10
⇒ 越界(正确槽 = 9)。
判据与修法(两条,均已写进代码注释与告警报文):
1) 布局配对断链:成员表里 'children' 的声明类型是**联合类型折叠后的通用指针**
(`list[rawptr[AST]] | t.CPtr` ⇒ i8*),而 body 槽是具体指针(%"...list[...]"*)⇒
原配对只比 `is` / `str()`,在这一条断链,其后所有条目不再消费槽位 ⇒ 目标字段退化为
"base + 表内下标"('name' ⇒ 1 + 9 = 10)。修:两侧都是指针时复用存储/建 body 侧同一
判据 `_MemberSlotAccepts`(通用指针 i8* 放行、具体指针按被指类型),标量仍走严格比较
——不引入新的过配对。修后 type = 8、name = 9 ✓。
2) 重名条目使长度判据失真:`_expected_count_pre = len(class_members) + vtable` 把重复项
也算一槽 ⇒ 误判"body 不完整"而用**带重复项的表**重建 body(本模块布局比其它模块多一
槽 ⇒ 跨模块 ABI 撕裂)。新增判据:表有重名**且** body 槽数恰等于「去重名数 + vtable」
⇒ 认定 body 已是权威布局(来自定义模块 stub),只报事实、不重建。
另在"未被 body 配对命中"的回退路径上,把"成员表含重名条目 + 表项数/去重项数 + 该
返回值取自回退路径可能失准"作为事实告警报出(每类一次)。
验证:冒烟复刻本现场(表含重名 'children' 且其类型为联合 i8*;body 10 槽)——逐字段
1..9 全部命中(parent=1 … children=7、type=8、name=9),无重名的自洽表行为不变;
FuncGen / StructGen 两文件 py_compile 通过。
|
2026-09-29 23:48:52 +08:00 |
|
TermiNexus
|
b06dac1d6b
|
fix(LLVMCG): 字段偏移改用「冻结表有效性锚点 + 尾部对齐」,AnnAssign.value 不再读到 i32
类别:a 编译器缺陷(TPC 侧)
现象:编译 TranslatorGenMixin.vp 时 fail-fast —— getelementptr(GEP) 的指针操作数不是
指针类型:操作数类型=i32、操作数名='value.9'、GEP 名='vtable_slot_AST'。即
`aa.value.kind()`(TranslatorGenMixin.vp:788)的接收者读成了整数:AnnAssign.value 落到
槽 3(lineno, i32),随后虚分派取 vtable 时把 i32 当指针用。
根因(两条独立判据,均写进代码注释与告警报文):
1) 冻结表陈旧:StructGen 建 body 时把「成员名→槽位」挂在 struct 实例上,而 body 之后会被
「不完整即清除」(StructGen 预检 existing_st.elements = None)与 stub 加载
(HandlesImports._TryLoadStructFromStub 的 set_body)清空后重设,重设路径不更新该表
⇒ 陈旧表按旧布局取槽(AnnAssign 在「自有 4 字段 + vtable」时冻结 {'value': 3},body
被重设为 12 槽正确布局后仍取槽 3)。修:建表时同时记下 body 对象身份
(_tpc_member_body,set_body 每次赋新 tuple),查询侧用 `is` 判同一性,失效即不再采用。
2) 未展平成员表:表只含自有字段(父类前缀未补齐)时,「base(0/1) + 表内下标」会把整类字段
整体前移(target/annotation 落到指针槽 ⇒ 类型巧合、静默读错对象;value 落到 i32 槽 ⇒
本次崩溃)。修:表短于 body 字段区时按**尾部对齐**取槽(展平规则 = 父类前缀 + 自有字段
⇒ 自有字段恒为 body 尾部 len(表) 项),并用 _MemberSlotAccepts 逐项类型比对自校验;
表自洽(长度 == 字段区)时本路径不介入 ⇒ 对既有正确行为零变化;REnum 是 max-variant
镜像布局,明确排除。命中时每类留一次告警,报出表长/字段区/取槽结果。
验证:8 例冒烟(冻结表新鲜;陈旧×展平表 / ×自有表;无冻结×自有表 / ×展平表;无 vtable;
整类逐字段 = 8/9/10/11;尾部类型不符时落回旧路径)全部通过;两文件 py_compile 通过。
|
2026-09-29 23:18:37 +08:00 |
|
TermiNexus
|
f28ff1b414
|
fix(tpc): 字段偏移改为「布局真源优先」,成员表漂移不再整体平移
类别 a(编译器缺陷):_get_member_offset 返回 `base + 成员表下标`,但 class_members
是**可变**表(继承展平会在父类就绪后前置前缀、跨模块可按需重载/重跑),而 struct
body 一旦 set_body 即**永久冻结** ⇒ 表与布局的序位一旦漂移,整类字段偏移整体平移。
现场(IR 实证):Converter 模块读 `Alias.name` 落在 struct 槽 9(= asname),而定义
模块 Alias.__init__ 写入槽 8;`import t` 无 as 子句 ⇒ asname=NULL ⇒ TransPyV StubGen
误报「import 别名 name 为空(_copy_str 返回 None)」并终止 includes/stdint.vp 的 vpi
生成。同族旧现场:ast.Constant.lineno 取到 pool 槽(已由成员偏移同源修复过)。
- StructGen._generate_structs:set_body 时把「成员名 → 槽位」映射冻结到 struct
实例上(_tpc_member_slots / _tpc_member_base)。用**实例属性**而非全局表:同一
类名可能存在不止一个 struct 实例,偏移必须与被 GEP 的那一份布局同源;仅当
member_types 恰为 `[vtable?] + 全部成员` 时记录(位域类折叠为单一 storage 槽,
其字段位置另由 class_member_bitoffsets 表达;stub 已置 body 的情形不记录)。
- FuncGen._get_member_offset:新增两条「只看布局」的路径,优先于原下标法——
① 冻结映射命中即返回;
② 用**类型**把成员表逐项配对到 elements(类型不匹配、重名的条目视为方法/占位/
漂移项,不占槽位),配对中类型相等的槽位即字段真实槽位。
表与布局自洽时两者给出与旧下标法逐字相同的结果;都覆盖不到才落回下标法(对既有
正确行为零变化)。另在「配对结果 ≠ 下标法」时每类每字段告警一次,报出成员表项数
与 struct 槽数,把漂移来源变成可见事实。
本地冒烟(三类,均通过):自洽表 8 / 漂移表(类型不匹配)8(旧下标法 9)/
全同型漂移且命中冻结映射 8。
|
2026-09-29 19:57:57 +08:00 |
|
TermiNexus
|
415916b3dd
|
fix(tpc): 成员偏移以「实际 GEP 用的 struct 实例」为准,并报出双实例不一致
类别:a(编译器缺陷 —— 偏移与 GEP 不同源,整类字段偏移平移)
现场:TransPyV/App/lib/core/Gen/Class/ClassGenGeneric.vp:346
return ast.Constant(pool, cnst.const_kind, cnst.int_val, cnst.float_val,
cnst.str_val, cnst.lineno, cnst.col_offset)
报「调用参数类型不匹配:指针类型 %"c772afbbfd495aca.MemManager"* 不能隐式转换为
整数参数 i32」,逐项列表显示实参 [6](= cnst.lineno)求值成 MemManager*。
取证(TransPyV/temp/5df907d3a02a0bac.stub.ll:21/:23):
%"…Constant" = { [0]i8*(vtable) [1]AST*(parent) [2]MemManager*(pool)
[3]i32(lineno) [4]i32(col_offset) … }
__new__(Constant*, MemManager*, i32, i64, double, i8*, i32, i32)
成员表扁平序为 [parent, pool, lineno, col_offset, …] ⇒ base=1 时 lineno 偏移 3
(正确),base=0 时偏移 2 = pool,正是报出的那个指针类型;而 col_offset 偏移
3 落到 lineno 仍是 i32,所以**只有 [6] 报错** —— 与现象逐位吻合。
根因:FuncGen._member_base 的布局取自**类键** self.structs[cls],而 GEP 用的是
**取值处** ObjVal.type.pointee 那一份实例。同名类双注册(或一份已从 stub 加载完整、
另一份仍 opaque)时两份布局不同 ⇒ 用一份算偏移、用另一份读,整类字段偏移平移。
_class_has_vtable 对跨模块 AST 类恒为 False(其 docstring 已记录该已知静默路径),
base 只能靠 delta + 类型校准救回,两实例不同源时即失守。
改动:
1. FuncGen._member_base(ClassName, StructHint=None):hint 为**同类**(短名相同)的
struct 实例时,以它计算 delta / 首元素 vtable 判据 / 类型校准;当它与类键上的
实例不是同一对象时,每类一次 vlog().warning 报出两侧名字与元素数(opaque 或
元素数),使"双注册"这一事实不再静默。
2. FuncGen._get_member_offset(..., StructHint=None) → _BaseNow() 透传(base 仍现算,
不缓存)。
3. HandlesExprAttr._handle_attr_name:把 ObjVal.type.pointee 作为 hint 传入。
不传 hint 时行为与改前逐字一致;其余偏移消费点(字段写入 / 构造初始化等)本轮未动。
|
2026-09-29 18:18:49 +08:00 |
|
TermiNexus
|
9d8aedec4a
|
fix(tpc): 函数声明创建收口到幂等入口 _CreateOrReuseFuncDecl;清理 DDEBUG 探针
类别:a 编译器缺陷(根因修复)+ 调试探针移除。
现场:翻译 CallGenFd.vp 时抛 llvmlite.ir._utils.DuplicatedNameError:
'5d84ea579d83ef73.CallGenFd._translate_fakeduck_call'(llvmlite 的
NameScope 按名字去重,GlobalValue.deduplicate_name=False ⇒ 同名 global
建第二次必抛,且报文只给名字、不给两侧签名)。
根因:BaseGen._get_or_declare_function 建完 ir.Function 后**只加入
module.globals**(llvmlite 自动)而**未登记 Gen.functions**;而
HandlesFunctions._EmitFunctionLlvm 的 need_new 判据只看 Gen.functions
(`MangledName not in Gen.functions`)⇒ 同一名字再建一次 → DuplicatedNameError;
该处 except 又把它吞掉(非 strict 模式只 LogWarning)→ 函数始终没进
Gen.functions → 后续其它创建点(FuncGen._get_or_declare_func /
get_or_declare_c_func,同样只查 self.functions)再建 → 异常从别处逃逸到
Phase2Translator。
修复:
1. BaseGen 新增 _CreateOrReuseFuncDecl(name, func_type) —— 函数声明创建的
唯一幂等入口:module.globals 已有同名函数且**函数类型结构串相同**则复用
(并补登记 Gen.functions;FunctionType 无 __eq__,只能比 str);
类型不同则 fail-fast 报出两侧签名(declare/define 分裂的真因),
绝不静默复用错签名(调用点会按错签名传参)。
2. _get_or_declare_function 改走该入口(顺带补登记 Gen.functions);
FuncGen._get_or_declare_func / get_or_declare_c_func 改走该入口;
HandlesFunctions 定义路径改走该入口,且该处 except 对 FailFastError
直接 re-raise(不再吞)。
3. 清理遗留调试探针(含 sys.exit(1)):BaseGen 三处 [DDEBUG]
(_get_or_declare_function 双点 / _mangle_func_name 前导点与结果双点)、
HandlesExprAsm 两处 [DDEBUG_ASM]、HandlesExprCall 一处
[DDEBUG] _HandleClosureCallLlvm。
|
2026-09-29 13:00:11 +08:00 |
|
TermiNexus
|
66de269ebf
|
fix(tpc): 撤回失效的"事后修复",改为 set_body 前拦截降级布局(不冻结)
a 编译器缺陷。实测证据(07ea8e2f 的探针回执):对本版本 llvmlite,
`st._elements = None` 之后 `st.set_body(*elems)` 仍以
`RuntimeError: <name> is already defined` 拒绝 —— 说明 **`_elements` 不是 set_body 的
判定存储**,即"清 _elements 以便重载/重设 body"这一全仓惯用手段在本版本是**空操作**
(结构体 body 一经设定即不可改)。因此:
- 撤回 7fb0e498 加的 `_SyncStructBodyTypes`(使用点就地修复)及其在
`_get_member_offset` 的调用 —— 它在本版本永不可能成功,只会把编译卡死;
- 改为**事前拦截**:`_generate_structs` 在 `set_body` 前调用
`_HasDegradedMemberTypes`,若本次布局里存在「注解是类引用(`Mod.Class` /
首字母大写裸名,排除 t/c 模块)**却**解析成 `i8**`」的成员,说明该 pass 类型尚未
就绪 ⇒ **不设 body、保持 opaque**,等类型就绪的 pass 再设。这样从根上避免
"降级布局被永久冻结"(现场:Generator 的槽 i8** 而声明 %"…ExprGenFstr"*,
赋值时报「层数不同」)。始终不就绪则在使用点响亮失败(opaqueness / 层数不同),
不再静默产出错布局。
- 新增 `_IsI8DoublePtr` / `_IsClassRefPtrAnnotation` 两个判据助手(保守:只在
"指针包装 + 类引用内层 + i8 系两层指针"三条同时成立时判降级)。
|
2026-09-29 11:56:08 +08:00 |
|
TermiNexus
|
7fb0e49854
|
fix(tpc): 成员偏移查询点就地修复错位 struct body(修正晚于冻结的时序)
a 编译器缺陷(承接 b8ed33a2):Step 4 的前置校验只在**当次** _generate_structs 生效,
漏掉"class_members 被 .vpi/stub 修正在后、struct body 冻结在前"的时序 —— 于是
一次只修好一部分槽(实测:第 3 槽修好、第 11 槽仍错),错误逐个前移。
证据链(成员槽来源明细 + 全盘 grep):
class_members[Generator] 项数=47 base=0 下标=11
声明槽类型=%"a7b68c79f39cb4d3.ExprGenFstr"*
布局 struct name='fd4cd0ec583f42b9.Generator' 元素数=47 elements[11]=i8**
且**没有任何** stub 文本里含 i8** ⇒ body 是从"当时已降级的 class_members"冻住的,
后来重载只修 class_members,改不了已冻结的 body(llvmlite set_body 只能设一次)。
修法:新增 StructGen._SyncStructBodyTypes —— 在**使用点**(_get_member_offset,
即任何 GEP 之前、成员表已在上方补齐/重载之后)按 class_members 逐槽比对,
只把**存储时必被拒绝**的槽(判据同 _MemberSlotAccepts)改回声明类型,其余元素
(含通用指针 i8* 槽)原样保留;_elements 置空后 set_body 重设(命名类型对象不变,
故已发出的 getelementptr %"name"* 不受影响)。同名类 sha1 冲突路径
(_ResolvedClass != ClassName)跳过,避免用别的同名类成员表写坏布局。
|
2026-09-29 00:19:06 +08:00 |
|
TermiNexus
|
78c5155de9
|
revert(tpc): 回滚 51de3b6d 的 [DIAG-decl] 临时诊断
「跨模块函数形参退化成 i32*」(constant_get_str_val / function_get_name 第 0 形参
i32*)一族已由 1c1f78e7 定位修复(同名枚举成员遮蔽类定义,判据按 IsEnumMember
区分),探针使命结束,整体移除:
- FuncGen._RecordDeclFrom / _DescribeI32ParamDiag 及两处调用点
- _adjust_args fail-fast 报文中的 _diag_extra 拼接
- BaseGen._get_or_declare_function 入口记录点
- HandlesBase.GetOrCreateFuncDecl 入口记录点
|
2026-09-28 23:23:02 +08:00 |
|
TermiNexus
|
51de3b6dcf
|
chore(tpc): [临时诊断] 声明来源 + i32* 形参判定依据并入 fail-fast 报文
只为定位"跨模块函数形参退化成 i32*"(现场 function_get_name 第 0 形参 i32*,
实参 %"46c7dc5230ea5a52.Function"*)。静态排查已穷尽:_ctype_to_llvm /
_type_str_to_llvm 产生 i32* 的出口只有「BaseType 退化成 i32 + PtrCount=1」
(含 CTypeInfo.ToString() 的 'CInt *' → i32*)与「IsEnum + Name + PtrCount=1」,
离线复现不出,需要运行时证据。
做法:把判定依据直接拼进 FailFastError 报文,使其随 Traceback 一起被看到:
[DIAG-decl] 实参类 / structs / _struct_sha1_map / class_sha1_map /
symtab 标志 / 声明函数类型 / 声明来源(创建者调用栈)
并在四个声明创建点记录首个创建者:
FuncGen._get_or_declare_func / get_or_declare_c_func、
BaseGen._get_or_declare_function、HandlesBase.GetOrCreateFuncDecl(会替换声明)。
定位完成后整体回滚(连同记录点)。
|
2026-09-28 22:20:09 +08:00 |
|
TermiNexus
|
96d8e13c5a
|
fix(err): 成员查找 fail-fast 改用可读异常 + 报错语句栈不再重复长报文
① 新增 MemberLookupFailFast(KeyError):_get_member_offset 的 fail-fast 原用 raise KeyError(消息),而 KeyError.__str__ = repr(消息) ⇒ 报文被加上引号、换行被转义成字面 \n(含"源代码 (文件, 行号): 行号 | 源码"的多行报文彻底不可读)。新类继承 KeyError(保住 HandlesExprAttr 两处 except KeyError 兜底点)但 __str__ 返回裸消息。
② 顺带删除该处的 traceback.print_stack 调试转储(遗留调试语句,输出噪音)。
③ Phase2Translator 语句栈渲染:原格式把同一条异常消息贴在每一层帧后面 ⇒ 一句话被打印 N 次;改为外层→内层的调用路径逐帧印位置、异常消息只在最内层印一次。
|
2026-09-28 16:48:58 +08:00 |
|
TermiNexus
|
d7158bd336
|
feat(cast): 指针隐式转换新规则 + None 可隐式转任意类型 + 诊断错位修复(9 文件)
MemoryOps._ClassifyPtrImplicitConvert:同类型放行;层数不同禁;任一侧通用指针(i8*)放行;皆非通用按被指类型(非基本类型禁、基本标量按位宽无损);指针与非基本值互换禁
_IsNoneValue 收敛:AST None 常量 或 指针型 null 常量 → 放行任意目标(指针目标给 null,非指针目标给零值);整数 0 不误命中;短路口覆盖 9 处禁令
诊断:新增 BaseGen._DescribeValueNode(子表达式下沉 + 有符号列号 + 源码片段),9 处禁令统一使用,不再打印外层 Assign 与 4294967295 列号
注:TPC 侧规则③比 TPV 更严(指针→非基本值恒禁),可能与既有按值回读冲突;待实机编译确认后再统一两侧口径
|
2026-09-28 15:10:39 +08:00 |
|
TermiNexus
|
58050a1ab2
|
fix(member_base): base 改由声明类型与 elements 的一致度校准,修整类字段偏移整体差 1
delta 长度启发式只在成员表与布局恰好差 vtable 一项时成立;成员表多/少一个非 vtable 项时 base 判错,整个类字段偏移整体平移:ast.Constant 的 lineno 落到 pool(MemManager*),调用点报形参 lineno: i32 收到指针,把真因掩盖成指针/整数错配
改法:对 b 属于 {0,1,2} 逐项比较成员声明类型与 elements[b+i],取一致度最高者(完全相同 +2),仅在明显更优(至少多对齐 1 个成员)时覆盖启发式;指针槽区分度最高
同时移除上一轮临时加的运行时字段布局探针(_diag_member_layout 及其两处调用)
|
2026-09-26 21:29:28 +08:00 |
|
TermiNexus
|
53a345a59a
|
feat(ctrlc-stack): 新增 --ctrlc-stack 编译期开关(按键打印 .vp 调用栈)
Config/Phase2Translator: --ctrlc-stack 自动开 DWARF;缓存失效;链接后 llvm-dwarfdump 导出 <exe>.stackmap(逐条归一化为 RVA——旧的整体判据会被 lld 去重产生的 0 地址行带偏,导致全表差一个 ImageBase);链接参数追加 -ldbghelp;include 也生成 DWARF 并隔离到 includes.binary_ctrlcstack(_asan);llc 追加 -frame-pointer=all。
BaseGen._RegisterDbgStackInstallViaCtor + StructGen.finalize 钩子: 注入 llvm.global_ctors(priority 65535) 在启动期调用 dbgstack.Install(),写盘前核对 global_ctors 否则 fail-fast。
FuncGen._adjust_args: 指针到整数的 fail-fast 补逐项类型诊断。
|
2026-09-25 13:11:13 +08:00 |
|
TermiNexus
|
2cc816ac13
|
修复了一些错误
|
2026-09-18 20:00:59 +08:00 |
|
TermiNexus
|
6af2dea917
|
修复了一些问题
|
2026-09-17 14:52:37 +08:00 |
|
TermiNexus
|
0bda395ecc
|
fix(translator,peephole): TPC 属性链解析修复与窥孔 T1-T3 收尾
- TPC(lib/core): 泛型父特化形参按声明类登记 var_struct_class; _find_struct_key 键归一支持方括号内嵌 sha 前缀; 字段探测失败不再冒泡 FuncGen fail-fast; cast 局部通用指针槽按静态类 bitcast; 属性解析失败附诊断
- 窥孔(includes/llvmlite/__function.vp): 窥孔移至 Renumber 前使输出 SSA 编号连续; T3 no-op bitcast 消除; T4(数组 bitcast->GEP)验证干扰返回类型收敛已移除
- 附调试打点与 1.log
|
2026-09-08 12:52:48 +08:00 |
|
TermiNexus
|
45e78ad107
|
基线重置,修复了一些 bug
|
2026-09-07 14:46:02 +08:00 |
|
TermiNexus
|
0ce4a4d073
|
fix(tpc): import 路径/隐式转换/缺失 return 三项漏检 fail-fast
- HandlesImports: 模块在所有来源找不到时 raise ImportError(原静默容忍导致跨模块 mangled fallback,链接期才暴露 undefined symbol)
- LlvmGenerator: import 处理 ImportError 直接重抛,不被 _ErrorStack 吞掉
- FuncGen: 指针→整数、浮点→整数隐式转换改 raise TypeError(显式 cast 仍允许,符合隐式转换规则)
- HandlesFunctions: 有非 void 返回注解但函数体掉出末尾 raise Exception(-> None / -> t.CVoid 视为 Void 仍合法)
- 新增 Test/NegativeTest 反向测试专项:9 个漏检用例,当前 9 PASS / 0 FAIL
|
2026-08-22 03:57:19 +08:00 |
|
TermiNexus
|
6fc9e19e24
|
feat(vast): 新增自研 Viper/Python 语法解析器取代标准库 ast
TPC 侧取缔对 Python 标准库 ast 模块的依赖,改用 lib/vast 包:
- Nodes: 与 CPython 3.12 ast 完全同构的 131 个节点类(含抽象基类继承)
- Tokenizer: 词法分析(缩进/字符串/f-string/数字/运算符/软关键字)
- ExprParser: 表达式递归下降解析(优先级/lambda/推导式/f-string/切片)
- Parser: 语句解析(def/class/if/for/try/with/match/import/注解)
- Utils/Unparser: walk/dump/unparse/copy_location/literal_eval 等辅助
- 软关键字 fn/fun/func/function 并入解析器, 废除 ExpandSoftKeywords 预处理
- lib/_bootstrap 将 lib 目录加入 sys.path, import vast as ast 零修改替换
- 52 个文件 import ast 替换为 import vast as ast; 94 文件差分测试 0 失败
|
2026-08-17 09:36:38 +08:00 |
|
TermiNexus
|
cb557c84ce
|
fix(TPC): _get_member_offset 短名规范化+跨模块懒加载+fast-fail
class_members/class_vtable/class_parent 以短名注册而调用方可能传 sha1 全名,且 class_members 未随 struct 就绪,导致查表全 miss 静默返回 None → 变量 alloca 未初始化 → 运行期读 0xffffffffffffffff 崩溃(HandlesImports.HandleImport imp.names)。修复:统一短名解析、主动懒加载 class_members、找不到字段改为 fast-fail raise 暴露 class_members/struct 真实状态。
|
2026-08-10 18:09:05 +08:00 |
|
TermiNexus
|
cfc30d735c
|
将 .py 和 .pyi 后缀名改为了 .vp 和 .vpi 后缀名
|
2026-07-30 16:33:56 +08:00 |
|
t
|
796222a300
|
snapshot before regression test
|
2026-07-18 19:25:40 +08:00 |
|