Commit Graph
37 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 3122793139 fix(define): _try_resolve_nested_cdefine 复用 _make_define_constant,消除模块属性 CDefine 的位宽误判
模块属性访问(win32.win32file.GENERIC_READ)走的是 _try_resolve_nested_cdefine,其内部三处常量物化仍用 val > 0x7FFFFFFF 判 i64,绕过 _make_define_constant 的按值推断;导致 0x80000000 等无符号 32 位 define 变 i64、与 32 位使用点组合时报「64→32 隐式窄化」。改为委托 _make_define_constant(带声明类型按声明位宽,否则按值推断)
2026-10-11 11:51:31 +08:00
TermiNexus 7a061d4d49 fix(define): CDefine 常量位宽按值推断(含无符号 32 位高半区)
_make_define_constant 原用 abs(val) > 2^31-1 判定,把 [2^31, 2^32-1] 的无符号位模式(如 GENERIC_READ=0x80000000、SHARED 掩码)误判为 i64,导致 X | DEFINE 结果为 i64、赋回 32 位使用点时触发「64→32 隐式窄化」。改为按值推断:落进 [-2^31, 2^32-1] 即 i32,与 TPV 的 define_min_width/ExprGenCdef 同口径
2026-10-11 11:46:33 +08:00
TermiNexus 4f9c234ea8 fix(cdef): external 声明不再遮蔽同名 CDefine 常量;补 t 类名别名解析
两处:① 现场证据(_shared_sym_includes.pickle)显示 all_dc 已含 STD_*-10/-11/-12,但模块 IR 仍 load @STD_ERROR_HANDLE —— 因为 stub 注入的 @X = external global(无初值)让 _lookup_cdefine 的遮蔽判据 AttrName in Gen.module.globals 成立,直接跳过了 CDefine 回退。新增 SymbolUtils.GlobalDeclShadowsDefine:只有**带初值**(本模块真正定义)的全局才遮蔽;仅 external 声明不算。裸名路径同判据改用同一 helper。② all_decl_types 为空的根因:DWORD 的 BaseType 为 None,底层类型存在 OriginalType 字符串 'CUInt32T'(t 类名),原解析只认内层 CTypeInfo。补:按 getattr(t, 类名) 解析该串。离线校验 DWORD|t.CDefine → (32, False)。
2026-10-10 21:25:33 +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 936a43f543 fix(attr): 模块属性访问的 CDefine 查询补 _all_define_constants 回退
上一提交只补了 3 级路径 _try_resolve_nested_cdefine,而 win32file.STD_OUTPUT_HANDLE 是 2 级访问 → 走 _handle_attr_name → _lookup_cdefine,该函数只查 SymbolTable/_define_constants,没有裸名路径已有的 _all_define_constants 回退。includes 的 vpi 模块不会在 SymbolTable 里登记 IsDefine,于是解析落空 → _lookup_module_global 现造一个无定义的 @STD_OUTPUT_HANDLE → 链接期 undefined symbol。补回退(仅在无同名变量/全局时),覆盖 STD_INPUT/OUTPUT/ERROR_HANDLE。
2026-10-10 20:46:52 +08:00
TermiNexus 1050e5a23a fix(decl): stub 跳过联合形态 CDefine + 模块属性访问回退 _all_define_constants
链接报 undefined symbol: STD_INPUT/OUTPUT/ERROR_HANDLE。根因两处:① DeclarationGenerator._generate_global_decl 的 CDefine 跳过判据只认裸 t.CDefine,而 define X: T = V 展开为注解 T | t.CDefine,于是 stub 里写出 @STD_OUTPUT_HANDLE = external global i32(该符号无人定义);② 模块属性访问 win32file.STD_OUTPUT_HANDLE 的 _try_resolve_nested_cdefine 只查 SymbolTable/_define_constants,缺裸名路径已有的 _all_define_constants 回退,解析落空后转去加载那条错误的 stub 全局 → 链接期未定义符号。改为 AnnotationContainsName 判据 + 补 _all_define_constants 回退(仅在本模块无同名全局时,避免遮蔽真实模块全局)。
2026-10-10 20:29:59 +08:00
TermiNexus c2f53852ee fix(Handles/PythonParser/DeclarationGenerator): 补齐 3 处"调用了不存在成员"的死路径 + 1 处被 hasattr 掩盖的静默降级
类别:a(编译器缺陷)

