Commit Graph
100 Commits
Author SHA1 Message Date
TermiNexus c02aa3a2eb fix(gen): @life/@willFree 不再被当作运行时装饰器
自定义装饰器检测(__decor_wrap_<name> 生成路径)此前把 P2 的编译期标注当成 User 装饰器:会生成 wrapper 调用并不存在的 @life/@willFree,并把被装饰的 extern def(如 stdlib.free)变成本模块 internal 声明,llc 报 invalid linkage for function declaration。把 life/willFree 加入该处标记白名单。
2026-10-08 21:43:47 +08:00
TermiNexus b60ce06335 feat(gen): willFree 覆盖关键字实参、方法调用与取地址三条路径
关键字/混合实参:CallGenMixin._MarkWillFreeKwargs 按形参序(位置实参占前 can 个形参,其余按关键字名匹配)标记。方法调用:CallGenCall._translate_method_call 的 kwargs 与位置两条循环,实参链含 self 故用户第 ai 个实参对应 bit (ai+1);新增 GenApi/StructGenMixin.get_param_willfree_method(查 Class.method 并沿 MRO 回退)。取地址:ExprGenOps 的 AddrOf 分支对已失效变量 fail-fast。
2026-10-08 21:39:53 +08:00
TermiNexus d921dcd9e7 fix(gen): willFree 形参表访问先转 Arguments*,修复 TPC 侧 MemberLookupFailFast
FunctionDef.args 的字段静态类型是 AST*,直接写 fn.args.args 会在 AST 类上查 args(class_members=7 不含 args)。改为先 ast.Arguments*(fn.args) 再取 .args 列表,与 VpiReader / FuncGenMixin / ClassGenVTable 等既有写法一致。
2026-10-08 21:34:14 +08:00
TermiNexus 97313e9e55 feat(gen): P2 生命期标注 @life(willFree(...)) 驱动释放后使用与二次释放检查
标注面:@life(willFree(<形参名|0起序号>)),兼容叠加式 @willFree(...),可混用累加;序号按形参表下标、self/cls 计入。GenApi.compute_willfree_mask 解析标注并对非法标注 fail-fast。本文件表 StructGenMixin.WfTable + 跨模块 .vpi 行尾 wf=<mask>(Converter 写 / VpiReader 读 / CallGenBase 查)。调用点在实参全部翻译之后把对应实参变量槽置 VarEntry.Freed;其后的读取路径报 LifetimeError。重新赋值清除失效态。
2026-10-08 21:28:49 +08:00
TermiNexus 9ff5a3a03e fix(gen): 泛型类构造复用 new 描述符存储,并支持泛型下标 callee
- _translate_generic_ctor_call 之前一律 _alloca_at_entry:new memgr(pool) hlife list[int](...) 会忽略描述符给的内存、把对象构造到栈上、返回栈地址(静默悬垂)。改为与 _translate_struct_ctor 同款:tmp = _g_new_storage,为空才回落 alloca。

- _translate_new_expr 支持泛型下标 callee(Box[int]):新增 _specialize_new_generic_class 先特化模板拿具体类名,再走同一条取存储路径。
2026-10-08 21:04:41 +08:00
TermiNexus b6a9b50f93 fix(gen): 异常与传播出口也释放 slife(P1)
插桩点选在 StmtGenMixin._eh_ret_default —— 异常路径上真正离开函数的唯一汇聚点(translate_raise 的 bare raise / StopIteration / 传播三条分支 + try 的 UnhandledBB 传播分支都走它),发 ret 前 _SlifeEmitFrees。不得改在 raise 语句本身:被本函数 except 捕获时对象仍在用(那一步只 br 到 DispatchBB);EH 返回值也不会是 slife 对象(逃逸检查已拒)。
2026-10-08 21:04:33 +08:00
TermiNexus 70390858d8 feat(gen): 协程体里的 new heap slife fail-fast(释放点无法确定)
AsyncGenMixin 的状态机会把协程 body 拆成多个 state 块并多次转译,编译器无法确定 slife 的释放点;此前是静默漏释放。新增锚点 trans._coro_body_func(Translator 字段 + init 置 None),只在 body 翻译期间由 translate_async_function 设置并保存/恢复旧值;_translate_new_expr 以**函数对象同一性**(_coro_body_func == _cur_func)判定并 fatal_error(LifetimeError)。嵌套普通函数会换掉 _cur_func 故不误报;new stack 与 hlife 不受影响。
2026-10-08 20:42:09 +08:00
TermiNexus 2178970ff7 feat(gen): slife 释放前调度析构 __del__,并禁止手动 del(§3.6 落地)
- 释放统一入口 _SlifeEmitGuardedFree 改为「先析构、再 free」;析构名定案 __del__(对齐 TPC LLVMCG/MemoryOps._emit_local_heap_frees 的释放路径;del obj 那条语句走的仍是 __delete__)。

- 查表沿 MRO / 跨模块 stub 回退(复用 ExprGenOps._resolve_dunder_by_class);类未定义 __del__ 时**不加任何分支**,常见路径零开销。

- 析构用条件分支而不是 select:未拥有的路径必须完全不进析构体(析构体里会解引用 self,传 null 进去会踩空);块标签走 trans._label_counter,避免同函数内重名。

- §2.4 判据5 扩展:对 slife 对象手动 del obj → LifetimeError(否则析构跑两次)。hlife 路径不受影响。

- 为把 trans 传进析构查找,_SlifeEmitFrees / _SlifeEmitGuardedFree / _SlifeDropOwned 加 trans 形参,9 处调用点同步。
2026-10-08 20:34:11 +08:00
TermiNexus 78b2052445 feat(gen): 接线 M3 owned slife 的 RAII 出口释放(函数级 scope guard)
- 所有权影子标志(i8,登记时入口块置 0)+ free(select(影子!=0, load 槽, null)) 保护式释放:赋值在分支/循环里而未执行 → free(NULL);槽里写入外来指针或别名 → 清影子,绝不 free 外来指针;循环反复 new → 赋值前覆盖释放上一轮,不累积。

- 三条函数体转译路径(FuncGenDef 主路径 / FuncGenMixin 嵌套函数提升为 __closure_* / ClassGenVTable 方法体)各自抬升与弹回登记区间;修两处漏 reset 导致内层出口 free 外层对象再被外层 free 一次 = double free(Windows STATUS_HEAP_CORRUPTION)。出口按槽去重做兜底。

- free 由模块前言统一声明(Translator.vp,紧挨 malloc);释放点只查表 + fail-fast,绝不吐指向未声明符号的 llvm.call。

- 赋值处记账:new heap slife → 登记 + 覆盖释放 + 影子置 1;其它 RHS(new stack / hlife / 别名 / 外来指针 / None)→ 已登记则交还所有权。手动 free slife 对象 → LifetimeError。
2026-10-08 20:03:54 +08:00
TermiNexus 934708b206 fix(type): 数组退让豁免提到级数检查之前,修 [N]str 形参被误判 CastError
形参侧 CArray 按 C 语义退让成元素指针 str*(级数 2),实参仍是 [N]str 的数组地址(级数 1)→ _ptr_cast_reason 先查级数就判 PC_DEPTH,_pointee_convert_reason 里那条既有数组退让豁免成了死代码。元素为 i8 时级数不变所以一直没暴露,元素本身是指针才炸(现场:includes/tomllib _parse_key_path 的 segs)。
2026-10-08 20:03:42 +08:00
TermiNexus 1dd53ebff5 feat(gen): M3 owned slife 登记机制(函数级 scope guard 的底座)
登记本函数内由 new heap/memgr slife 直接绑定的变量 alloca,提供 Reset/Register/Owned/MarkAliased/EmitFrees/ReleaseOld 六个 API,供出口插桩与覆盖释放使用。

为什么是函数级而非块级(已核实):Stmt 层(if/while/for/with)不调用 enter_scope/exit_scope,局部存储一律入口块 alloca(函数级寿命)——块级释放会让"块之后仍可达的变量"变悬垂。别名(q = p)在覆盖释放时保守跳过(宁可泄漏不悬垂),函数出口释放不受别名影响。

本提交仅机制,尚未接线(无行为变化);下一步接 4 处钩子:函数入口/收尾、translate_return 的 3 个 build_ret、赋值处的登记与覆盖释放、以及 §4.3 手动 free 判据。
2026-10-08 18:41:52 +08:00
TermiNexus 09b5bf5ac3 docs(gen): _translate_new_expr 注明缺省规则(stack 默认 slife)
缺省规则(§3.2 / D3):来源缺省 = heap;生命期缺省由来源决定——stack → slife(故 new stack T(...) 不写 slife 也等效),heap/memgr → hlife。生命期在 life_of_expr 按同一张表落地(LIFE_FRAME / LIFE_HEAP)。
2026-10-08 18:21:00 +08:00
TermiNexus 9e55e909a8 feat(gen): LifeTag 接到 new 描述符;vpi 文本缓存收敛为单一入口
life_of_expr 新增 ASTKind.New 分支(§2.3 矩阵):stack→LIFE_FRAME;heap/memgr 的 slife 同样按帧生命期(作用域末 RAII 释放,逃逸必悬垂);hlife→LIFE_HEAP。于是 new stack slife Foo() 的结果被赋给变量/返回时会被既有汇点判据 fail_if_life_escapes 拦住(该判据本来就是生命期驱动,无需再加语法特例)。

