Commit Graph
56 Commits
Author SHA1 Message Date
TermiNexus f19d25782f refactor(tpc): 退役 t/c 模块并将定宽类型升级为内建
删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
2026-10-18 13:00:58 +08:00
TermiNexus 15f77da9d3 chore: 改名同步 TransPyV -> ViperC(源码/配置内的纯替换) 2026-10-12 15:06:48 +08:00
TermiNexus d5b4e9a8b9 feat(cdef): define 常量带类型注册——按声明类型物化(DWORD(-11) → i32 位型)
方案 C:CDefine 不再只存无类型 int,而是把**声明整数类型**(位宽 + 符号性)一并登记,使用点按该类型物化,而不是按数值大小猜 i32/i64。链路:① SymbolUtils 新增 DefineIntSignednessOf / DefineDeclIntTypeFromAnnotation(由 T | t.CDefine 注解经符号表 typedef 链解析宽度与符号性)/ DefineDeclTypeValue(按声明类型把值归一成 (位宽, 位型值));② 同模块注册(LlvmGenerator._register_cdefine_constant)与跨模块提取(Phase2Translator._ExtractCDefineConstantsFromPyi,含 _shared_all_decl_types 的 pickle 传递)分别写 Gen._define_decl_types / translator._define_decl_types;③ 物化处(HandlesExpr 裸名两处、HandlesExprAttr._make_define_constant,及 from-import 注册)优先按声明类型出常量。这样 win32file 的 STD_*_HANDLE(DWORD(-10/-11/-12))解析为 i32 位型 0xFFFFFFF5 等,与 GetStdHandle(ULONG) 使用点一致。
2026-10-10 21:20:30 +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 9ff301d747 refactor(types): 移除 list[T, N] 的定长数组遗留判据,统一走 _list.vp
- SymbolUtils.IsListAnnotation 不再把双参 list[type, count] 判为栈上定长数组:
  list 是 includes/_list.vp 的堆上 STL 容器泛型类,list[T] / list[T, N] 都走泛型特化
- ParseListAnnotation / ListAnnotationParseResult / ExtractListFromBinOp 相应收窄为
  只处理 t.CArray / rawarray / array,并同步文档串
- HandlesAnnAssign / HandlesBase / HandlesFunctions / HandlesImports / SymbolUtils 的
  注释改按 CArray 形态表述
2026-10-02 22:16:30 +08:00
TermiNexus b18d57fa38 perf(全仓库/正则): 字面量正则全部改模块级预编译常量(15 文件 / 115 个调用点)
背景(prof 基线 PROF/20260930_224857,主进程 433.69s):正则这一族合计 ≈45s ——
`re.match`(未预编译入口)被调 1970 万次 / 自身 10.70s、它内部 `Pattern.match` 占 8.06s,
`re._compile`(缓存查找)1975 万次 / 7.19s,`re._make`(真正编译)274 万次 / 7.62s
(说明 re 的 512 条缓存已被打穿,每 7 次调用就有 1 次重新编译)。
每次 `re.match(字面量, s)` 都要做"模式串哈希 → 缓存查找";预编译后这层全省掉。

改动:把 15 个文件里 97 处"字面量当模式"的 `re.match/search/sub/subn/fullmatch/
findall/finditer/split(...)` 提升为模块级 `_RE_*: re.Pattern[str] = re.compile(...)`,
共 115 个调用点(含同字面量跨处共用)。模式串与 flags 一字未改(flags 从调用处
搬进 re.compile,含原先以**位置参数**传入的 flags)。4 处拼接型动态模式按设计不动
(FuncGen 2 处、HandlesImports 2 处)。

核验(不靠肉眼):写了 AST 指纹对拍脚本,对每个文件取 HEAD 版与新工作区版,把
"旧 re.<m>(字面量, 其余实参, 关键字) + flags" 与 "新 _RE_X.<m>(实参, 关键字) +
常量 (模式, flags)" 做多重集比对 —— 15 个文件、115 个调用点全部逐一等价(0 失败),
另查无重名常量、无遗留字面量调用、GetDiagnostics 全空。
对拍过程中查出一处子代理抄写错误:`_RE_GLOBAL_DSOLOCAL_MULTILINE` 丢了行首锚 `^`
(原文注释明确"使用 ^ + MULTILINE 避免匹配字符串常量内容中的 define/declare"),已修正。

同轮经查证后**未做改动**的两项(避免把假热点当真事修):
- VLogger 的 `re.sub` 6.43s:profile 当时的 VLogger 版本里根本没有 `import re`
  (`git show 3658ab06:lib/core/VLogger.py` 已确认),属 C 帧错挂,不做。
- tokenize 274 万次:那是 `_generate_tokens_from_c_tokenizer` 的 **token 产出次数**
  (≈350 个整文件的词法量),SymbolUtils 的 4 个 tokenize 调用点 nc 仅数百,且已有
  `_EXPAND_CACHE` 去重;再加一层 token 缓存无收益,不做。
2026-09-30 23:47:36 +08:00
TermiNexus e2c84daa65 fix(Handles): 成员表登记改实时按名判重,消成员表重名条目(AST.children 重复)
类体字段收集循环每轮都可能重入并清空重填同一张成员表(CollectAnnAssignMember → 泛型特化 → _generate_structs → _TryLoadClassMembersFromPyi(force=True) → HandlesImports.py:3415,该 force 分支不受字段收集中保护),而三处只在循环前快照一次名字集合的判据即时失效,会把嵌套帧已登记的同一字段再追加一条:AST 的最后一个字段 children(注解含 list[...] 泛型容器,是全类唯一触发该重入的字段)被登记两次 ⇒ 表 8 项/去重 7 项、重名条目 children@7;该表再被祖先块展平原样拷给 AST 的每个子类 ⇒ StructGen「[结构体布局] 成员表含重名条目」在大量 AST 子类(ExprNode/Stmt/MatchCase/ExceptHandler…)上齐发。三处一律改为实时读表判重(HandlesClassDef 自有字段段与 _PreRegisterClassMembers、HandlesImports 跨模块自有字段段),判据语义与改前逐字相同;自有字段段刻意只跳过本轮循环开始后才出现的同名,以保住字段名遮蔽 fail-fast 与既有布局语义。
2026-09-30 19:31:21 +08:00
TermiNexus 2e7bac1816 fix(HandlesImports/HandlesClassDef): 剥掉"祖先块前缀的陈旧半截副本",消除成员表重名条目
类别:a(编译器缺陷)

现场(用户构建日志):
  WARN[StructGen]: [结构体布局] 类 'ClassGenDef' 的成员表含**重名条目**:
  表 50 项 / 去重 42 项,现有 body 42 槽恰等于「去重名数 + vtable」

判据(磁盘实证 + 结构推导,非猜测):
  · ClassGenDef 自身 **0** 个字段(全是方法),父类 ClassGenBase 恰 **42** 个字段;
    temp / output 两份 stub 的 ClassGenDef body 都是 **42** 槽,且槽序 = ClassGenBase
    的字段声明序 ⇒ body 正确、**表多出 8 条**(50 = 42 + 8)。
  · ClassGenBase 自己的 Phase-1 stub 就是 42 槽(不是 8)⇒ 多出的 8 条并非"父类 stub 短",
    只能来自**内存里父类表尚未收集完就被展平**(写入了半截祖先块 Block[:k],k=8)——
    正是 PrependInheritedBlock 文档里写明的"已知残留"。
  · 重名条目不是布局槽位(见 FuncGen._get_member_offset 的重名段),却让
    _member_base 的 _Delta = 42 - 50 = -8 走进类型校准,并让回退路径的
    base + 表内下标 整体偏斜(同族现场:MatchCase / TypeGenResolve 的偏移算错)。