现场:翻译 TransPyV/App/lib/core/Gen/Call/CallGenLeafKit.vp 时终止编译
  RuntimeError: 翻译 ... 失败: 'ClassHandle' object has no attribute '_PreRegisterClassMembers'
  (FuncGen.py:965 有调用,方法全仓无定义)

按要求做了全仓静态扫描(ast:属性访问 vs 全仓属性定义;symtable:未定义全局名),共修 4 处:

1) HandlesClassDef.ClassHandle._PreRegisterClassMembers(缺失 → 实现)
   调用点:FuncGen._get_member_offset 的"struct body 已存在、class_members[类名] 为空"分支
   —— 该类的成员表在本次翻译里从未被收集,而按名定位字段槽位必须有表。
   实现与既有两处成员收集段同源(CollectAnnAssignMember → 追加 (名, 类型)),但**只做收集**:
     · 不展平继承前缀(调用方随后经 _member_base → EnsureClassMembersFlattened 补齐);
     · 不调用 _generate_structs(body 已存在,重入 set_body 会把残缺布局永久固化);
     · 只追加尚无同名的条目(幂等,重复命中不会把表撑长)。
   跳过 __provides__/__requires__/__require_must__(非布局槽位),并登记字段限定符。

2) HandlesExprAttr.ExprAttrHandle._load_bitfield_member(缺失 → 实现)
   读路径 7 处调用(位域分支)全部指向不存在的方法 ⇒ 任何位域字段读取都会 AttributeError。
   实现与 HandlesAssign._store_bitfield_member 严格对称:位域类 body 只有一个 storage 槽
   (elements[0]),字段位置由 class_member_bitoffsets/bitfields/signeds 表达,
   读取 = `(storage >> 位偏移) & ((1<<位宽)-1)`,有符号字段再做符号扩展;
   缺位偏移 / 位宽 ≤ 0 / struct 未具化 / storage 非整数一律 fail-fast(不返回 i32 兜底)。

3) PythonParserMixin 的 __set_default__ 分支(幽灵调用 → 明确报未支持)
   原调用 self._handle_set_default_in_parse(...) 全仓无定义。核实:该注解在 TransPyC/lib 内
   无任何消费端(只有 t.py 的定义与 StubGen/Converter 的"剥离该调用保留类型"),
   includes 全仓亦无源使用 ⇒ 不静默丢弃源码语义,改为 NotImplementedError 明确报"未支持"。

4) DeclarationGenerator._llvm_type_size_str 的数组分支(静默降级 → 修好)
   原写作 `self._ARR_TYPE_RE`(少一个 A)并以 hasattr 守卫 —— 该属性全仓从未定义 ⇒ 守卫恒假
   ⇒ 数组字段一律落到"未知类型 → 8",与 docstring 声明的"_EmitREnumLlvm 尺寸口径对齐"不符。
   改用本类已定义的 _ARRAY_TYPE_RE,并去掉守卫(属性再丢失应当响亮失败)。

核验:compileall 全 lib 通过;属性扫描剩余 26 条全为仓外对象(logging / vast AST /
llvmlite Value·Instruction·IRBuilder / 内置 Exception.args / __class__ / __dict__);
symtable 未定义全局名仅 __file__(运行时内置)。未新增/放宽任何 fail-fast。
2026-09-30 18:23:25 +08:00
TermiNexus 00edd90c28 fix(Handles*): GEP 基址 opaque pointee 收口统一为单一判据源,补齐同族 12 处缺口
【a 编译器缺陷】7aa12263 修好 `_get_attr_ptr` 的 self 分支后,同族其余 GEP 点仍会在
"基址 pointee 是另一份 opaque 同名实例"时抛裸 TypeError(被 IR 边界守卫拦下,报文为
"GEP 的基址指向**未具化**的具名结构体")。根因是同一套收口逻辑被各点各写一份、且
**多数点根本没写**:真正需要的判据只有一条。