VpiReader 新增 _cache_vpi_annots_text 单一入口(ret/param/逃逸摘要一次喂齐),两个 vpi 加载点都改调它:从结构上消除"某个加载点漏喂某类缓存"这类静默退化(本次 EscapeXmodTest 漏检的根因类别)。
2026-10-08 18:19:15 +08:00
TermiNexus 8a98051759 fix(gen): new 的分配尺寸常量改用 const_int64,修 mlir-opt 校验失败
ConstInt 的第 4 个参数是常量在 IR 里的文本(不是注释/名字),此前传 "newsize" 会打印成 llvm.mlir.constant(newsize : i64),mlir-opt 报 expected attribute value。已改用项目通用的 mlirlite.const_int64(pool, size_bytes)。
2026-10-08 18:18:03 +08:00
TermiNexus c77d38e923 fix(gen): new heap/memgr 的尺寸改用 ClassGenEnum._get_type_size,修结构体报 cannot determine the size
原先调用 TypeGenResolve.get_type_size_bytes,它只解析 typedef/标量,结构体一律返回 0,于是 new heap Point(3,4) 在语义期 fail-fast。

改用语言级 T.__sizeof__() 的同一实现 ClassGenEnum._get_type_size(struct_ty),保证 new 分配的尺寸与源码手写 __sizeof__() 完全一致(含对齐/填充)。
2026-10-08 18:07:28 +08:00
TermiNexus 14920c0e1e fix(vpi): 逃逸摘要在所有 vpi 加载点都喂缓存,修 EscapeXmodTest 跨模块漏检
_ensure_vpi_ret_annot_loaded 开头有"本模块 ret 注解已缓存则直接 return 1"的短路:若某模块先经 _ParseVpiIntoModuleImpl(stub 注入)加载,而该处只喂了 ret/param 缓存、没喂逃逸缓存,后续跨模块逃逸查询就会永久查空。现场:EscapeXmodTest 漏检——box.vpi 里 `# esc=2 ret=0` 落盘正确,查询侧却命中不到。在该加载点补 _cache_vpi_escape_annots_text。
2026-10-08 17:58:07 +08:00
TermiNexus 64502471e1 feat(gen): M2.4 new 描述符语义落地(stack/heap/memgr 三来源)
CallGenCtor 新增 _translate_new_expr:只替换取存储一步——stack 用帧内 alloca、heap 用 malloc(sizeof)+bitcast、memgr(x) 用 x.alloc(sizeof)+bitcast;其余构造序列(__before_init__ → __init__ / 字段赋值)用合成 Call 复用原路径,因此 __init__ 的逃逸检查对 new 同样生效;结果恒为 T*。

文件级 _g_new_storage 承接描述符算出的存储,两个 ctor 入口的默认 alloca 改为有则复用;_translate_new_expr 前后保存/恢复,支持嵌套 new。

§2.4:stack+hlife 语义矛盾 fail-fast;memgr(x) 拿不到管理器类 fail-fast。ExprGenMixin 分派 ASTKind.New。
2026-10-08 17:45:39 +08:00
TermiNexus cd68bb62ac feat(gen): M2.3 v3 跨模块逃逸摘要 + 全局赋值判据双保险
【v3 跨模块摘要】Converter._PyiFunction 在每个 def 签名行尾写 `# esc=<mask> ret=<ret>`(仅非零时写);VpiReader 新增逃逸摘要缓存(键 {sha1}.{Class}.{method} / {sha1}.{func},值打包 mask|ret<<32),与返回注解缓存同一次加载解析,并加"模块已加载"备忘 + 键前缀过滤避免拖慢编译;StructGenMixin 抽出 compute_escape_summary 供登记与落盘共用;CallGenBase.lookup_escape_via_vpi 按本类 + MRO 祖先模块 sha1 查询,方法/构造器/模块级函数三处调用点在本地表未命中时回退查 vpi。

【修复】Converter._PyiEnsureEscScratch 补 global(漏写导致全局仍 NULL,box 算成 0+520 → ASan WRITE on 0x208);函数内写"本文件已声明的模块全局"且无 global/nonlocal 时必须 fail-fast——原判据只看 SymTab.Root.Vars,部分时序看不到模块全局而静默建局部影子;新增 FileVarNames(register_file_funcs 预扫收集顶层变量名)+ is_file_var() 兜底,普通赋值与注解式重声明两处都接上。
2026-10-08 17:28:06 +08:00
TermiNexus 9f98e683a9 feat(gen): M2.3 覆盖面扩展——类方法与嵌套函数的逃逸摘要
摘要键约定:模块级/嵌套函数用裸名(与调用点 func_name 一致),类方法用 "Class.method",查询沿 MRO 回退;刻意不回退裸名,避免方法名与同名模块函数(error/init 等)串味产生误报。

register_file_funcs 登记类方法与嵌套函数摘要,v2 传递闭包相应覆盖(_RescanEscapes 拆为 _RescanOne/_RescanNested/_RescanClassMethods)。

调用点新增:_translate_method_call 的方法路径检查(形参下标含 self,用户第 ai 个实参对应 bit ai+1)、_call_method_on_ptr 的 __init__ 构造器检查(self.f = p 的逃逸;__new__ 形参可能与 __init__ 共享并裁剪,不查)。

已知边界:摘要表按文件重置,跨模块查询待 v3;_PropagateCallEscapes 只处理裸名被调者,方法调用链的传递待补。
2026-10-08 16:55:34 +08:00
TermiNexus b03e55bb7e fix(gen): 类归属不采信星号导入候选,收口 fatal_error 返回类型与默认值补全
TypeGenResolve._class_true_def_sha1 / CallGenBase._lookup_reexport_from_vpi 新增 allow_star 参数:类归属只采信具名 re-export。此前 `from X import *` 候选被当成类的真实定义模块,而几乎每个文件都 star-import stdint,导致 TypeGenErr 前向声明被建成 "stdint.TypeGenErr";该名字在 StructTable 里只剩一个错误 sha1 的条目,fatal_error 的跨模块返回类型解析全部落空并 fail-fast。

TypeGenErr.fatal_error/fatal_type_error 显式 -> int(留空会解析出退化类型 i0,命中 CallGenCall 的 i0 守卫);_fail_method_ret_ty 增加失败上下文转储并并入同一条 VLogger.error(批处理下 error 即 sys.exit,其后代码全是死代码)。

CallGenMixin 模块级调用:默认值已知但重建不出时 fail-fast,不再静默产出操作数不足的 llvm.call(只会被 MLIR 校验拦下);AssignGenMixin 两处 VLogger.error 补上 category 实参。