修复(判据全部为正向事实,且与插入方向无关):
  · 新增 NormalizeAncestralCopies(Table, Block, InsertAtHead) -> (新表, 是否已含完整块):
      ① 完整块在**头**、尾部挂前缀副本 ⇒ 剥尾(副本是被后来的整块前置推过去的);
      ② 完整块在**尾**、头部挂前缀副本 ⇒ 剥头(副本先写入、整块随后追加);
      ③ 完整块尚未出现 ⇒ 剥插入边(仅当这些名字已另有正本,见下)。
    剥掉的每一项在(表里已有的 / 随后插入的)完整块里同名同型 ⇒ **不丢布局信息**,
    与 PrependInheritedBlock 性质①"不删块内条目"不冲突(剥的是副本)。
    第一版曾"两端都剥",离线冒烟立刻暴露会把**正本**当副本剥掉([A,B,C,D,A,B] →
    [C,D,A,B],再前置整块反而多出 C,D 两份)⇒ 改为先定位完整块在哪一端、再剥另一端。
  · TrimStalePrefixCopy 判据:插入边连续游程与 Block[:j] 逐项同 name 同 IR 类型,
    1 ≤ j < len(Block),且这 j 个名字在表里**各另有一份**(计数 ≥ 2)——最后一条把
    "子类自有字段恰好与祖先块前缀同名同型"的误判排除。
  · 两个插入点(HandlesImports.PrependInheritedBlock 前置 / HandlesClassDef 展平追加)
    统一走该函数,判据对称;真正剥除时各留一条 WARN(含条数与前后表长)。
  · PrependInheritedBlock 原有两条幂等提前返回("表头等于块" / InheritedBlockAlreadyPresent)
    合并为 _HasFull 一条(语义等价),并更新其"已知残留"段落。
  · StructGen 的重名 WARN 追加**逐条明细**(名@表内下标):单看"表 50 / 去重 42"无法区分
    "祖先块前缀的陈旧副本"与"两条收集路径各登记一次"(两种成因修法完全不同)。

核验:py_compile + compileall 全 lib 通过;离线冒烟(调用真实函数,8 组用例 × 两个插入方向):
①/② 均 6→4 正确剥除,"无重复 / 带自有字段 / 类型不同 / 无正本 / 空表"均不改动。
未放宽任何 fail-fast。
2026-09-30 18:41:24 +08:00
TermiNexus 83453c68db fix(HandlesImports): 解冻 struct 加载——缓存键缺失也删、索引陈旧定点再读、opaque 条目不再压住好 body
类别:a(编译器缺陷)。三处都会把"该类本 Gen 内始终 opaque"**永久固化**,
下游表现为 Repl.vp:802 `GenApi._g_gen.TypeGenCType.CTypedefNames` 报
"基座 pointee 未匹配 Gen.structs 中任何 struct(同短名候选=['TypeGenCType'],
全部未命中)"——而磁盘上 temp/<sha1>.stub.ll 明明有 41 槽 body。

1) `_TryLoadStructFromStub` 尾部缓存键删除判据:原只在"该键**有**实例且 opaque"时删;
   若索引里**有该类的条目**、而该键此刻根本没有实例(例如只落了 sha1 全名键、短名键
   尚未建立),这一轮的成功缓存被永久留下 ⇒ 之后每次同名查询都在入口直接 return。
   现改为"无可用 body(缺失或 opaque)且索引有条目"即删键,失败可重试。

2) `_entry_priority`:把 `is_opaque` 提到 `is_temp` 之前。原顺序让**陈旧的 output 占位
   条目压住 temp 里已有的好 body**(两侧都有 body 时仍保持 output > temp 原判据)。

3) 新增 `_ReReadStructBodyFromDisk`:`_build_stub_index` 只按"文件名集合"增量,假定
   stub `只增不改`;而 Phase 2 会**原地重写** output/<sha1>.stub.ll(译文生成点 :2194、
   依赖变化重组点 :1785-1790)⇒ 新 body 永不进索引。现在"选中的索引条目没有 body"
   这条失败路径上按磁盘当前内容**定点再读一次**(只读那一个文件,取不到即维持原状)。

静态核验:compileall 通过;全仓 symtable 未定义名扫描 0 条。
2026-09-30 15:44:10 +08:00
TermiNexus 3efe83f1ea fix(编译期名称解析): 修 StructGen 缺 _vlog 导入与 HandlesImports 的 node/Node 误用
两处均为 a(编译器缺陷),且都被 HandlesImports.py:1055 的
`except Exception -> WARN 忽略异常` 吞掉,表现为模块声明静默退化
(本次现场:VpiReader.vp 阶段 WARN + 结构体声明路径中断)。非源码违规、
非机制漏豁免。

1) lib/core/LLVMCG/StructGen.py
   - `_generate_structs` 的「成员表含重名条目、body 已是权威布局」提示调用
     `_vlog().warning(...)`,但本文件从未定义/导入 `_vlog` ⇒ NameError。
     该分支一旦命中(astaux.ExceptHandler 一类),`_generate_structs` 整体中断。
   - 补 `from lib.core.VLogger import get_logger as _vlog`,与同目录
     FuncGen.py / TypeConvert.py 同口径。

2) lib/core/Handles/HandlesImports.py:1317
   - `_EmitExternalGlobalDeclLlvm` 形参名为 `Node`,该 elif 分支误写成小写 `node`
     ⇒ 只要传入的是**非带注解**的跨模块全局量(`ast.Assign`)就恒抛 NameError,
     分支整体不可达:外部全局变量从未声明 external,消费侧表现为
     unknown global / 类型占位。
   - 判据改回 `isinstance(Node, ast.Assign)`。

静态核验:对 TransPyC 全部 .py 做 symtable 未定义名扫描,结果 0 条;
`python -m py_compile` 通过。
2026-09-30 14:55:40 +08:00
TermiNexus 55cbf1d261 fix(HandlesImports): 继承前缀前置改为"按表头判幂等",不再按名字过滤整块(重名继承项不再被删)
类别:a 编译器缺陷(静默删掉布局条目,使继承段下标整体前移、写到类型不同的槽)。

问题(旧判据):`_EmitExternalClassDeclLlvm` 的前置段用
`nm2 not in {class_members[ClassName] 整表所有名字}` 过滤祖先块。该判据把
**与子类自有字段重名的继承项整条删掉**,于是继承段与 body 的继承前缀失去一一对应:
被删项**之后**的继承字段表内下标整体前移 k(k = 被删项数),而查询侧回退路径用
`base + 表内下标`(FuncGen._get_member_offset)⇒ 落到类型完全不同的槽。
现场(本轮):TypeGenCType 重复声明 5 个父类已有字段后,继承字段
LastBuiltinsTypedefResult 的下标 32→27,`= "t.CPtr"` 写进 i32 槽 ⇒
"指针隐式转整数已禁止:不能把指针类型 i8* 赋给整数类型 i32"。