新增唯一判据源(HandlesExprAttr):
  · `_ConcretePointeeFor(Gen, ClassName, Pointee)`:取该类的**已具化实例** ——
    ① 类键那份先 `_TryLoadStructFromStub` 补 body;② 否则 `Gen._FindConcreteTwin`
    (同短名、槽数最多);③ 都取不到 ⇒ None(**不兜底**,交守卫 fail-fast 报同短名
    实例清单 + TPC 发射点)。
  · `_ConcretizeGepBase(Gen, Ptr, ClassName, Tag)`:pointee 非 opaque ⇒ 原样返回
    (对既有正确路径零变化);opaque ⇒ bitcast 到已具化实例并**同时返回该实例**,
    供 `_get_member_offset` 作 StructHint(偏移与 GEP 必须同源,与 a43513c9 同口径)。

接入点(全部改为调用上述判据源,逐点行为只在"原本必崩"的情形下变化):
  · HandlesExprAttr._get_attr_ptr — self / 变量 / 属性链 / i8* / 下标 / 强转基座 六条分支
    (self 分支已由 7aa12263 修,此处并入统一判据;下标分支此前**完全没有**收口);
  · HandlesAnnAssign._HandleAttributeStoreLlvm — self / 变量 / 属性链 三条分支;
  · HandlesBase._get_int_ptr — 属性分支;
  · HandlesExprBuiltin(len() 的两个接收者 GEP:`obj.len` 与 list 特化字段);
  · HandlesMatch — REnum 变体 match 的载荷 GEP(变体 struct 可能未 set_body)。

冒烟(临时脚本已删,鸭子类型 Gen + 真实方法):
  · `_get_attr_ptr` self 分支 ⇒ 基址 `%"fef783da4d24330d.Keyword"*`(经 cast_self_Keyword)PASS;
  · `_get_attr_ptr` i8* 分支 ⇒ 同上 PASS;
  · `HandlesAnnAssign` self 分支 ⇒ GEP 基址为已具化实例 PASS;
  · 回归:基址本就具化时必须**原样**(不得多出 bitcast)PASS。
另:`python -m compileall TransPyC/lib` 全绿。
2026-09-30 14:42:56 +08:00
TermiNexus 7aa12263f5 fix(HandlesExprAttr/BaseGen): _get_attr_ptr 的 self 分支补 opaque 基址收口(孪生体 bitcast)+ GEP 守卫报出 TPC 发射点
【a 编译器缺陷】现场:Phase2 翻译 includes/ast/astaux.vp:165
`self.arg = _copy_str(pool, arg)`,守卫报
"getelementptr(GEP) 的基址指向**未具化**的具名结构体:基址类型=%"8312ce86a2fd82c0.Keyword"*,
GEP 名='arg'",而同短名实例清单显示 'Keyword' 键上那份已具化(10 槽)。

根因:`_get_attr_ptr` 的 **self 分支**是全仓"self 字段取址"家族里唯一**没有**做 opaque
收口的一处 —— 同函数下方各分支(变量分支 / 属性链分支 / i8* 分支 / 强转基座分支)都先
`_TryLoadStructFromStub` 补 body、再 bitcast 到已具化实例;`HandlesAssign` 的 `self.X = v`
写路径与读路径 `_gep_and_Load_member` 也都有同一套孪生体搜索(`_FindConcreteTwin`)。
本分支直接 `gep(SelfPtr, …)`,typed pointer 下 llvmlite 必须在编译期从 pointee 算元素类型
⇒ 撞 opaque 即抛裸 TypeError(被 IR 边界守卫拦下)。

修法(与同函数其余分支同口径,不引入新判据):
  · 基址 pointee 为 opaque 时,先在类键(`Gen.structs[ClassName]`)上 `_TryLoadStructFromStub`
    补 body;类键那份仍不可用则退回 `Gen._FindConcreteTwin`(同短名、取槽数最多);
  · 命中即 bitcast 到该实例,并把该实例作为 `StructHint` 传给 `_get_member_offset`
    —— 偏移与 GEP 必须同源(与 a43513c9 的"hint 只接受同类"口径一致);
  · 顺带补 `offset is None ⇒ return None`(原实现会把 None 塞进 `ir.Constant(i32, None)`,
    属同一函数其余分支已有的判断)。

【a 编译器缺陷·取证】`RequirePointerOperand` 的 opaque 分支新增一行
「TPC 发射点(由内向外)」:取 Python 栈中位于本仓 `lib/`、且不在 BaseGen.py(守卫自身)
的最内 3 帧,报出 `文件:行(函数)`。理由:该守卫的报文只能指到**语句**,而同一语句里常有
多个候选 GEP 点(本例 astaux.vp:165 在读写两侧共有 4 个 self 字段 GEP 点),逐个读代码
无法判定是哪一个 —— 本次即靠该取证能力闭环(先按"唯一漏收口的分支"修正,下一次构建若
仍失败会直接指出真实发射点)。只在失败路径执行,热路径零开销。