M2.3 v1b 收尾:逃逸摘要表与扫描临时区改为只分配一次、传递闭包扫到不动点、u64 改 sizet;VpiReader 不再 free 跨阶段引用的 src_sha1(heap-use-after-free)。
2026-10-08 16:38:35 +08:00
TermiNexus 1fb0f4a4ea feat(gen): 逃逸摘要传递闭包(M2.3 v2)
- walker 认值位置上的调用(Return/Assign/AnnAssign/Expr 的 value 为 Call)。 - 传递规则:g(p,...) 中 g 会逃逸的实参位若绑到本函数形参 p,则 p 也逃逸。 - 注册完再重扫 2 遍(单调 OR-in)。已知:超过 2 层的链仍可能漏,真正收敛需改为扫描到不变为止。
2026-10-08 13:47:54 +08:00
TermiNexus 52fd89decf feat(gen): 调用点逃逸检查(M2.3 v1b 步骤4)
translate_call 里按被调者摘要核对实参:第 k 位为 1(该形参会逃逸/被返回)的形参位上,实参若交出本帧栈地址(&local / 局部数组退让)即报 LifetimeError。此处拿不到被调者形参类型,故传哑指针类型,仅用于让 life_of_expr 判定裸局部数组名处于指针位置=退让。
2026-10-08 13:41:00 +08:00
TermiNexus 4ce577d8fb feat(gen): 函数生命期摘要表 + 逃逸 walker(M2.3 v1b 步骤1-3)
- StructGenMixin:EscTable/EscCount(追加在类末尾,避免偏移漂移);register_file_funcs 每文件重置并逐函数算摘要。 - 逃逸 walker:return p / global 赋值 / obj.f 赋值,递归 if/while/for;不进嵌套 def/class;形参访问逐级显式重转(AST 退化)。 - 表内只存 u64 名哈希(djb2-64),不解引用字符串指针,消除槽内坏指针导致的 strcmp 崩溃。 - 表从 PermPool 分配并 memset。 - GenApi:get_param_escapes/get_ret_borrow 查询入口。调用点检查(步骤4)待接。
2026-10-08 13:29:28 +08:00
TermiNexus a6e1957768 feat(gen): 控制流汇合 Meet(M2.2)
- VarGenMixin:life_capture/life_restore/life_join(作用域链快照,池上 [count,(entry,life)…] 数组)。 - StmtGenCifMixin.translate_if:进分支前快照、then 末快照、else 前复位、出口按 min 合并。 - StmtGenMixin:while/for 统一在语句分派处 capture→run→join(一处覆盖全部迭代形态与解糖,含 0 次迭代路径)。
2026-10-08 12:35:59 +08:00
TermiNexus ec47401151 feat(gen): 生命期标签(LifeTag)与借用传播(M2.1)
- GenTypes:新增 define LIFE_VALUE/FRAME/HEAP/STATIC/UNKNOWN 与 VarEntry.Life。 - VarGenMixin:set_var_life/get_var_life/life_meet;add_var 初始化 Life=UNKNOWN。 - AssignGenMixin:life_of_expr(&local、数组退让、变量 Life 读取)、propagate_life(赋值传播)、fail_if_life_escapes(汇点检查,LifetimeError);在 AnnAssign 与单 Name Assign 处挂传播。 - GenApi.fail_if_stack_addr_escape 改为薄壳并委托 fail_if_life_escapes;原 (a)(b) 语法判据并入 life_of_expr。于是 s: str = l; return s 被拦截。
2026-10-08 12:22:10 +08:00
TermiNexus 7070bc1608 feat(gen): 栈地址逃逸检查(LifetimeError)、按值返回聚合、标量→聚合 fail-fast
- GenApi.fail_if_stack_addr_escape:禁止把本帧栈地址写出帧外(显式 &local,以及局部数组名退让到指针目标,如 return arr with '-> char*');裸聚合名 + 同型聚合目标是值拷贝,不在其列;err_type 记为 LifetimeError。 - StmtGenCifMixin.translate_return:按值返回聚合时,对被指类型与返回聚合类型同一的指针补 load(与多返回值 struct 的 ret 同形),修复 return 局部数组报 CastError。 - ExprGenBase.coerce_to_type:聚合目标不接受标量(旧行为落成 store i32 0, ptr,只写首元素字节并抬高对齐),改为编译期 fail-fast。
2026-10-08 12:10:13 +08:00
TermiNexus 2ab6342d3c fix(gen): arg 糖支持转发形态的 va_list
_translate_arg_sugar 原本在 trans._va_list_ptr 为 None 时(非变参的 vprintf 式包装函数,如 vsnprintf(buf,size,fmt,args))直接返回 0,转发下来的 va_list 因此读不到;现增加回退:按名 args 取形参 alloca 并 load 出槽内的 va_list 指针(自身变参形态仍用 trans._va_list_ptr,不 load)。点号形式 stdarg.arg(...) 经 ExprGenBase.get_func_name 取属性短名,已天然命中同一分派,未改动。
2026-10-07 20:15:40 +08:00
TermiNexus c20bd4734b feat(gen): 值引用自动取址接入虚分派/构造/属性/静态等全部方法调用路径
CallGenBase 新增 _vpi_auto_addr_mode(把原先埋在 _coerce_args_to_def_params 里的 vpi 注解解析抽成唯一实现,两处共用)与 _apply_auto_addr_to_call_args(同模块先查 AutoAddrModes,跨模块回退 vpi 注解)。接入原先完全不查表的路径:虚分派(原在 vpi 取址前 return)、_call_method_on_ptr 覆盖的构造 __new__/__init__(含泛型)与 dunder 分派、属性 getter/setter/deleter、静态/类方法、super()、FakeDuck;属性 setter 由 AssignGenMixin 传入 rhs AST 以支持 &T 取左值地址。
2026-10-07 19:59:52 +08:00
TermiNexus 5c1b882169 chore(gen): c.CIf 家族移除报错覆盖 CElif/CElse/CEndif,注释口径统一为 cif
ExprGenName / CallGenDispatch 的「已删除拼写」守卫原本只认 CIf/CIfdef/CIfndef,现补齐 CElif/CElse/CEndif 六个(与 TPC 侧一致),报文同步;StmtGenCifMixin 的头注释、docstring 与状态注释把语句统一称作 cif,内部标记仍写作 c.@CIf 族。
2026-10-07 19:10:05 +08:00
TermiNexus 2fb648d68a feat(lang): 新增 cif/celif/celse 条件编译与值引用注解 &T/&temp T,assert 改译 testcheck.check
cif 三件套:StmtGenCifMixin 负责常量求值(含 defined(模块宏) 的 Attribute 形式),链式错配与含运行时变量一律 fail-fast;删掉 c.CIf 家族。值引用:TypeGenResolve 让 CRef/CTempRef 与 t.CPtr 走同一解析路径(&void 折叠为 i8*,删除 t.CNeedPtr),CallGenBase 在调用点按形参模式自动取址(ref 只接受左值,右值 fail-fast;temp 物化临时栈),跨模块经 VpiReader/StubMergerBuild 传递模式。assert:StmtGenMixin 合成 testcheck.check(cond, None, msg),Translator 检测到 assert 时自动注入 testcheck 导入(带去重与防环),深递归守卫改用 stdio.printf + stdlib.exit(Translator 无 Gen 成员)。
2026-10-07 19:03:16 +08:00
TermiNexus ce50daa87a refactor(build): 构建产物目录去掉 _mlir 后缀(temp/output)
TempDir/OutputDir 回归 {BuildDir}/temp 与 {BuildDir}/output,与 TPC 及项目脚本预期一致;mlir_dir_suffix() 仅保留给 includes 二进制缓存(其布局为 sha1 子目录,与 TPC 的扁平 obj 缓存不同,合并会混淆)。
2026-10-07 19:03:02 +08:00
TermiNexus 3b4bd1c6dc fix(gen): 跨模块函数作值时不再伪造同名外部全局
`serial.puts` 这类模块属性指向的是函数(elf.vp 的 _resolve_symbol 返回它作
函数指针),属性兜底路径却为它造了一个 llvm.mlir.global external @<sha1>.puts,
与已有的 llvm.func @<sha1>.puts 同名,mlir-opt 报 redefinition of symbol named。
改为在伪造之前先精确匹配函数符号(目标模块 sha1 前缀过的函数名与 Function.Name
逐字符相等,避免误命中他模块同名函数),命中则返回函数符号引用本身
(@<mangled>,类型 Ptr(Func),与同模块 &f 分支同一形态),并让属性读路径跳过
对该值的 load(函数地址即值,load 会去读函数体)。
EOF
2026-10-07 15:59:54 +08:00
TermiNexus edca6c3760 chore(detsite): 类型文本 4096 缓冲补插桩
19 处 TypePrint(..., 4096, ...) 对应的 pool.alloc(4096) 全部改用 alloc_tagged
(AssignGenMixin/ClassGenVTable/FuncGenDef/ExprGenBase/ExprGenCdef/CallGenLeafKit/
TypeGenCType/TypeGenResolve/CallGenCBuiltin/ExprGenOps),tag 33..51 见 memhub.vp。
detection==0 时 alloc_tagged 直接转发,无布局与性能变化。
2026-10-07 15:16:52 +08:00
TermiNexus f3628a797a fix(global): 修复存储结构体字段零值文本的池缓冲溢出
_stg_field_zero_text 分配 160 字节,却用 snprintf(buf, 576, ...) 写出,长类型文本
(如 !llvm.array<8 x i8> zeroinitializer)可越界 415 字节,写穿相邻空闲块的元数据,
触发 [MEM] _fl_pop / [FREEFRAME] 空闲块被写穿(内核编译在 PhaseA 45/50 处中断)。
按实际类型文本长度分配(strlen+24),并把 snprintf 上限与分配对齐。

本文件同时含 3 处 DETSITE 插桩(elem_ty_str_n / ty_str / ty_buf_v)。
2026-10-07 15:16:47 +08:00
TermiNexus 12b15958c6 feat(global): 支持模块级符号地址初始化器
新增 init_kind=5(符号地址):分类阶段识别 UnaryOp(AddrOf, Name),不再把它
误送进整数常量提取器;发射阶段取模块作用域里该全局的引用文本(@mangled /
@mangled 带引号两种形式)作为初始化器,MLIR 层渲染为 llvm.mlir.addressof。
类型/操作数/引用目标不合法时按 fail-fast 报错。

复现:_v: int = 1 / _p: rawptr = &_v
      修复前报 CDefine value extraction failed(该分支原假设所有 UnaryOp 都是负数/取反字面量)
2026-10-07 14:54:44 +08:00
TermiNexus 5993affd9c fix(type): const 等限定联合不再被误判为 str*/bytes*
_is_ptr_element_annotation 原先只要注解联合里出现 str/bytes 就返回 1(按 i8** 处理,
8 字节元素步长),于是 const str(t.CConst | str,实际仍是 i8*)的下标取到的是指针。
现在要求联合必须带 CPtr 标记(真正的 str*/bytes*)才判定;模块级全局的同一处逻辑
(TranslatorGenMixin)同步收紧。新增 _annotation_has_cptr_marker 供两处复用。

复现:def F(p: str) -> int: / path: const str = p / ch: char = path[i]
      -> CastError 指针转整数(形参位置的 const str 一直正常,仅局部/全局错)
2026-10-07 14:35:25 +08:00
TermiNexus fb3d3787e6 refactor(build): linker.cmd 由绝对路径改为裸名,--asan 提示文案去硬编码
- project.vpj / repl.vpj 的 linker.cmd 改为 clang++.exe,交由 PATH 解析

- main.vp 的 --asan 运行库提示改用占位符路径,并说明 clang64 根目录由 PATH 自动探测
2026-10-07 11:25:38 +08:00
TermiNexus 36d23d2f42 feat(build): 实现 Qt 运行时依赖部署(runtime.qt6_path / qt6_dlls / qt6_plugins)
背景:project.vpj 里的 runtime 块此前只是声明(编译器不读取),Qr 程序运行时报 Could not find the Qt platform plugin "windows"。