新判据(抽成模块级 PrependInheritedBlock,可独立验证):
  ① 不删块内条目——块内每项都对应 body 的一个继承槽,删任一项都会整体前移;
  ② 幂等——只问"表头前 len(块) 项的名字序列是否等于祖先块的名字序列",相等即整块
     已前置 → 不再前置(保住 2026-08-10 修的重复字段问题:BasicBlock [Next, Next, …]);
  ③ 同名并存——子类自有字段与继承项同名时两者都留(定义端 body 同样是"继承前缀 +
     自有段",两侧槽数一致);源码层面的这种重名已由 HandlesClassDef 的"字段名遮蔽
     fail-fast"拦下(1903ed14)。

冒烟(纯逻辑,跑完删除):首次前置=块+自有;重复调用不再前置;**同名项仍全保留**
(对照旧实现会删掉块首项 ⇒ 下标前移);空块 no-op。py_compile 通过。

已知残留(写进函数文档):若此前只前置过部分祖先块(父类表当时较短),本次会整块再前置
一次 ⇒ 该前缀出现重复条目;调用点上方刚对父类 force 重载(块内容稳定),该情形仅在
"父类表被中途改写"时出现,且重复条目会在成员槽失败报文的"名序"里直接可见。
2026-09-30 11:18:07 +08:00
TermiNexus c86ecb0c89 refactor(LLVMCG/Handles): 直建 ir.Function 点全部收敛到幂等入口,3 处不再吞 fail-fast
类别:a 编译器缺陷(同一根因的其它变体收口:函数声明创建的唯一入口 + fail-fast 不被吞)

背景(前几轮已修两处):llvmlite 的 `Function.__init__` 不是事务性的(名字在 `_set_name`
就进 module.scope,之后建 Argument/ReturnValue 才断言类型,最后才 add_global),中途失败会
留下悬空名字;本仓已加两道防线:全局守卫 `InstallFuncCreateGuard()`(回滚名字 + 带调用点的
FailFastError)与唯一幂等入口 `_CreateOrReuseFuncDecl`(创建前自检、同名同类型复用、异类型
带两侧签名 fail-fast)。但仍有 20+ 处**绕过入口直建**(同名时抛裸 DuplicatedNameError、且
名字被占/半注册时只能看到没有上下文的名字),以及若干处 `except Exception` 会把这颗
FailFastError 吞掉(声明静默缺失、真因丢失)。

改动:
1. 创建点收敛(21 处,行为等价或更严)——`X = ir.Function(<gen>.module, <fty>, name=<N>)`
   → `X = <gen>._CreateOrReuseFuncDecl(<N>, <fty>)`:
   · Handles:HandlesAnnAssign[llvm.memcpy]、HandlesAssign[llvm.memcpy.p0i8.p0i8.i64 ×2]、
     HandlesBase[GetOrCreateFuncDecl / GetOrCreateStubFuncDecl]、
     HandlesExpr[malloc]、HandlesExprBuiltin[strlen / llvm.memcpy]、
     HandlesExprCall[llvm.* 与普通 / win32 API / strlen / llvm.memcpy]、
     HandlesAsyncFunctions[malloc / create_* / resume_* / CRT 声明 / free]、
     HandlesExprLambda[lambda 包装]、HandlesFunctions[_replace_function_decl 的 old_func=None 分支]、
     HandlesImports[output stub 按需加载]
   · LLVMCG:BaseGen[_DeclareExternalFunc 与 6 处 --hotspot-sites 内部符号]、
     ExprGen[llvm.pow.f64]、VaArg[llvm.va_start / llvm.va_end]
   原有 globals/functions 预检查与随后的 `Gen.functions[...] = X` 赋值一律保留。
   注:`_DeclareExternalFunc` 收敛后外部声明会同时登记进 `self.functions`(幂等入口固有行为,
   与既有 `get_or_declare_c_func` 一致;该路径仅 --hotspot-sites 调试特性使用)。
2. fail-fast 不再被吞(3 处):在包裹创建的 `except Exception` 首部加
   `isinstance(_e, FailFastError) → raise`:
   · HandlesExpr[malloc 的 null 回退分支]、HandlesExprBuiltin[strlen]、HandlesExprCall[strlen]
   (其余异常维持原行为,本轮不扩大 fatal 面。)
   另有 HandlesFunctions / HandlesImports 的同类 handler 前几轮已具备 FFE 重抛,本次未重复改。

验证:13 个改动文件 `py_compile` 全部 EXIT=0;冒烟 4 例通过——同名同类型复用同一对象、
异签名 → FailFastError(报文含两侧签名 i64/i32)、名字被非函数全局占用 → FailFastError、
`llvm.va_start` 幂等。另:`ir.Function(` 在 lib 内仅剩 `BaseGen._CreateOrReuseFuncDecl` 内部
这一处(豁免点);`DecoratorPass.py` 的 `module` 为外部传入(非 Gen 的模块)故其两处保持原样。
2026-09-30 09:53:41 +08:00
TermiNexus 8f1ec5b715 fix(LLVMCG): llvmlite Function 创建事务化 + 不再吞 fail-fast,悬空名字不再复现
类别:a 编译器缺陷(TPC 侧)

现象:编译 StubMergerIR.vp 时 `_EmitExternalFuncDeclLlvm` 报「函数声明名字悬空占用:
'50741ad4b4b0934d.LLVMTypeCore.__init__' 已进 module.scope,但 module.globals 中无对应
对象」,且该 FailFastError 被 `_LoadModuleDeclarationsFromFile` 的节点级 `except Exception`
吞成一行 WARN「忽略节点 ClassDef LLVMTypeCore 异常」后 continue。

机制(判据已写进代码注释与报文字段):
1) llvmlite 的 `Function.__init__` 不是事务性的:名字在 `_set_name` 即进 module.scope,
   之后逐个建 Argument/ReturnValue 才做类型断言,最后才 add_global;中间任一步抛错都不
   回滚 scope ⇒ 留下「globals 查无、scope 已占用」的悬空名字,后续同名创建只能报裸
   DuplicatedNameError(或本仓的「名字悬空占用」),而真因——上一处被吞的创建失败——已丢失。
   修法:BaseGen 新增 `InstallFuncCreateGuard()`(随模块导入装一次),在**失败路径**上
   回滚名字(补 llvmlite 缺的那半截事务,模块状态可重试)并抛 FailFastError,报文含
   函数名 / 本次签名 / 原始异常 / 创建调用点(栈上首个非 llvmlite、非包装函数的帧);
   `DuplicatedNameError` 原样上抛——那是各调用点有意处理的正常分支(如「已存在则复用」)。
2) 首建失败与该 FailFastError 被 5 处兜底吞掉,使真因退化成一行 WARN:
   · HandlesImports._LoadModuleDeclarationsFromFile 节点级 except(本现场的直接来源)
   · HandlesImports stub 声明加载循环的两层 except
   · HandlesImports._TryLoadFuncDeclsFromOutputStub 的裸 `except Exception: pass`
   · HandlesFunctions._replace_function_decl 的 `except Exception: return old_func`
     (此处 old_func 必为 None ⇒ 调用点把 None 当函数声明用)
   修法:一律 `except FailFastError: raise`;其余异常维持原有口径(严格模式上抛 / 其余告警)。

验证:4 例冒烟(非法签名 → FailFastError 且报文含调用点;名字已回滚 ⇒ 同名可重试成功;
重复创建仍是 DuplicatedNameError 且旧名未被回滚;合法创建零副作用)全部通过;
BaseGen / HandlesImports / HandlesFunctions 三文件 py_compile 通过。
2026-09-29 23:31:57 +08:00
TermiNexus 716cd61a75 fix(tpc): 属性取值失败的报文补"基址诊断" + 补掉声明加载去重签名的真实缺口
类别:a(编译器缺陷)—— 两者都是"缺事实/漏输入",不是放宽判定。