冒烟(临时脚本已删):
  · `_get_attr_ptr` 复刻现场(self 槽持有 opaque `%8312…Keyword*`、'Keyword' 键那份 10 槽)
    ⇒ 输出 GEP 基址类型 `%"fef783da4d24330d.Keyword"*`(经 `cast_self_Keyword`),PASS;
  · 守卫取证:伪造 lib/ 下的发射帧 ⇒ 报文含
    `TPC 发射点(由内向外): core/Handles/_FakeProbe.py:2(_LibEmit)`,PASS。
2026-09-30 14:35:50 +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 64ddabbe17 feat(HandlesAnnAssign/HandlesExprAttr): 左值注解靶型提示(target-typing)——属性链读错类名时按注解类兜回
现场: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,
includes/llvmlite/__types.vp:33-34);ParamNode 只有 Next/Ty。更隐蔽的是**两边都有 Ty**
(Value.Ty = rawptr[LLVMType]、ParamNode.Ty = 裸 rawptr = i8*)⇒ 读错类不会当场报错,
只静默把类型变成 i8*,再往下 `.Pointee` 才炸。

机制(与 TPV translate_value 的 target_ty「使用处真实站点种类」同思路):
  ① HandlesAnnAssign._EvalRhsWithTargetHint:注解赋值求值 RHS 前,把**注解指向的结构体类**
     作为 `Gen._TargetStructHint` 传给属性链解析;求值结束(含异常)复位,不跨语句泄漏。
     两个 RHS 求值点(_reg_values 提升路径 + 常规路径)都改走该入口。
  ② HandlesExprAttr._apply_target_struct_hint:**仅当两条件同时成立**才改判——
     Ⅰ 当前解析出的类(或解析不出)**不声明**该字段(此刻原本会 fail-fast);
     Ⅱ 靶型类**确实声明**该字段。
     任一不满足即原样返回(不猜、不篡改本来正确的链);改判时 `_vlog().warning` 留痕。
     接入点:char*(i8*)分支与单级 Name 分支(含"原键解析不出"的情形)。

验证:py_compile 通过;`_apply_target_struct_hint` 冒烟 7 例全部符合预期——
无提示原样 / 原类不声明且靶型声明⇒改判(本次现场)/ 原类声明该字段⇒不改判 /
原键即靶型⇒原样 / 原键解析不出且靶型声明⇒改判 / 靶型也不声明⇒原样 / 靶型类不存在⇒原样。
2026-09-30 12:28:39 +08:00
TermiNexus 43853bc455 fix(HandlesExprAttr): 基座 pointee 与 Gen.structs 的匹配补「同 sha1 前缀」与「同短名唯一候选」
现场(Repl.vp:802):`ct_names: list[str]* = GenApi._g_gen.TypeGenCType.CTypedefNames`
的基座 `.TypeGenCType` 取值后 pointee 为 `%"750b8c10137d273e.TypeGenCType"*`(= 撤销
6a287b9 后的新 sha1),而 Gen.structs(250 键)里没有该 IR 名的实例 ⇒ 旧判据只有
"身份相同 / IR 全名逐字相同" ⇒ 全部未命中 ⇒ 属性链求值为空 → 带注解赋值判定"无值可存"
而终止编译。(a18ca4da 的记账正是把"基座形态 / pointee / 键数"三项事实直接印了出来,
本轮不必再猜。)

改动(判据分级,强到弱;找不到仍留痕失败,不兜底造类型):
  ① 身份相同(原判据);
  ② IR 全名逐字相同(原判据,覆盖"同名第二份实例");
  ③ 同 sha1 前缀 —— IR 名形如 `<sha1>.<短名>`,前缀相等即"同一模块的同一类";
  ④ 同短名——**仅当候选唯一**时放行(调用点算 `_UniqShortCN`):两个及以上同名类无法
     判定是哪一个,宁可留痕失败也不选错布局(同名类冲突在本仓一律以 sha1 全名区分)。
同时把"未命中"记账扩为:列出分级判据、同短名候选清单,以及"候选 >1 会被主动拒绝"。