实现:链接成功后(Phase2 的 PhaseC 成功点)调用 BuildPipeline.deploy_runtime_deps(exe_path)——把 qt6_dlls 各项从 <qt6_path>/bin 复制到 exe 同目录;把新增的可选字段 qt6_plugins 各项从 <qt6_path>/plugins 复制到 <exe 目录>/<相对路径>(父目录不存在则 mkdir)。Config.vp 新增 Qt6Path/Qt6Dlls/Qt6Plugins 读取(口径同 LinkerStaticLibs)。

fail-fast:声明了但源文件不存在 / 复制失败 / mkdir 失败 => VLogger.error 并中止构建;三字段全未声明则整段跳过。

验证:重编 SUCCESS(210.11s);ViperMNIST 产物含 7 个 Qt6*.dll + platforms/qwindows.dll,实跑 stderr 无插件报错;ViperAIChat / ViperQtHelloWorld 同样 OK 并完成部署。
2026-10-07 09:08:35 +08:00
TermiNexus 848dc0ab38 fix(compiler): 跨模块调用补全 int→ptr 转换与别名默认参数;类型文本缓冲 512→4096
1) CallGenMixin.vp(跨模块 extern 实参提升):指针目标形参改为无条件走 coerce_to_type——原守卫按整数位宽比较,而指针类型的 bits 恒为 0,整段提升被跳过,致 VirtualAlloc(0,...) 以 i32 传入指针形参、mlir-opt 报 operand type mismatch(ViperAIChat 失败)。

2) CallGenMixin.vp(默认参数限定键):改用 StructGen._resolve_module_sha1 解析模块 SHA——原只精确匹配模块名,import x as y 这类别名取不到真实 SHA,默认值表落空、跨模块调用实参数目不符(ViperRequestsTest 失败)。

3) 11 个文件的 TypePrint 类型文本缓冲 512→4096(分配与传入 size 成对修改):48 字段类(如 MNIST 的 Net)的 MLIR 结构体类型文本超过 512 被截断并 fail-fast。
2026-10-07 08:48:09 +08:00
TermiNexus 7a9bc5ae75 chore(messages): TransPyV 运行时中文字符串英文化
把 TransPyV/App 下 57 个文件的运行时中文字符串(编译器报错/告警/日志、CLI 帮助与横幅、REPL 提示、Phase1/Phase2 流程日志、Codegen 各 Mixin 的类型与调用报错、Stub/Vpi 诊断等)共 1091 行译为英文。