【一】`_RaiseUnresolvedExpr` 增打基址事实(HandlesBase)
现场:TransPyV/App/lib/core/Gen/MatchGenMixin.vp:231
  `val: ast.AST* = expr_node.value`(base 是 `expr_node: rawptr[ast.Expr]`)
  → Attribute 取值返回 None → 本报文 + sys.exit(1)。
属性读回 None 的根因只有两类:① 类名登记退化(var_struct_class 存 'rawptr' /
'rawptr[X]' / 折叠态,或压根没登记);② 登记名与 Gen.structs / class_members 的键
不同源(短名 vs sha1 全名)。原报文只有"目标变量 + 注解 + 源码",不含任何一项事实
⇒ 只能从"求值为空"反推。现追加一行(仅 Attribute + Name 基址时,其余形态逐字不变):
  基址诊断: 'expr_node' 的 var_struct_class=<...>;alloca 类型=<...>;
            该名在 Gen.structs=<是/否>;class_members=<N 个字段/无该键>
与 `_DescribeMemberSlot` 同口径:列数据、不猜。

【二】`_ClassMembersReloadSignature` 的"类数"改为"逐类 (键, 表长) 元组"(HandlesImports)
上一轮 3399b44c 的签名里全局进度只记 `len(class_members)`(键数)。缺口:**某已有类的
成员表继续增长时键数不变**(典型=父类成员后到),而父类成员正是继承前缀的唯一来源
⇒ 极端时序下会漏掉一次必要重跑。改为逐类 (键, 长度) 元组,并补记
`len(class_parents)` / `len(class_parent)`(父链登记本身也是输入)。
代价 O(类数)(约 300 项/次调用),仍远低于一次重跑的成本。

验证:GetDiagnostics 干净;py 层 import + 既有 16 例类型判定 smoke test 全过。
未跑编译器(无 includes 改动,无需重编)。
2026-09-29 16:50:51 +08:00
TermiNexus 3399b44c2d perf(tpc): 声明加载去重 + _parse_llvm_type memo(PROF main_prof_72472 前两名热点)
两项改动同在 HandlesImports.py,合并提交:都属"重复重跑"型浪费,且第二项是第一项
放大链的下游。