验证:py_compile 通过;`_PointeeMatchesStruct` 冒烟 6 例(身份 / 同名第二份实例 /
同短名不同 sha1 / 裸短名 / 不同类 / 非 Identified 一侧)全部符合预期。
2026-09-30 12:20:20 +08:00
TermiNexus 2aa55f36b9 fix(LLVMCG/Handles): GEP 基址 opaque 时按同短名找已具化孪生体并 bitcast;守卫报文补实例清单
现场:includes/ast/astaux.vp:165 `self.arg = _copy_str(pool, arg)` 的基址 pointee 是
opaque 的 `%"<sha1>.Keyword"*` —— 同一类名常有两份 struct 实例(短名 'Keyword' /
sha1 全名 '<sha1>.Keyword'),"函数签名里的 self 用哪一份"与"StructGen 具化的是哪一份"
并不保证一致 ⇒ GEP 无法在编译期算元素类型(llvmlite 抛裸 TypeError),
_GuardIrBuilder 的 opaque 守卫先行 fail-fast。

改动:
1) 新增 BaseGen._FindConcreteTwin:按**同短名**(IR 全名相同者优先)在 structs 里取一份
   已具化实例(元素最多者),与既有"同名实例取字段最多版本"(HandlesAssign:1156-1163)
   同一判据;返回 None 表示确无孪生体(真因 = "body 从未 set_body")。
2) 写入路径 HandlesAssign(`self.字段 = ...`):pointee opaque 时 bitcast 到孪生体,
   并把它同时用作 struct_type 与 `_get_member_offset` 的 hint ⇒ 偏移与 GEP 同源。
3) 读取路径 HandlesExprAttr._gep_and_Load_member 共用同一工具函数(读写两路同判据,
   避免"写修了读没修"再吃一轮)。
4) opaque-GEP 守卫报文补"同短名 struct 实例(key(IR 名)=槽数)"清单:清单含已具化项
   ⇒ 属"偏移与 GEP 未同源";全是 opaque ⇒ 属"body 从未 set_body"——一次报文即可判定是哪一侧。

找不到孪生体时**不兜底**:仍由守卫 fail-fast 并报出实例清单(本仓"不许静默兜底"约定)。

验证:py_compile 通过(BaseGen / HandlesAssign / HandlesExprAttr 三文件)。
2026-09-30 11:57:07 +08:00
TermiNexus a18ca4da3b fix(ExprAttr): 嵌套属性读的每个 silent return 都留痕(含内层失败原因链),Repl.vp:802 类错误不再只能看到"基座形态"
类别:a 编译器缺陷(可观测性补齐:报错点与真因相隔数层)

现象:TPC 编译 TransPyV/App/lib/core/Repl.vp:802
  `ct_names: list[str]* = GenApi._g_gen.TypeGenCType.CTypedefNames`
报「带注解赋值表达式 …(Attribute 形态)编译期求值为空(表达式未解析出目标、无值可存)…
赋值将被跳过」,报文里只有「基座形态=Attribute(.TypeGenCType←Attribute(._g_gen←Name(GenApi)))」,
看不出是三级链的哪一级失败、为什么失败。

判据:`_handle_attr_nested`(多级属性读)里有 7 处 `return None` 是**静默**的,而
`Gen._LastAttrNone`(`_NoteAttrNone` 记账,供 `_DescribeAttrBase` 回显"读取侧原因")只在
`_handle_attr_name`/`_gep_and_Load_member` 一侧登记 ⇒ 本函数的失败在报文里完全没有原因。
且嵌套读取时**内层**的记账会被外层覆盖,即使内层登记了也回显不出来。

修法(纯记账,不改任何判定/IR):
1. `_handle_attr_nested` 的每处静默 return 都调 `_NoteAttrNone` 记下**具体事实**:
   · 基座求值为空/非指针 → 附 type + **内层链的失败原因**(把 `_LastAttrNone` 里"字段名不同"
     的那条记录串进来,形成原因链);
   · 类名提示未命中 Gen.structs 键(报 structs 键数);
   · struct 实例类型异常;
   · body 仍 opaque 且无泛型特化成员;
   · **字段在类中取不到偏移**(报成员表项数 / body 槽数 —— 跨模块成员表缺失或漂移的关键判据);
   · 槽是 void 占位;
   · 结构体分支 pointee 未匹配任何类(报 structs 键数)。