口径:只改字符串字面量内部文字,行数零变化(+1092/-1092);printf 格式符与转义序列多重集合校验不变(_strcheck 异常 0);译文不引入撇号以免干扰单引号字面量解析。验证:三重重编 SUCCESS(136.20s)+ 全量 77/77 顺序回归通过 + VET 编译 SUCCESS / --search-paths 7 条 exit 0;新产物 help/日志输出已为英文。
2026-10-07 00:03:58 +08:00
TermiNexus 0cf80632c1 feat(gen): typedef 源文本归一 C 式 const/T*(R16)
TPV 的 typedef 注册走裸源码扫描,需与 TPC 同形:_parse_typedef_line 把右值的前导 const/volatile 归一为 t.CConst | / t.CVolatile |、末尾 * 归一为 | t.CPtr;register_ctypedef_from_source 的缓冲 320->512 以容纳展开后的文本。
2026-10-05 20:36:40 +08:00
TermiNexus 374921623b fix(gen): 补全新语法 &/* 的取地址与解引用路径
(*p).attr 属性基址:_get_cderef_attr_base 增加 UnaryOp(Deref) 分支(读写都要求 GEP 指针本身,而非加载后的结构体值)。_is_addrlike_call 增加 AddrOf/Deref 分支:指针型右值不应走模块全局的『静态存储对象拷贝』分支。
2026-10-05 19:58:45 +08:00
TermiNexus df2de5ecfa refactor: 去 t.CPtr(&a) 冗余包装(R15)
TransPyV 4 文件 / 7 行:Phase/BuildPipeline.vp、core/Gen/AssignGenMixin.vp、core/Gen/TranslatorGenMixin.vp。验证:自举三重重编 SUCCESS + 全量 77 项顺序回归通过。
2026-10-05 17:55:52 +08:00
TermiNexus cd55a7e214 refactor: rawptr[T] -> T*(R14)+ 修 REnum 前向占位未就地填充
R14:rawptr[X] -> X*(56 文件 / 834 行改动);保留 6 处 rawptr[t.CPtr](存纯裸指针的规范例外)。 修复:class X(t.REnum) 的变体字段写成自引用 X* 时,字段解析在变体扫描期经 ensure_forward_class 建了一个 opaque 前向占位;末尾 register_struct 按 Ty 指针去重会再建第二个同名 entry,而 find_struct 取首个(占位,0 字段)→ X.__sizeof__() == 0,报「已注册但大小为 0(字段链表未填充)」。改为注册前若命中同模块前向占位则就地填充(与 ensure_forward_class 文档口径一致)。TPC 无此问题,属 TPV 侧缺口。 验证:自举三重重编 SUCCESS;全量 77/77 顺序回归通过(修复前卡在 LLvmLiteTest)。
2026-10-05 17:38:28 +08:00
TermiNexus aeb4e8e54c refactor(gen): R12 收尾同步——12 处计数 while 循环改 for range
与 includes 同步:<= 条件转 range(expr + 1),并放宽初始化行的紧贴要求(同块内最近一次写即为初始化即可)。其余保守守卫不变。

验证:bootstrap 三重重编 SUCCESS;全量 77/77 顺序回归通过。
2026-10-05 16:36:36 +08:00
TermiNexus fb53f88893 refactor(gen): R12/R13 同步——下标 while 循环改 for range、去 c.Set
与 includes 同步执行两批源改写:R12 把「i: int = 0 与 while i < N: … i += 1」形式的计数循环改写为「for i in range(N):」;R13 把 c.Set(*p, v) 迁移为 *p = v、c.Set(a, b) 迁移为 a = b(c.Set 是正在退化的路径)。

验证:bootstrap 三重重编 SUCCESS(无 vast_c 解析回退);全量 77/77 顺序回归通过(WebTest 首轮网络超时,单独重跑通过)。
2026-10-05 15:33:58 +08:00
TermiNexus a7b8118ce8 fix(call): c.Set 支持 Starred 解引用目标(*p 在实参位被解析为 Starred)
新规范把 c.Set(c.Deref(p), v) 改写成 c.Set(*p, v),而实参位的 '*' 由 ast/parser.vp 解析为 Starred(value=p, ctx=Load),translate_c_set 只认 c.Deref/Call 与 Name 形态 ⇒ 整条 store 被静默丢弃。

后果:zlib 侧 includes 全部 47 处 c.Set(*out_len/*out/*length/*cap/*buf/*best_dist/*p_done, ...) 失效 —— 压缩结果长度恒为 0(decompress 报 Z_DATA_ERROR -3),ZlibTest 运行期 0xC0000005。现按 UnaryOp/Deref 与 Starred 两种形态统一走解引用写入,并对非指针目标 fail-fast。
2026-10-05 14:35:50 +08:00
TermiNexus 87b24c2445 fix(type): resolve_typedef_or_map 补齐裸内建别名,修复 int(x, t.CPtr) 类型解析
裸名 str/bytes/int/char/bool/float/double/void 在 map_t_type 中只有 t.CXXX 拼写,导致 _tc_h4 的双参指针包装分支拿不到 bare_ty,落回外部函数返回类型兜底并 fail-fast(argparse.vp:93 c.Deref(int(uint64(ptr), t.CPtr)) 报 TypeError: int)。
2026-10-05 14:14:29 +08:00
TermiNexus 0f4aeeceff docs(tpv): R11 注释与 docstring 英文化并压缩到 2 行内
按 wiki/新规范:注释只讲作用、不掺杂历史原因、避免超长、尽可能英文(含三引号 __doc__)。全文 79 个 .vp:# 注释 16269 行(中文 13808)与 docstring(中文 1381 处)全部改英文;超 2 行的注释块(2093)与 docstring(397)全部压到 2 行。运行时可见文本未动(fatal_error/VLogger 的中文报错文案、stdio.printf 的横幅格式串)。校验:屏蔽注释与三引号后逐行比对各文件代码骨架,0 漂移。验证:自举重建 153.48s 通过(跨模块内联完成);TPV 顺序回归 77/77 全通过。
2026-10-05 13:38:22 +08:00
TermiNexus a2874a14e6 chore(tpv): 移除 --allow-multiple-definition 兜底并同步缺省链接参数
main.vp 的缺省 linker flags 与 ViperBuild 内置 _c_linker 默认值去掉 -Wl,--allow-multiple-definition,与 project.vpj 同口径;Phase2 三处引用该 flag 的注释改为描述链接器选 main / 链接前按路径去重的实际机制。重建验证:跨模块内联优化完成、链接成功 139.17s。
2026-10-05 09:22:58 +08:00
TermiNexus e79ea010b0 fix(tpv): 消除 PYI_BUF_SIZE 跨模块重复全局并去掉 --allow-multiple-definition 兜底
Phase1 与 BuildPipeline 各自把 PYI_BUF_SIZE 声明为模块级全局,模块级全局走裸名符号(类 C extern 全局语义),两模块各发一份强定义 @PYI_BUF_SIZE,llvm-link 报 symbol multiply defined 并回退到单独编译。改为编译期宏 define PYI_BUF_SIZE = 262144(与同文件 define SRC_BUF_SIZE 同口径,不产生符号),同步更新引用该符号的非 CDefine 示例注释。project.vpj 移除 -Wl,--allow-multiple-definition 兜底。验证:跨模块内联优化完成,最终链接无该 flag 成功(161.70s);TransPyV 自举产物顺序回归 77/77 全通过。
2026-10-05 09:16:12 +08:00
TermiNexus f2ef1bb240 refactor(tpv): 新语法 R10 括号内隐式续行并一行(1140 处 / 67 文件) 2026-10-05 07:14:14 +08:00
TermiNexus 4a685d478f refactor(tpv): 新语法 R10 单语句块并一行(7722 处 if/for/while 单语句体) 2026-10-05 03:10:55 +08:00
TermiNexus f923dc4d8d chore(tpv): 删除已废弃的 Test 目录(回归测试保留在仓库外 Test/) 2026-10-04 23:10:44 +08:00
TermiNexus 30a3da4cd4 refactor(tpv): 新语法 R10(反斜杠续行合并)+ 回退 R5(语义不等价)
- 反斜杠续行合并为单行(304 处),呼应"尽可能不换行"。
- 回退 c.DerefAs(p, v) → *p = v 两处(StructGenMixin):原写法是 bitcast 后
  store 指针位,新写法按 pointee 值类型赋值,类型不符(i8* → List 值),
  语义不等价,保留 c.DerefAs。

种子自举通过。
2026-10-04 22:56:27 +08:00
TermiNexus 185a2196ca refactor(tpv): 迁移新语法 R1/R2/R7/R8/R3/R4/R5(指针 T*、短别名、define、&/*、__asm__)
按 wiki/新规范:
- T | t.CPtr → T*(无 | 标准)
- t.CInt/t.CUInt64T/t.CChar/t.CDouble 等 → int/uint64/char/double 等短别名
- X: t.CDefine = Y → define X = Y
- c.Asm → __asm__,c.AsmInp/c.AsmOut → asminp/asmout,t.ASM_DESCR. → ASM_DESCR.
- c.Addr(x) → &x,c.Deref(p) → *p,c.DerefAs(p, v) → *p = v

种子自举通过(96s)。
2026-10-04 22:49:01 +08:00
TermiNexus 9717ce0107 feat(traceback): 运行期调用栈显示 callsite 行号(编译器旁文件 + 链接后 objdump 归一)
MLIR 后端下 mlirlite 只记录 DI 不输出、且 mlir-translate 不产 !dbg(实测),
导致我方 .vp 函数在最终 exe 无任何 .debug_line(<exe>.stackmap 只剩 mingw CRT
的 C 源记录)→ 用户代码帧只能显示 line 0。

改为 Route A:--traceback 时编译器记录每函数(F)与每次调用(C,含调用点行),
写 <sha1>.vpcall;链接后 WriteStackMap 用 llvm-objdump 反汇编,把 callq 的
返回地址 RVA 按 (调用方,被调方,出现序号) 匹配到调用点行,并在函数入口写定义行
兜底;合并进现有 .stackmap 格式。运行期 traceback.vp 不改。

验收:PtrOpProbe --traceback 生成 427 条我方记录(抽查 main 的 malloc/printf
等行号与源码逐一吻合);非 --traceback 构建零旁文件、产物与运行结果不变。
2026-10-04 22:38:02 +08:00
TermiNexus 4236127956 fix(tpv): f-string 隐式 snprintf 声明形参 buf/fmt 用 i8* 而非裸 i8
f-string 降级为 snprintf 时按"隐式提供"原则在使用点补 declare,但三段固定
参数里的 buf/fmt 误写成数组元素类型 i8(应为指针 i8*),与调用侧传入的
buf_ptr/fmt_ptr(i8*)不匹配 → MLIR 'llvm.call' operand type mismatch
'!llvm.ptr' != 'i8'(ZlibDbg 编译失败根因)。改为 Ptr(i8)。
2026-10-04 20:51:38 +08:00
TermiNexus 68cd5f2f90 fix(tpv): __new__ 截断条件放宽到 nn_pc>=1(源侧 __new__ 可无参数)
OopInheritTest 报:
  error: 'llvm.call' op incorrect number of operands (4) for callee (expecting: 1)
      %16 = llvm.call @"...Vec3.__new__(%0, %5, %10, %15) : (!llvm.ptr, f64, f64, f64) -> !llvm.ptr

源码 `def __new__() -> 'Vec3' | CPtr:` 无参数(TransPyV 只注入 self),
__init__(self, x, y, z) 才收 x/y/z。上一提交的截断条件写成 nn_pc > 1,
nn_pc == 1 时被跳过 ⇒ 仍多传 3 个。放宽为 nn_pc >= 1(裁到只传 self)。

验证(均已跑通):
- OopInheritTest:PhaseB 编译完成 → PhaseC 产出 OopInheritTest.exe → 完成
- SlotsBugTest:同上(无回归)
2026-10-04 20:15:37 +08:00
TermiNexus 58cfe2346e fix(tpv): __new__ 调用按被调方签名截掉多余尾参
mlir-opt 报:
  error: 'llvm.call' op incorrect number of operands (8) for callee (expecting: 7)
      %245 = llvm.call @a959d1abdb31a471.FunctionDef.__new__(%35, %239, %240,
             %241, %242, %243, %is_async, %244) : (...) -> !llvm.ptr

定义/声明侧(ast/stmts.vp vpi 核实):
  FunctionDef.__new__(self, pool, name, args, decorator_list, returns, is_async)
      = 7 个形参(非-self 6)
  FunctionDef.__init__(..., is_async, type_params = None)
      = 8 个形参(非-self 7,多出的 type_params 有默认值)

根因:构造器路径把 ctor 实参**全量**转发给 __new__,而 __new__ 的签名比
__init__ 短(无 type_params)⇒ 调用点传了 7 个非-self 实参,声明只收 6 个。
(临时探针实测:mdf_param_count=6 正确、封参逻辑未触发,extra_count=7 才是不匹配源。)

修复:_call_method_on_ptr 中对 method_name == "__new__" 且已找到 declare 时,按被调方
非-self 形参数截掉多余**尾参**(这些尾参 __new__ 本就不接收,语义上由 __init__
消费;__new__ 只负责分配存储)。探针已删除。

验证:python ./TransPyC/Projectrans.py --project ./TransPyV/project.vpj --clean
      --rebuild-includes --clear-cache 重编通过;
      ./TransPyV/output/TransPyV.exe --project ./Test/SlotsBugTest/project.json
      PhaseB 编译完成 → PhaseC 产出 SlotsBugTest.exe → TransPyV 完成。
2026-10-04 20:09:21 +08:00
TermiNexus 6a6cae2a44 fix(tpv): 模块限定调用优先用 vpi 定义侧形参类型,Win32 白名单降为兜底
mlir-opt 报:
  error: 'llvm.call' op operand type mismatch for operand 2: 'i64' != 'i32'
      %5 = llvm.call @VirtualAlloc(%c6, %2, %3, %4) : (!llvm.ptr, i64, i64, i64) -> !llvm.ptr

声明(真值):extern def VirtualAlloc(VOIDPTR, sizet, ULONG, ULONG) -> VOIDPTR
           ⇒ llvm.func @VirtualAlloc(!llvm.ptr, i64, i32, i32)

根因:调用点 found_func 为 None 时用 `_get_external_func_param_ty` 硬编码白名单,
它把 Win32 API 的**所有**非指针参数一律当 i64(注释依据"DWORD/ULONG 在 stubs 里
被映射为 i64"的旧口径),而现实中 ULONG → i32 ⇒ 字面量被 sext 到 i64,与声明
i32 不匹配。

修复:CallGenMixin 的参数 coerce 分支(found_func is None)改为**模块限定调用
先用定义侧 vpi 形参注解**(`_resolve_vpi_param_annot_seg`,模块级函数段下标 ==
形参下标)取真实类型;拿不到注解才回退白名单。CallGenLib 的该函数补注释,
标明它是**兜底专用**且 Win32 口径已过时。
2026-10-04 18:17:51 +08:00
TermiNexus b7e4861e6c fix(tpv): vpi 返回注解纯 marker(t.State 等)解析为 void,修 void 调用被当 i32
调用侧 `_resolve_vpi_ret_annot_str` 只把 `t.CVoid` 映射为 void,纯 `t.State`
(存储类装饰器标记)会解析失败返回 None → 调用侧回退外部函数白名单默认 i32。

现场(MLIRLiteTest):`includes/stdlib.vp` 的 `extern def exit(status: int)`
在 stdlib 的 vpi 中是 `def exit(status: int) -> t.State: pass`,于是生成
  %6 = llvm.call @exit(%c3) : (i32) -> i32
而模块声明是 `llvm.func @exit(%status: i32)`(void),mlir-opt 报
  'llvm.call' op calling function with void result must not produce values

修复:在 `_resolve_vpi_ret_annot_str` 增加"纯 marker 注解 → void"分支,与
declare 注入路径 `_inject_module_declare` 的 is_pure_marker_rt 判据同口径。
仅**纯** marker(`t.State` / `t.CExtern` / `t.CExport`,可带 t./c. 前缀)
才归 void;`HANDLE | t.State` 等含真实类型的注解仍由段循环返回真实类型。
2026-10-03 21:51:13 +08:00
TermiNexus 94b174c8a0 fix(tpv): 补齐 asm_arg_cap 声明与嵌套数组 element 预算漏改
上一条提交(3426139)中两处改动实际未落盘(编辑动作报告成功但文件内容未变),
导致 TransPyC 编译报 NameError: 未定义名称 'asm_arg_cap'。

- CallGenCBuiltin:补 asm_arg_cap 声明(按操作数个数给足内联汇编实参表容量),
  args_buf 改用该容量分配(此前 4 处用法已改为 asm_arg_cap,声明却缺席)
- TranslatorGenMixin:嵌套数组 element 预算 192 → 768(含子数组类型前缀)
2026-10-03 21:17:41 +08:00
TermiNexus 3426139d03 fix(mlir): TypePrint 输出缓冲按 MLIR 类型长度放大;初始化器文本按类型长度给足
MLIR 类型文本内联具名结构体完整字段体(可达数百字节),旧的短缓冲会截断类型
文本、产出畸形 MLIR(mlirlite 侧 TypePrint 现已对截断响亮报错,此处补齐容量)。

- 10 处 TypePrint 调用点及其缓冲统一放大到 512:
  AssignGenMixin / TranslatorGenMixin / CallGenCBuiltin(×2) / CallGenLeafKit /
  ClassGenVTable / ExprGenBase / ExprGenOps(×4) / FuncGenDef / TypeGenResolve(×2)
- TranslatorGenMixin:
  - _stg_field_zero_text 缓冲 160 → 576(元素 = 类型前缀 + 值)
  - _default_val_const_text 缓冲 48 → 576
  - 嵌套数组 element 预算 192 → 768(含子数组类型前缀)
  - storage 结构体 element 预算 160 → 576
- CallGenCBuiltin:内联汇编实参表按操作数个数分配(原固定 512,一个结构体
  操作数即溢出)、汇编行缓冲按实际长度分配
2026-10-03 21:08:30 +08:00
TermiNexus d0434bf114 fix(repl): 片段导出符号探针改用 MLIR 形态 llvm.func;布局恢复文案改指 {sha1}.meta
- Repl.vp ⑧ 探针由 "define i32 @名(i8* %__repl_ctx__" 改为
  "llvm.func @名(%__repl_ctx__: !llvm.ptr) -> i32"(单端后 dump 出的是 MLIR 文本)
- VpiReader.vp REPL 布局恢复的注释/报错/汇总文案 .stub.ll → {sha1}.meta
  (数据源早已是 meta:_repl_stub_collect_module 读 {sha1}.meta,
   _repl_meta_scan_layout 解析 STRUCT/VTABLE;本次只改文案与注释,无逻辑改动)
2026-10-03 19:58:37 +08:00
TermiNexus cbf76cd468 fix(callgen): text.ll 返回类型回退支持 MLIR 形态 llvm.func
- _CacheModuleRetTyTexts 同时认 define 行与 mlirlite 的 llvm.func 行(含缩进/void 省略 ->/变参)

- 缓存值以 '#' 前缀标记 MLIR 形态,命中时用新增 _ParseMlirRetTyStr 解析

- _ParseMlirRetTyStr 覆盖 none/iN/f16..f128/!llvm.ptr/!llvm.array/!llvm.struct(具名按登记表回查,未登记返回 None 不臆造)

- 背景:单端 MLIR 后 text.ll 无 define 行,回退恒空 ⇒ 指针返回值退回默认 i32 被 inttoptr 截断
2026-10-03 19:45:47 +08:00
TermiNexus 7b3e814524 refactor(backend): 单端 MLIR —— 发射器全树改名 mlirlite 并删除 --backend 开关
- App/Test 的 .vp 中 llvmlite 全部改名为 mlirlite(import、限定名、类型注解、注释)

- 删除后端开关:Config.set_backend/is_mlir_backend/alias_module_name、BackendTarget/BackendIsMlir、CLI --backend、options.backend/options.target 读取,以及 IncludesScanner/StubMergerIR 的模块别名调用

- BuildPipeline 的 mlir-opt -> mlir-translate 降级管线去掉开关门,改为恒执行

- backend_dir_suffix 改名 mlir_dir_suffix 并恒返回 _mlir:TempDir/OutputDir/includes 缓存继续落在 *_mlir,避免复用旧 LLVM 后端的 .ll/obj

- project.vpj 删除已失效的 options.target
2026-10-03 19:26:24 +08:00
TermiNexus 1dcd29db9c fix(phaseb): llc 并行失败按阶段定位,不再一律报 llc 编译失败
- LlcTask 追加 FailStage 字段(0=未失败/1=mlir-opt/2=mlir-translate/3=ASan opt/4=llc),worker 在各步失败时写入

- run_llc_parallel 按 FailStage 打印真正失败的阶段名与对应命令:MLIR 后端下 mlir-opt/mlir-translate 失败此前被误指为 llc(现场 .ll 含 LLVM IR 时 mlir-opt 报 unexpected character,日志却指向 llc)

- 字段追加在结尾,所有 stride/memset 均按 LlcTask.__sizeof__() 计算,既有偏移不变
2026-10-03 19:01:50 +08:00
TermiNexus cda4cca805 refactor(generic): 类型实参符号判定复用 spec_sign_of_annot
- 两处 Call 推断由 SpecSignFromTypeNameSpan 改为 TypeGenCType.spec_sign_of_annot,复用注解侧唯一真源(精确名白名单 + CTypedef 链逐层展开)

- 收益:别名(uint64/size_t/WCHAR->WORD->uint16 等)也能判出符号性,不再是裸白名单的 UNKNOWN
2026-10-03 18:20:42 +08:00
TermiNexus 2ac412c11a feat(generic): 泛型实参推断补齐全部内建标量位宽的精确票名
- 整型按 位宽×符号性 全覆盖:i8 -> t.CUInt8T/char、i32 -> t.CUInt32T/int,i16/i64 维持 t.CUInt16T/t.CInt16T、t.CUInt64T/t.CInt64T

- 浮点补 half -> t.CFloat16T、fp128 -> t.CFloat128T(原仅 float/double,其余返回 None)

- 票名与 TypeGenResolve.map_t_type 的可解析名一一对应;无符号一律不走裸名(避免静默变号),位宽无裸名别名且符号未知时返回 None(宁缺毋错)
2026-10-03 18:19:53 +08:00
TermiNexus f9ba391236 feat(generic): 无符号 i32 泛型实参改发精确票名 t.CUInt32T
- _infer_scalar_type_name_from_spec 对 i32 增加符号性分支:无符号(CUInt32T/CSizeT/CUIntPtrT 等)发 t.CUInt32T,有符号/未知保持裸名 int(位宽无误且与历史逐字一致)

- 修复 CUInt32T 实参经泛型推断被静默变号为 int 的问题
2026-10-03 18:18:21 +08:00
TermiNexus 21436b2690 feat(generic): 泛型实参推断为无裸名别名的整型位宽补精确票名
- _infer_scalar_type_name_from_spec 支持 i64/i16 -> t.CUInt64T/t.CInt64T、t.CUInt16T/t.CInt16T;符号性未知时不猜(返回 None)

- infer_scalar_type_arg_from_llvm_ty 增加 sign 参数:LLVM 类型层无法区分 iN/uN,符号性由被调名源码文本经 SpecSignFromTypeNameSpan 判定

- 泛型函数与泛型类构造两处 Call 推断同步传符号性,修复 GenericOopTest fxi2 第 3 个类型实参(CUInt64T)推断失败
2026-10-03 17:12:47 +08:00
TermiNexus ddb1e6cc2a fix(类型): get_type_size_bytes 补浮点位宽,修复浮点泛型实参的 __sizeof__ 尺寸解析
现象:Test/VectorGenericTest/App/vectortest.vp:32 vector.Vector[CFloat64T] 特化时 vector.vp:12 T.__sizeof__() 报 "NameError: 未定义名称 T(当前泛型上下文: 类型形参 1 个 / 类型实参 1 个)" —— 新增诊断证明上下文是好的(T 能换成 CFloat64T),故问题在 __sizeof__ 快径没接住。

根因:get_type_size_bytes 只用 get_llvm_type_bits 取位宽,而该函数只认整数(Float/Double/Half/FP128 一律返回 0)⇒ 浮点 typedef(CFloat64T 经 map_t_type 已正确解析为 Double)被判"尺寸未知"返回 0 ⇒ CallGenDispatch._tc_h5_sizeof_len_isinst 的尺寸表也不含 CFloat64T(只有 CInt/CDouble/CFloat 等)⇒ 落回"回退 2"把接收者 Name(T) 当实例翻译 → NameError。同文件第 15 行 Vector[CInt] 走整数路径正常,故只有浮点特化暴露(不对称现象由此解释)。

修复:整数位宽为 0 时再取 get_llvm_float_bits(浮点位宽),两者皆 0 才返回 0。
2026-10-03 16:50:42 +08:00
TermiNexus 3a4323e288 feat(generic): 特化上下文自检 fail-fast + NameError 附泛型上下文诊断
背景:VectorGenericTest 在第 32 行 vector.Vector[CFloat64T] 特化时仍报 "NameError: 未定义名称 T"(8af967d 的类模板 tp 名补缺只能覆盖 tp 名缺失那一种,这里 tp 名在场)。静态读完 6 个 _specialize_generic_class 调用点与 ClassGenDispatch 的 __sizeof__ 快径后,无法确定是"上下文没建"还是"建了装不上",故加两处诊断。

1) ClassGenGeneric._specialize_generic_class 在 set_generic_context 之后立刻自检:类型实参个数必须等于模板类型形参个数,且首形参必须能解析成具体类型名;否则 fatal_error 点出类名与特化键(含实参),替代下游 12 行之外那句脱节的未定义名称。

2) ExprGenName 未定义名称报文追加当前泛型上下文(类型形参 N 个 / 类型实参 M 个):形参 0 个=上下文没建,形参>0 且实参 0 个=实参表丢了,皆>0=上下文在但该名不在其中,一眼可分。
2026-10-03 16:38:01 +08:00
TermiNexus da18dd39a4 fix(classdef): 已注册类早退路径补字段类型完整定义
上一条(96dad30)只改了"全新定义"路径的字段扫描循环,但 includes 在 Phase A 预注册、Phase B 重新翻译时走的是 existing 早退分支(ClassGenDef 117-167,只 module_add_named_type 后即 return 0),字段循环根本不执行 ⇒ includes/condition.vp 的 Condition 仍内嵌 opaque 成员、自身 unsized,llc 仍报 base element of getelementptr must be sized。

物证:同一构建里 ThreadingTest 的 main.vp(fb785af4a2aa1a46.ll)因按需调 ensure_struct_def_in_module,已正确拷入 CRITICAL_SECTION/CONDITION_VARIABLE/SRWLOCK 的完整定义;而定义它们的 condition.vp 自身(de351f55b29d33a3.ll)没有 ⇒ 只有定义模块自身体内 GEP 时才暴露。

修复:早退分支在 module_add_named_type 后补调 _ensure_field_types_in_module(Struct/Array 值类型递归补完整定义、Ptr 补 opaque),与全新定义路径同口径。
2026-10-03 16:05:24 +08:00
TermiNexus 96dad309ac fix(classdef): 值类型字段补完整结构体定义,修复跨模块嵌套结构体 unsized 导致 llc GEP 报错
现场:Test/ThreadingTest 编译 includes/condition.vp 时 llc 报「base element of getelementptr must be sized」:getelementptr %Condition, %Condition* %1, i32 0, i32 1。

根因:ClassGenDef 定义类时对字段类型一律只调 module_ensure_opaque_for_type(仅 opaque 声明)。当字段是**值类型**跨模块结构体时,本类体内嵌的成员在 IR 中仍是 opaque ⇒ 成员 unsized ⇒ 本类 unsized ⇒ 本模块内对本类做带字段下标的 GEP 时 llc 报错。现场物证:condition.vp 的 .ll 里 CONDITION_VARIABLE/CRITICAL_SECTION = type opaque,而 Condition = type {CV, CS}。

修复:指针字段维持 opaque(指向物无需在本模块有体);非指针(值类型结构体/结构体数组)改调 ensure_struct_def_in_module 复制完整定义,并配合 _ensure_field_types_in_module 覆盖数组元素。
2026-10-03 15:58:48 +08:00
TermiNexus 28b7437e21 fix(generic): 泛型类构造 Call 实参推断同步收紧,抽出共用精确映射
CallGenCtor._infer_generic_ctor_type_arg 的 Call 分支此前与泛型函数路径同款名字子串猜测(含 Int→int、Float→double),把 CUInt64T/CInt16T 静默归成 int=i32、CFloat32T 猜成 double。改为:把被调表达式交给注解解析器,命中标量才据精确位宽映射;非标量/不可解析仍 fail-fast(保持原有"明确的类型意图却无法解析"报错)。

新增 ClassGenGeneric.infer_scalar_type_arg_from_llvm_ty 作为两处共用的唯一入口(内部走 _infer_scalar_type_name_from_spec),泛型函数路径一并改为调用它,消除重复的 arena/SpecFromLLVMType 样板,保证两处同口径。
2026-10-03 15:51:12 +08:00
TermiNexus 9a80f1df6c fix(generic): 泛型函数 Call 实参推断改为精确类型解析,移除名字子串猜测
原实现按被调名子串猜类型实参(含 Int→int、Float→double 等),把 CUInt64T/CInt16T 一律归成 int=i32,静默窄化/扩宽位宽(禁止静默默认原则);CFloat32T 也会被猜成 double。

改为:把被调表达式本身交给注解解析器 resolve_annotation_type,命中**标量**才据其精确位宽经 _infer_scalar_type_name_from_spec(唯一真源)映射;非标量(构造/普通函数调用)或不可解析一律返回 None,由调用方汇总后 fail-fast 提示显式标注。行为变化:CUInt64T(x)/CInt16T(x) 等无等位宽裸名的转换实参不再被静默猜成 int。
2026-10-03 15:49:58 +08:00
TermiNexus e196d6a28a fix(类型): 模块限定注解支持 from-import 重导出解析
现场:Test/ThreadingTest/App/main.vp:184 `lock: vthreading.Lock = vthreading.Lock()` 报「变量类型注解解析失败」。vthreading.Lock 是重导出(includes/vthreading.vp `from lock import Lock`),Lock 真定义在 lock.vp;普通模块的 from-import 重导出不像包 __init__ 那样登记别名 entry(VpiReader._inject_reexport_class_declare 仅对包 __init__ 触发),故按 vthreading sha1 查 Lock 恒落空。

resolve_annotation_type 的 Attribute 模块限定分支此前未做真定义模块校正:先按原 sha1 查(既有命中情形逐字不变),未命中时再经 _class_true_def_sha1(唯一真源,已在 _normalize_type_name 规则 4b 使用)校正后重查一次,无证据时原样返回不改变行为。
2026-10-03 15:44:49 +08:00
TermiNexus c035a82394 fix(类型): str/bytes 聚合指针检查豁免字符数组衰减,并统一判据真源
误报现场:includes/os/_win32.vp:207 `name: str = find_data.cFileName`。WIN32_FIND_DATAA.cFileName 是 [260 x i8],字段访问得到 Ptr(Array(i8,260)),其指针在 C 语义下天然衰减为 char*/str,属合法赋值,原判据把 Ptr(Array) 一律当真而误杀。