【一】声明加载按依赖签名去重(类别 a:编译器缺陷)
证据:_TryLoadClassMembersFromPyi 142,888 次 → 6,683 次落到 _EmitExternalClassDeclLlvm
(cum 103.1s)→ _generate_structs 8,059 次(cum 128.7s)→ _TryLoadStructFromStub
88,970 次 → _parse_llvm_type 909,382 次;对照模块声明发射仅 320 次 ⇒ 绝大多数是
同状态的重复发射。
根因:guard 只在"表非空 **且已登记已展平**"时短路,而"父类是泛型特化/始终不可得"
的类永远不会被 `Gen._members_flattened` 登记 ⇒ guard 永不命中 ⇒ 每次重入都重跑整套
`_EmitExternalClassDeclLlvm`(其内部又触发 _generate_structs → _TryLoadStructFromStub
→ 本方法,即每轮 4 帧的环)。
修复:新增 `_ClassMembersReloadSignature`(纯读)收录"重跑能否产生新结果"的全部输入
——全局进度(已登记类数/已展平类数)、本类成员表长度与展平登记、struct body 元素数、
各父类的成员表长度与展平登记;签名不变即直接短路,依赖一变立刻放行(不破坏"与父类/
struct 就绪顺序无关"的设计目标;与 EnsureClassMembersFlattened 的依赖签名同一思路)。
要点:键含 source_sha1(同名类分属不同模块);**先登记再发射**(否则环上第一层重入
还会再发一次,去重被推迟一层);发射抛异常时撤销登记(保住"失败可重试",不让失败态
被签名冻结);force=True 完全绕过。

【二】`_parse_llvm_type` memo + 基础类型表提升为模块常量(类别 b:漏缓存)
证据:该函数被调 1,689,809 次(cum 46.7s),`type_map` 字典每次调用现建 ⇒ 字典字面量
1.69M 次、`IntType.__new__` 9.09M 次;每个 `X*` 还要新建 `ir.PointerType` ⇒ 全程序
`_TypedPointerType.__init__` 4,596,463 次(≈12–15s)主要来自这里。
修复:拆 memo 包装 + `_parse_llvm_type_impl`(原实现逐字搬移,内部递归仍走包装);
memo 只缓存**与 Gen 状态无关**的结果(新增 `_IsGenIndependentLlvmType`:类型图不含
`IdentifiedStructType` 且非 None——含具名结构体的结果绑定 `Gen.structs` 实例且有
泛型特化副作用,None 表示"此刻未加载",二者都不可缓存,理由写进注释防以后被放宽);
`_LLVM_PRIMITIVE_TYPE_MAP` 提升为模块级常量(llvmlite 中这些类型无状态、IntType
按宽度缓存同一实例,跨调用/跨 Gen 共享安全)。

验证:py 层 smoke test 覆盖 16 种类型(含 struct / struct* / [4 x struct] /
{i32,struct} / fn(struct) / fn->struct* 组合),判定全部符合预期,模块可正常 import。
未跑编译器(无 includes 改动,无需重编)。
2026-09-29 16:31:29 +08:00
TermiNexus 467e62a45e fix(tpc): 继承前缀配槽改用 elements 快照,不再对已被重置为 None 的 body 下标
类别:a(编译器缺陷)—— 裸 Python TypeError 崩溃 + 外层静默吞掉整条类声明。

现场:编译 includes/ast/astaux.vp 时
  HandlesImports.py:2526 `_inherited_ph.append((_nm_ph, _st.elements[_slot0_ph + _i_ph]))`
  → TypeError: 'NoneType' object is not subscriptable
(栈由 VLogger.warning 打印 exc_info 后首次可见;外层 HandlesImports.py:647
 `except Exception` 只 WARN "忽略节点 ClassDef" 就 continue ⇒ 该类声明整条
 被静默丢弃,类型解析退化。)

根因(TOCTOU):guard 在 :2500 通过(elements is not None),但两侧之间
`_ResolveInheritedFieldNames`(:2535)会加载父类成员:
  _ResolveInheritedFieldNames → _TryLoadClassMembersFromPyi
  → _EmitExternalClassDeclLlvm → _generate_structs
而 `_generate_structs` 判定"struct body 与 class_members 不一致"时会**主动**
`existing_st.elements = None`(StructGen.py:579/:590,既有机制,为强制重新派生)
⇒ 配对时读到的 elements 已变 None。

修复:guard 通过时立即对 elements 取快照 `_elements_ph`,槽位数与槽位类型取自
**同一时刻**的布局(`_num_elements` 本就取自它,二者必须同源);配对用快照,
不再触碰可能被重入重置的 `_st.elements`。无重入时行为与改前逐字节一致。
2026-09-29 16:26:43 +08:00
TermiNexus 24573e5af6 fix(tpc): HandlesImports 不再静默 RecursionError + VLogger.warning 补打 exc_info
类别:a(编译器缺陷)+ b(机制漏豁免)—— 类型解析链成环被当成"可忽略异常"吞掉,
上游根因不可见、声明静默退化。

- HandlesImports.py:978 / :1475 / :1583 三处新增 `except RecursionError: raise`,
  对齐家族口径(HandlesBase.py:1060-1068:「RecursionError 不是可忽略异常,
  是类型解析/声明发射链成环的真缺陷信号」)。成环路径:
  _TryLoadClassMembersFromPyi ↔ _EmitExternalClassDeclLlvm ↔ _TryLoadStructFromStub
  (每轮 4 帧),现场与 :2985 深探针记录一致(match.MatchOr.patterns、
  stmts.Interactive.body 等"首字段即指针/容器"的类)。
  修复前表现为一行 `WARN: HandlesImports: 忽略异常 maximum recursion depth exceeded`
  + 返回类型退化成 CInt / 形参退化成 i32。

- VLogger.py:warning() 的 exc_info 形参**从未被使用** —— 调用方传了异常却无任何
  输出,吞异常点只剩一行 WARN、栈不可见。现与 error() 同口径打印
  `Exception: <类型>: <消息>` + traceback(重复帧由 traceback 模块自动折叠为
  "[Previous line repeated N more times]",不刷屏)。
2026-09-29 16:16:01 +08:00
TermiNexus 4fc067e3bf perf(tpc): 按 profile 消掉两处主热点(stub 索引每 miss 重扫目录 / vtable 每类全扫函数)
依据 PROF/main_prof_10152.prof(main_time.txt: 失败 2362.46s,72 个文件全部走
顺序 _translate_file,tottime 合计 2288.9s):

  tottime      calls   函数
  491.7s      723782   nt._path_isdir            ← 总时长 21%
  268.6s       15762   StructGen._generate_structs
  182.9s      479819   nt.listdir                ← 8%
  87.2s    657640754   builtins.isinstance
  78.6s     41514263   ntpath.join
  75.9s     83047878   ntpath.splitroot
  75.7s         1631   StructGen._create_Vtable_globals   (46ms/次)
  66.6s       238007   HandlesImports._build_stub_index
  63.0s    317868145   str.startswith
  38.4s    175751378   str.endswith
  ...
  ── 仅 isdir + listdir + join/splitroot/endswith ≈ 850s ≈ 总时长的 37%

一、_build_stub_index 的零 syscall 快路径(HandlesImports + Phase2Translator)
    它由 _TryLoadStructFromStub 的**每次索引 miss** 调用(238k 次),每次都要
    2× os.path.isdir + 2× os.listdir + 全量 endswith/join 重拼文件集合 ——
    这正是上面 isdir 723k / listdir 479k 的主要来源。
    改为:写入方显式置脏(ImportHandle.MarkStubSetDirty),未置脏时直接返回。
    置脏点:① 每个文件翻译入口(_translate_file,顺序与 worker 模式皆按文件粒度
    覆盖)② 写 temp/<sha1>.stub.ll 之后 ③ 注册 include 写 output/<sha1>.stub.ll
    之后。索引建完即清脏。语义:增量重扫、output 覆盖 temp 全部不变,只是把
    "集合是否变化"由目录扫描改为写入方免费告知(编译进程内 stub 只增不改)。

二、_create_Vtable_globals 的 O(类数 × 函数数) → O(函数数)
    原实现对每个候选类都遍历一遍 self.functions 找 "{ClassName}." 前缀且非
    declare 的函数;改为一次性预计算"非 declare 函数名的全部点分前缀"集合,
    每类只做一次集合查询。判据等价(startswith(prefix) ⟺ prefix 在点分前缀集)。

重编后请再抓一次 profile 复核收益;下一梯队热点是 _generate_structs
(268.6s tottime / 35k 次调用)与 _parse_llvm_type(3.5M 次调用)。
2026-09-29 14:36:57 +08:00
TermiNexus f1e7fd6c28 perf(tpc): _LookupStubFuncType 的目录计数按目录 mtime 缓存,去掉每次调用的全量 listdir
类别:纯提速(判定结果不变)。原实现每次调用都要

  sum(1 for f in os.listdir(output_dir) if f.endswith('.stub.ll'))
  sum(1 for f in os.listdir(temp_dir)   if f.endswith('.stub.ll'))

只为构造一个"stub 是否新增"的签名;本函数位于每次跨模块函数/方法查找的热路径
(20 个调用点),开销 = O(目录文件数) × 调用次数,与编译工作量无关,工程越大越亏。

改为 ImportHandle._CountStubFilesInDir(DirPath):同一「目录 + 目录 mtime_ns」
只 listdir 一次,mtime 命中即复用上次计数(每目录一次 os.stat 代替一次
os.listdir + 全量 endswith 判定)。
判据:stub 目录只增不改、且由主进程在批次之间写入 ⇒ 只有目录条目增删才会改变
计数,而 Windows/NTFS 在条目增/删/改名时会更新目录 mtime。
取不到 stat(目录不存在/权限)时不写缓存、退化为每次实算。
计数仍是权威签名,缓存只决定"要不要重新 listdir",不改变任何判定结果
(增量重扫、output 覆盖 temp 的语义逐字不变)。
2026-09-29 14:32:39 +08:00
TermiNexus f4c8c48748 fix(tpc): 函数声明创建全部收口到唯一幂等入口,消除 DuplicatedNameError 裸抛
类别 a(编译器缺陷)+ b(机制漏豁免)。报错:翻译 lib\core\Gen\Expr\ExprGenName.vp
失败,报文只有名字 dddc595175f00c66.ExprGenAttr.find_global_in_module
⇒ llvmlite DuplicatedNameError(NameScope.register 对 GlobalValue
deduplicate_name=False,同名 global 再建必抛,__str__ 只回名字)。

根因(已取证,非猜测):
- llvmlite Module 里 `scope`(NameScope,注册/去重)与 `globals`(OrderedDict)
  是两套结构;`add_global` 只在构造时写入 ===> 「名字已在 scope._useset、
  但 globals 查不到」这一状态一旦出现,任何"先查 globals 再建"的守卫都会失效。
- 该状态由**清理不完整**制造:删旧名时只删"对象真名 existing_func.name/old_name",
  而字典键/目标名(func_name / MangledName)仍留在 scope._useset。
  别名注册(Gen.functions[短名] = 名为全名的对象)恰好让二者不同名。
- 另有若干创建点只看 Gen.functions、完全不看 module.globals(裸建 ir.Function),
  只要 module.globals 已有同名声明就裸抛 DuplicatedNameError。

本次收口(函数声明创建的唯一入口 = BaseGen._CreateOrReuseFuncDecl):
1. BaseGen._CreateOrReuseFuncDecl:新增"名字被非函数 global 占住"分支,把冲突
   双方(类型 + repr)报出来,替代原 llvmlite 只给名字的裸抛。
2. 清理不完整处补全为「同时清 真名 + 目标名」:
   - HandlesImports.py 模板 declare 装载(clearing func_name 之外还清 existing_func.name)
   - HandlesFunctions._replace_function_decl(clearing {old_name, MangledName})
   - 其 except 对 FailFastError 改为上抛(不再回退成复用旧声明)
3. 裸建 ir.Function 的创建点改走唯一入口(module.globals 同名则复用、
   签名冲突/非函数冲突则 fail-fast):
   - HandlesExprCall._HandleStaticMethodCallLlvm({sha1}.Class.Method)  ← 本现场形态
   - HandlesExprCall._HandleMethodCallLlvm 的 class_sha1 回退分支
   - HandlesExprCall._try_declare_c_lib_func / HandlesExprBuiltin._try_declare_c_lib_func
   - HandlesAssign 模块级全局赋值处的函数声明
   - HandlesImports.__before_init__ 声明(原查 NewFuncName 却建 MangledName)
   - HandlesFunctions._EmitFunctionLlvm(补登记 module.globals 已有声明,
     使既有的签名修复路径生效,而不是裸建撞名)

行为等价性:上述各点原先"撞名"时必然抛 DuplicatedNameError(即必失败),
收口后要么复用同一符号、要么 fail-fast 报出两侧签名/冲突类型,无静默降级。
2026-09-29 13:50:44 +08:00
TermiNexus dab0823f5c fix(tpc): 收紧「类身份」判据 + REnum 变体载荷解析失败不再被吞
承接 02d89b09:上一版判据"BaseType 是 CVoid ⇒ 类型信息丢失"**误伤 REnum** ——
REnum 类型条目本身 `BaseType=None`,`T | t.CPtr` 合并时 `_MergeAllComponentTypes`
末尾会把空 BaseType 默认填成 CVoid,但 IsRenum/IsStruct/Name 齐备,`_ctype_to_llvm`
仍能解析出 `%<sha1>.T*`。于是合法注解 `Pointee: rawptr[LLVMType]`(REnum 变体载荷)
被打成致命错误,异常又在此处被上层吞掉 ⇒ 变体只剩 __tag。

两处修正:
1) HandlesBase._CheckPtrAnnotationKeepsClass:判据收紧为「BaseType 是 CVoid **且
   没有任何类身份**(IsStruct / IsRenum / IsEnum / Name 全空)」才失败。