2. `_DescribeAttrBase` 的回显键是 (字段名, 类名),本次登记与报错节点一致 ⇒ 下次同类报错将
   直接给出"读取侧原因=…",一轮定位到级与因。

验证:py_compile EXIT=0。真因证据(同一现场、另一侧):`TypeGenCType` 类体一个字段都没声明,
5 个字段全靠方法体裸 `self.x = ...`;其 .vpi(temp/05d515186a7c3668.vpi)里确实没有
CTypedefNames —— 跨模块成员表缺该字段即本次链断之处,已在 TransPyV 侧按"跨模块可见字段
必须在类体声明"补上(见另一仓 commit)。
2026-09-30 09:59:27 +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 935a5b372b fix(tpc): 属性读取返回 None 时登记「确切原因」,5 个 return None 点不再同义
类别:a(编译器缺陷 —— fail-fast 报文缺根因区分,5 个不同故障同报"求值为空")

现象:`self.Gen.ExprGen.translate_value(builder, pool, mod, ie.orelse, ...)`
(ExprGenOps.vp:97)报「调用实参编译期求值为空」,而同函数同对象的 `ie.test`
(:43)、`ie.body`(:78)求值正常。三个字段在 `IfExp` 布局里是**连续三槽**
(stub: %"…IfExp" = { i8*, AST*, MemBuddy*, i32×4, list*, AST*(test),
AST*(body), AST*(orelse) },共 11 元素),只有最后那个失败 ⇒ 必然是"偏移越出
body 元素数"这一类,但报文只说"求值为空",无法与"类名未解析 / 基座求值为空 /
结构体未匹配 / stub 无 body"区分。

改动(纯取证,不改变任何判定与 IR):
1. HandlesBase 新增 `_NoteAttrNone(Gen, ClassName, AttrName, Reason)`:把
   `(类名, 字段名, 原因)` 记到 `Gen._LastAttrNone`。
2. HandlesExprAttr 的 5 个 return None 点全部登记:
   - `_gep_and_Load_member`:偏移为 None;**偏移越界**(附 offset / body 元素数 /
     st 版元素数 / 成员表项数)。
   - `_handle_attr_name`:类名未解析;基座自身求值为空;结构体未匹配(附 ObjVal
     类型);stub 无 body;槽位越界(附 offset / pointee 元素数 / st 元素数)。
3. `_DescribeAttrBase` 追加三项事实:`struct body 元素数`、`字段 X 计算偏移`
   (`_get_member_offset`,异常则报异常类型)、以及与被报节点 (类名, 字段名)
   一致时回显 `读取侧原因=...`(不一致不回显,避免嵌套读取的旧记录冒充)。

依据:字段名在成员表里能找到却没读到值,只可能是"偏移 ≥ body 元素数"
(`_get_member_offset` 找不到字段时已 fail-fast,不会返回 None);因此
`偏移/body元素数/成员表项数` 三个数字是判定该情况的唯一依据,必须一次报全。
2026-09-29 17:46:58 +08:00
TermiNexus fd212b3ff8 fix(tpc): 联合强转 (T|t.CPtr)(x) 及其属性访问失败改为 fail-fast(附判定依据)
类别:b 机制漏豁免(把静默 return None 改成响亮失败并带证据)。

现场:TransPyV lib/core/Gen/Expr/ExprGenBase.vp:360 的
v = (ast.Expr*(node)).value 报“赋值表达式 'value'(Attribute 形态)编译期
求值为空”,而同一函数前三条 (ast.Assign/AnnAssign/AugAssign*(node)).value
同款写法正常 ⇒ 无法从报错看出是哪一步丢了类型。

两处静默返回改为 fail-fast(均只对该强转形态生效,其余路径行为不变):
1. HandlesExprCall._HandleTypeUnionCastLlvm:目标类型串解析失败(原为
   _vlog().warning + return None)。新增 _DescribeUnionCastFailure 取证:
   MergeTypes 返回值/ToString()/异常、_ExtractTypeStrFromUnionBinOp 结果,
   以及联合中每个操作数在符号表与类登记表(Gen.structs / _struct_sha1_map /
   class_sha1_map)的命中情况 —— 直接指认“基座类名没被当成类”还是
   “CPtr 标记侧解析失败”。