新增 ExprGenBase._str_rejects_ptr_kind(单一真源:1=结构体/类/联合指针、2=非字符数组指针、3=函数指针、0=可接受;[N x i8] 豁免)供 fail_if_str_annot_agg_ptr 与 CallGenLib 跨模块实参检查共用,消除两处重复的 kind 判定,避免同规则两处演化。
2026-10-03 15:40:01 +08:00
TermiNexus bf2f38acd2 fix(generic): 修正 SpecToLLVMText 返回值判据倒置,恢复内建标量实参的泛型类型实参推断
_infer_scalar_type_name_from_spec 把 SpecToLLVMText 的『0=成功』误判为失败(写成 == 0 就 return None),使该函数对任何内建标量都恒返回 None —— 泛型函数隐式推断中『实参来自内建标量形参/字段』的路径(Name/Attribute 分支)永远推不出,报『无法从实参推断泛型函数 ... 禁止静默默认 int』(现场:GenericOopTest fxi 体内 fxi2(a, b, ...),a: double)。判据改为 != 0(与 ClassGenVTable 同约定)。

同时收紧位宽映射:i16/i64/f16 在 Viper 没有等位宽裸名别名(裸 int=int32、裸 float=float32),原映射 i16/i64->int、half->float 会静默窄化/扩宽位宽(i64->int 即 i64->i32),违反『禁止静默默认/兜底』原则;改为只映射位宽精确对应的形态(i1->bool、i8->char、i32->int、f32->float、f64->double),其余返回 None 交给调用方 fail-fast 提示显式标注。
2026-10-03 15:28:02 +08:00
TermiNexus 09ea7283f9 fix(类型): str/bytes 不再作通用指针通配,补齐实参/赋值/返回三处隐式转换 fail-fast
规则:void*/t.CPtr/rawptr 允许隐式转为任意指针类型,str/bytes 不允许(即便两者在 IR 层同为 i8*)。此前 coerce_to_type 的规则 1(通用指针通配)会把指向结构体/类/数组/函数的指针静默 bitcast 到 str 目标(反向亦然)。