2) HandlesImports REnum 变体载荷注册:历史上 `CollectAnnAssignMember` 的异常被上层
   吞掉、`parsed` 为 None 时静默跳过 ⇒ class_members 只剩 __tag、变体循环中断
   (现场同前缀 structs 键只有 LLVMType_Int / LLVMType_Ptr,源顺序其后还有
   Func/Array/Struct/…),进而使变体构造丢载荷、match 捕获绑不上。现改为:
   - 只把 AnnAssign 当载荷声明(pass / docstring 合法跳过,如 `class Void: pass`);
   - 解析抛异常 ⇒ fail-fast 并带上原异常(拒绝留下只有 __tag 的成员表);
   - 解析返回 None ⇒ 同样 fail-fast。
2026-09-29 11:24:57 +08:00
TermiNexus c49dc1d915 fix(tpc): 类型静默降级改 fail-fast + 成员槽写入失败附来源明细
a 编译器缺陷:类型信息缺失时静默兜底会掩盖上游根因,兜出来的"看着合理"的类型
(如 i8**)又会让下游报出与真因无关的错。按既定铁律改为响亮失败:

1) HandlesImports._parse_llvm_type:被指类型是具名聚合(%...)却在
   create_structs=True 下取不到结构体时,原静默 `return PointerType(i8)` ——
   结构体指针被悄悄变成通用指针,外层再套一层即成 i8**。改 fail-fast。
   (create_structs=False 属"尚未加载",非异常,保持原样。)

2) HandlesTypeMerge._HandleSubscript:新增判据自洽守卫 —— base 是指针标记
   (rawptr / t.CPtr / 裸名 CPtr / 别名)而 IsPtrSubscriptNode 未命中时,
   历史上会落到 CollectAll 当"数组下标"解析、静默产出「基座 void + 多层指针」
   (i8**)。现 fail-fast(判据分裂即内部不变量被破坏)。

3) HandlesAssign._HandleAttributeStoreLlvm(`self.字段 = 值`):成员槽写入失败
   时追加「成员槽来源」明细 —— class_members 声明侧(项数/base/下标/声明槽类型)
   + 布局侧(struct IR 名/元素数/elements[offset])+ structs 键数与是否同一对象,
   使"声明侧退化"与"布局侧退化"一眼可分,杜绝再靠猜。

现场:TransPyV/App/lib/core/Gen/Generator.vp:193 `self.ExprGenConst = SubExprGenConst`
  → 指针隐式转换已禁止(层数不同):不能把指针类型
    %"cfd1f3d0d7e87fea.ExprGenConst"* 隐式转为 i8**
2026-09-28 23:59:29 +08:00
TermiNexus e6451a077e fix(tpc): 继承展平沿继承链补真实字段名(消除 __inherited_N 占位名)
a 编译器缺陷:泛型基类的继承字段在导入侧展平时名字丢失。父类是泛型特化
`GSListNode[ParamNode]`,其特化体不在任何 .vpi 中 ⇒ 按特化名加载必落空 ⇒ 占位符
路径按 struct 槽位数补 `__inherited_N`:偏移对、**名字丢**。于是继承字段的属性访问
找不到字段(现场 `[fast-fail] 属性 Next 在类 ParamNode 中找不到
(class_members=[__inherited_0, Ty])`)。

语义修正:新增 _ResolveInheritedFieldNames —— 按**声明顺序**沿继承链取父类声明里的
字段名;父类是泛型特化 `X[Arg]` 时回退用**模板名** X 加载其成员(模板声明了字段名,
如 linkedlist.vp:265 `GSListNode[T]: Next: T*` 的 Next),这正是编译期唯一可信的
名字来源;与 DeclarationGenerator._get_inherited_members(stub 端取模板成员)、
BaseGen._get_or_create_struct 的 `_struct_sha1_map` 拼名规则同一条"类名 → 模板/模块"
规则源。名字取不到才退回占位名(仅保证偏移)。

同时修正占位符配对的槽位起点:有 vtable 指针时首元素是 vtable,上面已把它从
_num_elements 扣掉,配对结构体元素必须同步右移一位(原实现从 elements[0] 起取,
会把 vtable 指针的类型当成第一个继承字段的类型)。

结果:展平表直接是 `[("Next", <槽位类型>), ("Ty", ...)]`,属性访问是普通表命中,
不再依赖任何查找期回退。
2026-09-28 21:46:30 +08:00
TermiNexus 35de6321f6 refactor(return): 移除 @c.CReturn 多返回值处理器,只保留 -> tuple[ty1, ty2, ...],遇到 CReturn 一律报错
DeclarationGenerator:tuple[...] 分支逐字保留(仅 CReturnTypes 机械改名 MultiRetTypes),装饰器分支改为 SyntaxError,报文含函数名与“请改用 -> tuple[ty1, ty2, ...]”提示

HandlesAssign(a, b = f() 解包路径):删除装饰器收集分支并改为报错;tuple[...] 恢复与逐个解包逻辑逐字不变

HandlesFunctions:新增 _CRETURN_REMOVED_HINT 与 _RejectCReturnDecorator,在函数定义入口(_GetFunctionSignatureLlvm / _EmitFunctionLlvm)fail-fast——即使只有装饰器、没有 -> 注解,也不会让返回类型静默退化成 i32

HandlesImports:外部函数声明处同样报错,并删除下游已失效的 CReturnTypes 参数拼接死代码

HandlesReturn / HandlesFor / BaseTranslator:CurrentCReturnTypes 等机械改名(读写端一致,无行为变化)