2. HandlesExprAttr._handle_attr_call_result:(T|t.CPtr)(x).attr 的 5 个
   return None(基座求值为空 / 非指针 / find_struct_by_pointee 未命中 /
   结构体不透明 / 成员偏移取不到)改为 _FailFastAttrCallBase,报文含联合
   基类名与三家登记表命中、被指类型 elements、class_members 项数与目标成员偏移。

原因:(T|t.CPtr)(x) 只可能来自指针强转(parser 把 (T*)x / (T*)(x) / T*(x)
统一产成该 Call),必须有值产出;静默丢弃会让整条表达式被判为空,把
“类名解析失败 / 结构体不透明 / 成员偏移取不到”三种不同根因混成同一条报文。
2026-09-29 12:23:54 +08:00
TermiNexus e33ac795ed fix(codegen): 指针强转基座 T*(x) 的字段写入补联合类名通道
与读取侧 _handle_attr_call_result 的联合分支同口径:_get_attr_ptr 新增 Call 基座分支,用 _extract_union_base_class 取裸类名后 bitcast/inttoptr 回 Ptr(类) 再 GEP 成员。此前写入侧只认 Name/Attribute/Subscript,强转基座的字段写入静默返回 None。
2026-09-27 16:02:40 +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 50cea6c7b3 fix(classdef,base,attr): 成员注解解析静默兜底改 fail-fast;新增按需输出的字段布局探针
HandlesBase.CollectAnnAssignMember: 注解解析返回 None / _ctype_to_llvm 得 void / 抛异常三处静默 i32、i8* 兜底改 fail-fast,报错带成员名+注解原文+BaseType/PtrCount 现场

HandlesClassDef: 方法内 self.x: T = ... 的同类三处兜底同样改 fail-fast(带类名/成员名/注解原文)

HandlesExprAttr: 新增 _diag_member_layout(默认静默,仅当 offset 为 None / members[offset] 名不符 / 类型与 elements[offset] 不一致时打一行,上限 15 行)
2026-09-26 21:25:52 +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 033c0a7771 fix(tpc): 修复 t.CVoid 清理暴露的三处类型解析缺口
SymbolTypeResolver: 裸 t.CPtr 作 typedef 值(无联合、无下标)时按 void* 展开。_find_base_type 把 attr==CPtr 归一为小写 ptr,而守卫 _PTR_MODIFIERS 写的是 CPtr 命不中,导致 ptr 被当成类型名存进 OriginalType,最终建成 %"<模块sha>.ptr" 幻影结构体(HANDLE/VOIDPTR/DIR 报 cannot store i8* to ...ptr*)。改前 t.CVoid | t.CPtr 走 BinOp 分支恰好绕过

HandlesExprAttr: 属性访问的成员查找补继承链回退(对齐 HandlesExprUtils._get_var_class 的口径)。字段声明在基类时元素类表的键是声明类,而收件人是子类,原实现只查收件人类自身;方法调用侧早已做 MRO 查询,故 150 处 self.Gen.X.method() 未暴露。修后 self.Gen.TypeGenCType.ImportAliasBuf 可解析(该字段在基类 TypeGenBase),且此前被静默丢弃的 _register_import_alias malloc 分支恢复生效

TypeConvert._base_ctype_to_llvm: 注册表给出完整类型串(CPtr/CArrayPtr/CNeedPtr/CAutoPtr -> i8*)时不再返回 None(_llvm_str_to_ir 只认标量名),改走 _type_str_to_llvm——与同文件 _basic_type_to_llvm 既有口径一致;否则 PtrCount 循环会构造 ir.PointerType(None)(llvmlite opaque 指针,无 .pointee),在 HandlesFunctions._GetFunctionSignatureLlvm 抛 AttributeError(opendir 的 FATAL)。触发集合经全注册表扫描恰好 4 个类

等价性验证: 31614 个符号 + 37527 个真实注解点位逐条对比改前/改后差异 0 条(崩溃输入除外,由 opaque ptr 变为 typed i8**)
2026-09-16 18:16:38 +08:00
TermiNexus 355811d64e chore(tpc): 移除属性链/调用分派错误路径的临时诊断打点
- HandlesBase: 删除 _AttrFailDiag 现场诊断(含模块别名链逐跳 dump),恢复精简错误信息

- HandlesExprAttr: 删除 [CHAIN-DBG] stderr 打点与 [attr-diag]/[attr-diag-nested] KeyError 包装