- ExprGenBase:新增 _annot_name_is_bare_str/_annot_is_bare_str(裸 str/bytes 判定,组合段如 str|t.CPtr 不受影响)、fail_if_str_annot_agg_ptr(值是指向聚合类型的指针则 fail-fast,消息 CastError)、fail_if_str_annot_ast_agg_ptr(AST 注解入口)。

- 返回路径 StmtGenCifMixin.translate_return:在类型转换分支之前用 trans.CurFuncRetAnnot 判定,避免被规则 1 静默 bitcast。

- 赋值路径 AssignGenMixin.translate_annassign:四个分支(global / nonlocal / mod_glob / 局部)在 coerce 前用 aa.annotation 判定。

- 同模块实参 CallGenMixin.translate_call:在参数循环前一次性确保本模块 .vpi 参数注解缓存就绪(同跨模块 CallGenLib 键式:模块级函数 cls=None、段下标==形参下标),循环内按 _vpi_param_annot_seg_is 判定裸 str/bytes。
2026-10-03 14:46:57 +08:00
TermiNexus 8af967db7f fix(generic): 泛型类模板类型参数名补缺 + 空上下文 fail-fast,修复特化方法体 T 变 NameError 2026-10-03 14:34:55 +08:00
TermiNexus 98ee53340f feat(call): 跨模块实参加 str/bytes 形参的 fail-fast(str 不作通用指针通配),并加 vpi 注解段等值判定 2026-10-03 14:23:12 +08:00
TermiNexus feb29fa7a3 fix(generic-func): 发射特化调用改传符号名(callee: str)而非 Function*,修复生成空 @ 的非法 IR 2026-10-03 14:18:14 +08:00
TermiNexus df1ffa4c2a refactor(subscript): 删除调用侧下标 zext 与 _zext_index_to_i32,统一交给 build_gep(单一真源) 2026-10-03 13:35:36 +08:00
TermiNexus bcbc7142be fix(subscript): 指针下标 GEP 补 zext,修复 i8 下标被符号扩展(uint8ptr[200] -> p[-56] 越界),zlib 漏计字节>=128 根因 2026-10-03 13:20:11 +08:00
TermiNexus ab0ee723b3 fix(classgen): 补 import llvmlite,修复 llvmlite.LLVMType/Int32 解析不一致导致的指针隐式转换 fast-fail 2026-10-03 13:01:42 +08:00
TermiNexus 2868798f58 fix(classgen): 补声明 GenericFunc* 五个类字段,修复 GenericFuncKeys 成员查找 fast-fail 2026-10-03 12:54:56 +08:00
TermiNexus 63acb2bf4d fix(fstring): 使用点按需补 @snprintf declare,f-string 不再依赖显式 import stdio 2026-10-03 12:46:30 +08:00
TermiNexus f2b65f57ec fix(match): case A | B 的 OR 模式注册全部备选(switch 仅取首个)
_handle_simple_match 的 MatchOr 分支此前只把 pats[0] 译成 case 值 → switch value: case 1 | 2 中 2 落 default(LogicFlowTest SwitchMultiValueTest(2) != 10)。改为按臂记录 MatchOr 节点,建 sw 链时逐备选 new_switch_case 挂同一 body(等价 C 的 case 1: case 2:);_handle_guarded_simple_match 同款:cond 改为各备选 subj==cv 的 OR 再与 guard 取与。非 MatchOr 路径逐字不变;非值备选改为 fail-fast(原为静默丢弃)。
2026-10-03 12:11:43 +08:00
TermiNexus 3b465121cd fix(call): kwargs 调用路径补齐省略形参的默认值
_translate_call_with_kwargs 此前对「位置/关键字均未提供的形参」直接跳过 → 调用实参数 < define 形参数,被调函数按 ABI 读未写寄存器/栈槽(remote.one(x = 1) 的 cap 读成 0,DefaultArgTest 断言失败)。改为:按 found_func mangled 名前缀取定义模块 SHA1,用全局默认表 find_func_defaults 取定义处默认值快照补齐(右对齐索引);取不到默认值时 fail-fast,绝不静默漏参/填零。跨模块默认值通道本就通(vpi 带默认值),无需改产物格式。
2026-10-03 12:08:32 +08:00
TermiNexus 692998820c feat(generic): 泛型函数类型实参推断与单态化
支持 def f[T](x: T) -> T 及 f(x)/f[T](x):模板注册(Phase1Scan/Phase2 顶层 FunctionDef,键 {sha1}.{name})、按形参注解对齐从实参推断类型实参(无来源即 fail-fast,不静默默认 int)、克隆模板并 set_generic_context 后翻译生成特化体(名字 {sha1}.f[int],规范化复用 _mangle_generic_class_name)、同签名去重、跨模块按模板签名补 declare。泛型函数模板不再发 vpi(模板签名含未绑定 T),也不再发射 int 兜底版本。已知限制(未静默):bound [T: bound] 解析期已被丢弃;t.CExport/t.CExtern/t.State 泛型函数、关键字/默认参数调用、mod.f[T](x) 显式下标等暂 fail-fast 或走既有报错。
2026-10-03 11:59:26 +08:00
TermiNexus 1fbebb2a62 fix(type): 普通模块 from-import 重导出类的归属模块校正
_class_true_def_sha1 在 cand 模块下查不到该类时原样返回 cand_sha1;而普通模块(非包 __init__)的 from X import Y 重导出不登记别名 entry(VpiReader._inject_reexport_class_declare 仅对包 __init__ 触发)。于是 vthreading.Lock(vthreading 仅 from lock import Lock)的前向声明被错误建在 vthreading 模块下 → 方法返回类型查询去读 vthreading 的 text.ll/vpi(无 Lock.acquire)→ fail-fast(ThreadingTest 根因)。补:先查全局 re-export 内存表 lookup_reexport,未命中再按需解析 .vpi 的 from-import 定位源模块,取其真定义 SHA1(源为包时按同一 IR 名前缀口径继续校正);无证据时行为不变。
2026-10-03 11:37:27 +08:00
TermiNexus 18f4c2326f fix(match): REnum match 变体字段绑定前确保跨模块结构体完整定义
_bind_variant_fields 对 renum_ty 做带字段下标的 GEP,LLVM 要求被指结构体 sized;而模块内对跨模块 REnum(如 llvmlite.__types.LLVMType)只有签名扫描产生的 type opaque,作 GEP base element 时 llc 报 base element of getelementptr must be sized(LLvmLiteTest 根因)。其它取字段路径在 GEP 前都会调 ensure_struct_def_in_module,唯独 REnum match 绑定漏了。补上该调用(同名原地替换 opaque,非追加;本地非跨模块类型自动跳过)。
2026-10-03 11:21:41 +08:00
TermiNexus 105456e56e feat(type): 泛型类注解必须带类型实参,裸名 fail-fast
resolve_annotation_type 入口集中守卫:注解(或其 A | t.CPtr 一侧)的基名(Name.id / Attribute.attr)是已注册泛型模板却没写 [...] 时 fatal_error,报文给出正确写法示例(vector.Vector[CInt]、GSList[G5Node])。判据复用 _find_generic_template(按项目注册),非泛型同名类(struct_test 的裸 Box、dict)不误报;Subscript 形态不受影响,仍走 _resolve_generic_subscript_ty 与 _fail_on_degenerated_generic_annotation。自举源码 includes/** 与 TransPyV/App/** 已确认无裸泛型注解。
2026-10-03 11:16:42 +08:00
TermiNexus 8da4550d79 fix(vpi): 全局变量注入补自注入守卫,消除同模块 external global 与定义重名
循环 import(os/__init__ 导入 os._win32/os._posix,而二者又导入包 os)使 imported_modules 含本模块包名 → LoadDepVpiIntoModule 命中本模块自身 sha1 → _inject_global_variable_declare 为本模块自己的模块级全局发射 @<sha1>.<name> = external global,随后定义端 handle_module_level_var 再发 = global … → llc redefinition of global(SysLibTest 根因)。补上 _inject_function_declare / _inject_method_declare 已有的同款自注入守卫(_declare_only==0 且 src_sha1==trans.ModuleSha1 时早退)。
2026-10-03 11:08:58 +08:00
TermiNexus 19d7a90c28 feat(match): 支持 match/switch 守卫(case X if cond)
通配计数只统计无守卫的 case _,允许多个带守卫的 case _ if ...;_handle_simple_match 预扫描 has_guard,有守卫时改走 _handle_guarded_simple_match(按书写顺序的 if-else 比较链,guard 归一为 i1 后与值比较取与,链尾落 default/end),无守卫时保持原 switch 分派路径逐字不变(零回归);_handle_renum_match 对带守卫臂 fail-fast,避免 switch(tag) 静默忽略 guard。
2026-10-03 10:58:47 +08:00
TermiNexus 67667b10db fix(class): __before_init__ 定义时复用同名前向声明,消除同模块 declare+define
本类方法体内构造自身(如 Vec2.__add__ 里 return Vec2(...))时,构造路径先经 _call_method_on_ptr → _ensure_method_declare 在本模块建好同名 __before_init__ 前向声明(IsDeclared=1);随后 _generate_before_init 又 create_function 追加一条同名 define,使同一模块 IR 同时出现 declare 与 define → llc 报 invalid redefinition of function(OopInheritTest 根因;④ 改用 full.ll 直喂 llc 后不再被旧 BuildCombinedIR 去重掩盖)。改为按名复用该前向声明(命名首参 %self、校准类型、清 IsDeclared 转 define),与 _generate_method/FuncGenDef 同构。
2026-10-03 10:26:57 +08:00
TermiNexus 4c114d8875 fix(call): 泛型模板的前向声明占位不再阻断构造期类型实参推断
注解 vector.Vector | CPtr(无实参)会经 TypeGenResolve 登记不透明前向声明占位 {sha}.Vector(IsForwardDecl=1)。模块限定构造 vector.Vector(...) 在 CallGenMixin 命中该占位后,gen_ctor_entry != None 使泛型推断分支(struct_ty is None and gen_ctor_entry is None)被整段跳过,静默按普通结构体/函数构造并产出裸泛型基类对象 → 后续方法调用触发 D25 接收者 fail-fast(VectorGenericTest 根因)。改为:命中项是前向声明占位且类名为已注册泛型模板时,不锁定 struct_ty/gen_ctor_entry,放行泛型推断按实参(_hint: T)特化;裸名分支与模块限定分支同口径。
2026-10-03 10:18:29 +08:00