includes/c.py:保留 CReturn 名字作墓碑(删掉会让 @c.CReturn 变成未知属性、可能被静默忽略),docstring 写明已移除并指路 -> tuple[...];README 措辞同步
2026-09-28 13:57:04 +08:00
TermiNexus e1a2821bff fix(tpc): 函数声明创建幂等化,消除 DuplicatedNameError
同名声明只在 module.globals、不在 Gen.functions 时,旧代码会再走 ir.Function,而 llvmlite 的 NameScope 按名字去重(GlobalValue.deduplicate_name=False)必抛 DuplicatedNameError。GetOrCreateStubFuncDecl(含 check_existing=False 路径)、GetOrCreateFuncDecl、win32console 内建声明、output-stub 按需载入四处统一先复用 module.globals。真实事故:VarGenMixin.vp 同一模块两处 self.Gen.ExprGen.translate_value(...) 都走 check_existing=False,第二处崩在 llvmlite。
2026-09-27 16:18:37 +08:00
TermiNexus c83fc752c6 fix(sizeof,parse): 尺寸链去静默兜底,解析报错可定位,补 C 解析器缺口
StructGen: _get_struct_size/_get_align 去 opaque→8/ptr_size、未知→4 兜底并补 VectorType;LiteralStructType.fields→.elements(llvmlite 无 fields,必然 AttributeError)

HandlesClassDef: union 载荷尺寸经不存在的 ir.DataLayout 静默退化成 8 字节;HandlesExprCall/ExprBuiltin: sizeof 各静默 0 分支改 fail-fast,数组元素 sizeof 统一走 _get_struct_size

HandlesFor: nonlocal struct/array 堆分配不再退化成 malloc(8)

vast/vast_c: 补一元 * / & 解析,装饰器后 extern/export 分派修复,C 侧报错带 token 与行号;StubGen.Converter: 宏展开丢尾随空行修 .pyi 缩进非法