- HandlesExprCall: 删除 Unknown module 异常的 _rc_note 诊断后缀
2026-09-12 12:50:35 +08:00
TermiNexus ed3355202a fix(tpc): Mod.Var 链属性访问补第四条类回退(直读 var_/global_struct_class) 2026-09-12 12:42:59 +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 76d1ee6076 fix(compiler,peephole): TPC 属性链解析与窥孔输出瘦身
- TPC(lib/core): 任意级属性链按链前向类解析恢复 stub 退化字段; cast 局部 rowptr[X] 登记回填; 通用指针槽按静态类名 bitcast 兜底; 赋值 RHS 求值失败 fail-fast 防未初始化变量; 报错行按源码文本锚定并附 ATTR-DIAG 现场
- 窥孔(includes/llvmlite/__function.vp): 成员访问单级链模式; 窥孔移至 Renumber 前使 SSA 编号连续; T3 no-op bitcast 消除; 替换缓冲按最坏上界分配
- __builder/__module/string.vp 配套; 清理 Test 构建产物与 PROF 杂项
2026-09-08 11:02:37 +08:00
TermiNexus d698fad162 fix(TPC): 泛型基础类型字段访问特化,修复 GSList.Head 返回泛型占位 T*
_handle_attr_nested 对声明为特化泛型(GSList[BasicBlock] | t.CPtr)的字段(如 Function.Blocks)访问 Head/Tail/Count 时,基础 GSList 有 body 直接按基础类型返回泛型占位 T*,AnnAssign 存储时变量被污染为 T*(var_struct_class 错设为 T),后续字段访问/while 循环体翻译静默失败 → llvmlite __function.vp _find_max_ssa_number/RenumberSSA 死循环(LLvmLiteTest Test 3 崩溃根因)。

修复:字段类型为泛型占位指针时,用 class_member_element_class 记录的特化版本 bitcast 后访问返回真实元素类型(如 BasicBlock*);AnnAssign 兜底跳过泛型占位参与变量类型重建,防其它 T* 场景污染。
2026-08-20 15:35:21 +08:00
TermiNexus 0e80019033 fix(subscript): 泛型 T|t.CPtr 指针槽变量优先走 i8** load,修 8fbba list[str].get 返回类型不匹配
TPC 编译 TPV 时 _list.vp 泛型方法体 elem_ptr: T|t.CPtr = t.CPtr(...):
T 未解析时 var_struct_class[elem_ptr] 误注册 llvmlite.Value →
_HandleSubscriptLlvm 的 elem_class 推断为 Value → cast Value* → 与
get 声明 i8* 不匹配(llc 报错)。修复:
1. _is_struct_ptr_union 放宽——泛型参数 Name(单字母大写)也判定指针槽
   联合(标量 T 退化为 Ptr(i32) 不命中 i8 分支,安全)
2. _HandleSubscriptLlvm 的 var_ptr_element 分支提前到 elem_class 推断
   之前——T|t.CPtr 指针槽变量优先 i8** load i8*(8 字节)
2026-08-18 10:12:06 +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 6a672037c2 fix(attr): 修复联合类型转换 (X | t.CPtr)(arg) 后属性访问被丢弃
TPC 联合转换对非 CType 类(ast.Name/ast.Call 等类名)目标类型解析失败,
结果退回 Ptr(i8) 或错误类型,_handle_attr_call_result 的
find_struct_by_pointee 失败后返回 None,属性访问被静默丢弃——
((ast.Name|t.CPtr)(ov)).id 编译产物 store 0 次(TPV with 语句 asname
未绑定、pool 未定义根因)。修复:从联合 BinOp 提取真实基础类并
bitcast 到 Ptr(类) 再定位成员偏移;新增 _extract_union_base_class
辅助(跳过 CPtr/存储类/限定符修饰符)。
2026-08-13 07:44:43 +08:00
TermiNexus a39b5da0f8 基本稳定 2026-08-05 20:11:38 +08:00
TermiNexus 1837339f69 修正了一些错误 2026-07-26 20:32:26 +08:00
TermiNexus a277ded8d4 修正了 TPC 的一些错误,包括 Test 维护后 TPV 无法重新编译或重编译后越界的部分问题 2026-07-20 11:12:30 +08:00
t 796222a300 snapshot before regression test 2026-07-18 19:25:40 +08:00