其余为 rawptr 迁移 / fail-fast 口径等历史改动一并入库
2026-09-26 19:27:22 +08:00
TermiNexus 2cc816ac13 修复了一些错误 2026-09-18 20:00:59 +08:00
TermiNexus 6af2dea917 修复了一些问题 2026-09-17 14:52:37 +08:00
TermiNexus 015fbf17cf fix(tpc): 跨模块模块级变量类登记与 Mod.Var.Field 链解析;并停止跟踪 __pycache__/*.pyc 2026-09-12 11:51:42 +08:00
TermiNexus 9257dd841f fix(tpc): rowptr[X] 字段 element_class 登记补短名模糊扫描,修 Unknown module 误报 2026-09-12 11:24:49 +08:00
TermiNexus cc2f5d34eb feat(tpc): includes 只认项目配置;ASan 改为显式链接 clang64 运行库
includes 目录不再回退仓库硬编码 TransPyCRoot/includes:Phase2Translator 新增 PROJECT_INCLUDE_DIRS(INCLUDE_DIRS 置空以兼容旧引用),Config.py 从 project.vpj 的 includes 同步;HandlesImports 的模块搜索、TypeAnnotationResolver._builtins_include_dirs 一律只读项目目录。

ASan:mingw64 clang 没有 x86_64-w64-windows-gnu 目标的 ASan runtime,新增 _FindAsanRuntimeDir 定位 clang64 运行库并按 -l: 显式链接(asan_dynamic-x86_64.dll.a + runtime_thunk),定位失败即报错退出。HandlesExprFormat:i32 不再写 'l' 长度修饰符(LP64 下 printf 会按 64 位读实参)。
2026-09-11 22:47:21 +08:00
TermiNexus 45e78ad107 基线重置,修复了一些 bug 2026-09-07 14:46:02 +08:00
TermiNexus 50ca560563 fix(tpc): list 联合类型方法分派保护 + str 压平条件收紧 + external global 裸名兼容
- HandlesAssign: 变量已有同 base 声明类型时不再覆盖 var_struct_class(sha1 前缀特化名覆盖裸名,导致 dbody.get 查表 miss 后 fallback 到 list[int].get,i32 返回值被截断成垃圾指针崩溃——TPC 侧根治)
- HandlesExprCall: IdentifiedStructType 真值判断改 is None(opaque 时 bool() 触发 __len__ assert)
- HandlesFunctions/HandlesImports: IsStr 压平条件加 PtrCount<=1,str|t.CPtr(i8**) 不压平;external global 正则兼容裸名格式
2026-08-24 23:31:08 +08:00
TermiNexus c62153a685 perf(tpc): import 热路径优化——walk 结果缓存 + DebugPrint 参数惰性化
- import 兜底查找(_EmitModuleDeclarationsLlvm)每次解析失败都 os.walk 递归扫描 includes/工程目录,且多级模块名与 basename 永不匹配纯浪费:改为多级跳过 + 目录 walk 结果类级缓存(编译进程内目录不变)
- DebugPrint 调用点(HandlesTypeMerge 类型查询热路径)无条件构造 f-string 参数(含昂贵的 ast.dump),即使 DebugFile 未设置也执行:改为 getattr(DebugFile) 防护后才构造(单文件 profile:_io.open 1253 次 1.76s + DebugPrint cum 2.24s)
2026-08-22 06:05:43 +08:00
TermiNexus 56a4b5c818 fix(tpc): stub 加载器解析全局变量声明——跨模块全局变量不再静默丢失
- 根因:_LoadDeclarationsFromStubLlvm 只解析 struct/declare,忽略全局变量声明行,TPC 编译 TPV 时跨模块全局变量(StubMerger._sha1_store_count 等)从未嵌入 Gen.module.globals
- 后果:_lookup_module_global 恒 None -> return 静默跳过 ret(HandlesReturn 的 if Val 分支)、跨模块赋值静默丢失
- 修复:逐行循环加分支解析 16hex 前缀的 external global 声明(剥离 zeroinitializer 与 align 尾部修饰),用 _parse_llvm_type 解析类型后嵌入 external GlobalVariable;.str. 内部常量与 @main 等非 16hex 前缀跳过
- 诊断脚本验证 4 种真实 stub.ll 格式(struct 指针/数组/zeroinitializer/vtable 结构体)全部解析成功
2026-08-22 04:21:04 +08:00
TermiNexus 3117ab3dec fix(tpc): import fail-fast 判据误报修复——文件系统找不到不等于模块不存在
- TPV 自举工程 includes 为合并形态,源码模块(lib.Stub.StubMerger 包)不提供裸 .vp 文件,声明由 ModuleSha1Map 定位 sha1 -> temp/*.stub.ll 加载(_LoadDeclarationsFromStubLlvm,与 FullModulePath 无关)
- 原判据只看 FullModulePath 文件系统存在性 -> TPV 构建所有 import 误报 ImportError
- 改为:文件系统找不到时查 _source_module_sig_files / Gen.ModuleSha1Map(TPV 工程由 Phase2Translator._ModuleSha1Map 同步而来),模块有 sha1 注册即视为可解析
- 单文件编译两表皆空,NegativeTest 假 import 用例仍 fail-fast
2026-08-22 04:04:30 +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 fbd132284b perf(phase2): 按 PROF 热点优化编译耗时
- HandlesImports: _TryLoadClassMembersFromPyi 复用 _pyi_cache 跳过重复 isfile(-12.8s);_LookupStubFuncType 类级缓存 + 签名增量扫描新增 stub,去掉每文件 isfile(-6.5s+)
- Phase2Translator: pyi cache 仅主进程构建(worker 只读 pkl,-23s+pickle 10.4s);include 源文件 sha1/存在性缓存消除 _build_current_ModuleSha1Map 重复磁盘 I/O
- StructGen.finalize: 行过滤改 startswith(tuple) 预计算,消除 O(lines×structs×patterns) 嵌套循环(tottime 84.8s → 预期数秒)
- 附带 fail-fast(任意文件出错立即终止)+ 子进程 PROF 硬编码
2026-08-19 00:28:40 +08:00
TermiNexus bdc5ec3e88 fix(HandlesImports): 跨模块展平父类无条件 force 重载,消除并行 worker 布局不确定
并行 worker 中 class_members[Generator] 曾出现 83/85/88/89/105/106 vs 114
的不确定变体:父类在某次展平时祖先未加载完成即被冻结为部分成员,guard
(成员非空即跳过)又阻止重载 → this_adjust 按不完整 members 计算字节偏移
→ 继承方法 self 错位 → 运行时越界崩溃(FuncTest is_exception_name strcmp,
错位 68 字节)。

修复:
- 父类加载循环无条件 force 重载:_TryLoadClassMembersFromPyi(force=True)
  先清空该类 class_members/defaults/signeds/bitfields/byteorders/bitoffsets
  再重建,字段顺序与定义模块 stub 一致;对其祖先递归同样强制重载,
  最终所有 worker 展平结果确定性一致。
- 已加载父类经 class_sha1_map 直连定义模块 sha1 强制重载(O(1)),
  避免对每个父类全量扫描 ModuleSha1Map。
- _TryLoadClassMembersFromPyi 返回 bool(找到即停),移除 [DIAG-EXT] 诊断。
2026-08-18 14:38:06 +08:00
TermiNexus 858aba46d0 fix(HandlesImports): _seen_flat_cls 移到父类循环外,菱形去重真正生效
b021c5b 的递归展平把 _seen_flat_cls 定义在 for _ParentClass 循环内,每个父类新建 seen → 菱形祖先(ClassGenBase)被每个继承它的 ClassGen* 父类各展平一次 → Generator class_members 707 字段(与 struct 114 不一致) → this_adjust sub_off 索引越界 → 继承方法不调整 → register_reexport 写 0x3f 崩溃。运行时诊断确认(707→114),register_reexport 调用生成正确 this_adjust(GEP +776)。已移除全部临时诊断。
2026-08-18 14:04:33 +08:00
TermiNexus b021c5b527 fix(HandlesImports): 跨模块 class_members 展平同步按继承源去重
81ad712 只同步了 HandlesClassDef(运行时) 与 DeclarationGenerator(stub struct),遗漏并行 worker 跨模块重建路径 _EmitExternalClassDeclLlvm:仍用旧拼接+按字段名过滤算法,菱形继承下与 stub struct 布局不一致,worker 中 this_adjust 算不出偏移,继承方法 self 不调整,运行时错位崩溃(register_reexport 写 0x3f)。改为递归按继承源去重,与 HandlesClassDef._FlattenInherited 一致。
2026-08-18 13:44:22 +08:00
TermiNexus 7917be0fa1 perf(handles): stub 索引增量重建 + vtable on-demand pyi 缓存类级化,消除 worker 重复解析
- HandlesImports._build_stub_index:以已扫描文件集合替代文件数签名,无新增文件时仅一次集合比较;新增文件只增量解析,消除每编译完一个文件即全量重扫(prof 847 次全量重建 61s)
- HandlesImports._TryLoadStructFromStub:索引命中直接返回,仅在 miss 时才触发增量扫描
- HandlesExprCall._try_register_vtable_ondemand:函数局部 pyi_cache 提升为类级 _vtable_pyi_cache / _vtable_methods_cache,437 次 open+ast.parse 同批 pyi 降为每 pyi 一次(prof 38.5s)
2026-08-18 05:27:53 +08:00
TermiNexus 68d180e718 perf(handles): 跨模块类声明分类/节点查找缓存,去重 _EmitExternalClassDeclLlvm
新增类级 _extern_class_classify_cache((sha1,class)->分类元组)与
_extern_class_decl_cache((sha1,class)->pyi ClassDef 节点):bases/
decorator 分类遍历提取为 _ClassifyExternalClass 纯函数并缓存,
_TryLoadClassMembersFromPyi 节点查找改走索引避免跨任务重复线性扫描
pyi_tree.body(8214 次调用热点之一)。Gen 依赖部分(字段/方法/struct
注册)保持每 Gen 执行,不做整体跳过。
2026-08-17 23:27:44 +08:00
TermiNexus e5af28fa93 fix(imports): NoneType 异常静默 + struct_body 判空,减少 WARN 干扰输出
编译大量输出 "HandlesImports: 忽略异常 'NoneType' object has no attribute 'endswith'":注解/类型解析回退路径对 None 参与运算(数据缺失属正常兜底)——每文件每符号都打 WARN 淹没关键信息。

- 783/1166/1264 三处 except:AttributeError+NoneType 时静默不 WARN,其他异常保留
- 两处 is_packed 判断补 struct_body is not None 防护(源头防 None.startswith/endswith)
2026-08-17 20:07:35 +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 2f0b741d55 fix(gen): TPC 治本——struct opaque 具化、多返回值 fail-fast、with MRO 修复
1. HandlesExprCall: vtable 分派前 _EnsureReceiverStructConcrete 主动具化 struct
   body(stub + class_members 双路径),消除元数据已注册、本体仍 opaque 的
   撕裂状态,失败即 fail-fast 暴露上游 stub 加载时序问题;
2. HandlesImports: stub 加载后仍 opaque 时不保留成功缓存(可重试),
   避免 opaque 状态被固化导致 vtable 分派 GEP 崩溃;
3. HandlesAssign: 跨模块多返回值 CReturnTypes 恢复(LiteralStructType 回退)
   + 解析失败 fail-fast,不再静默跳过致目标变量未初始化触发堆损坏;
4. HandlesWith: MRO 继承方法解析跳过无函数体的 stub declare(Phase1 继承
   包装声明),bitcast 目标改用函数签名参数类型避免 opaque 占位对象。
2026-08-13 07:51:27 +08:00
TermiNexus 2129430446 fix(TPC): 跨模块多继承布局统一 - 字段整体前置/方法表合并/父类防重复
1. 定义模块多继承字段展平 prepend(反序) 改 append(正序),与 DeclarationGenerator stub 一致,修复 ASan 定位的 Generator 字段运行时错位(0xbe)。2. 跨模块加载 class_members 已含子类自身字段,父类字段必须整体前置(prepend),否则 Value.Next 命中 FloatVal(double) 导致 store 类型错乱。3. 跨模块补充与定义模块一致的方法合并(父类槽位前置、子类覆盖放父类位置),修复 vtable 槽错位(MemBuddy.alloc→_fl_find_and_remove)。4. 父类前置按字段名过滤已存在字段,防 _EmitExternalClassDeclLlvm 多加载路径重复调用导致 class_members 重复(BasicBlock:[Next,Next,...])。
2026-08-10 18:08:58 +08:00
TermiNexus 87b9dec1ef feat(core): TPC 多继承同步 M5 - MRO 查找/字段展平/vtable合并/this调整
BaseGen: 新增 class_parents + _get_mro_chain(与 TPV 语义一致: 深度优先
+声明顺序+去重) 与 _get_parent_classes 兼容旧单链
HandlesClassDef: 停用 is_base_of_any 自动 vtable; 多父字段展平去重;
方法合并用定义类名; vtable 槽沿 MRO 取定义类
HandlesExprCall: 方法调用沿 MRO 回退 + stub(无函数体)判定修复
undefined reference; 继承方法 this 调整(GEP+bitcast 成父类指针)
HandlesExprUtils/HandlesImports/HandlesWith/StructGen: MRO 查找同步
2026-08-10 00:29:05 +08:00
TermiNexus 0a10b20dde 修正了逻辑,使 TPV 能够正常编译 2026-08-03 02:00:49 +08:00