diff --git a/App/lib/core/Gen/Type/TypeGenResolve.vp b/App/lib/core/Gen/Type/TypeGenResolve.vp index bb28258..d8971aa 100644 --- a/App/lib/core/Gen/Type/TypeGenResolve.vp +++ b/App/lib/core/Gen/Type/TypeGenResolve.vp @@ -261,6 +261,50 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase): # fcount=-1 = opaque 哨兵(区别于空结构体 {}:后者 fcount==0 是"完整定义、 # 可 alloca");与 llvmlite 的跨模块 opaque 声明同一表示。 return llvmlite.Struct(pool, None, -1, full) + + def _is_non_class_type_name(self, pool: memhub.MemBuddy*, name: str) -> int: + """该类型名是否**本就无类归属**(CTypedef / 语言内置标量 / 泛型形参)——不是类名。 + + 用途:`_norm_type_arg_name` 的"保留裸名"取证门控。该取证的前提是"这是个**类名**" + —— 类名有 "{定义模块SHA1}.类" 这一 mangling 形式,留在裸名才会与带前缀形式分裂; + 而下列名字的名域就是它自身,不存在第二个形式(TPC 侧 + `SymbolUtils.NormalizeGenericArgName` 同样原样保留)⇒ 对它报 ERROR 是纯噪声。 + 现场(2026-09-30):includes/traceback.vp:532 + `FrameAddr: t.CArray[uint64, TRACEBACK_FRAME_BUF]` 的实参 'uint64' 是 + includes/builtins.vp 的 `typedef uint64 = t.CUInt64T`,不进类归属是**预期**, + 却每次编译刷一条 ERROR。 + + 判据(正向白名单,逐条可查,不猜): + ① CTypedef 动态表命中 —— typedef 唯一真源(Phase1 1b 的 + register_ctypedef_from_source 文本扫描注册;表在文件边界被 clear 后重建, + 故紧跟 ② 的 builtins 兜底,与 `resolve_typedef_or_map` 的"统一口径"一致); + ② builtins.vp 的 typedef(如 `typedef uint64 = t.CUInt64T`):builtins 始终 + 在编译链内,但其 typedef 不随当前文件 from_imports 注入 ⇒ 表可能 miss, + 必须走与 `resolve_typedef_or_map` 同一兜底(命中即注册进表,幂等); + ③ 语言内置标量/字符串名 —— 与 `_resolve_annot_type_name` 的跳过清单同口径; + ④ 泛型形参名(单字母大写,T/U/V…)—— 特化前出现在实参位属正常。 + """ + if name is None or name[0] == '\0': + return 0 + if self.Gen.TypeGenCType is not None: + _ts_nc: str = self.Gen.TypeGenCType.lookup_ctypedef(name) + if _ts_nc is not None and self.Gen.TypeGenCType.CTypedefFound != 0: + return 1 + if self._lookup_builtins_typedef(pool, name) is not None: + return 1 + if string.strcmp(name, "int") == 0: return 1 + if string.strcmp(name, "char") == 0: return 1 + if string.strcmp(name, "bool") == 0: return 1 + if string.strcmp(name, "float") == 0: return 1 + if string.strcmp(name, "double") == 0: return 1 + if string.strcmp(name, "str") == 0: return 1 + if string.strcmp(name, "bytes") == 0: return 1 + if string.strcmp(name, "void") == 0: return 1 + if string.strlen(name) == 1: + if name[0] >= 'A' and name[0] <= 'Z': + return 1 + return 0 + def _norm_type_arg_name(self, pool: memhub.MemBuddy*, type_name: str, from_imports: str) -> str: @@ -289,7 +333,9 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase): vs 目标 %"…list[rawptr[AST]]"*;includes/ast/base.vp:357 `children = list[rawptr[AST]](self.pool, 8)` 同族反向:字段侧裸名 vs 构造侧带前缀) - 6. 仍查不到:返回原串(内置类型名等,保持原样) + 6. 仍查不到:返回原串(CTypedef / 内置标量 / 泛型形参等**非类名**保持原样; + 它们本就没有"带前缀形式"可分裂,故也不触发下方的"保留裸名"取证日志 —— + 判据见 _is_non_class_type_name) 返回 None 表示 type_name 为 None。 """ @@ -560,18 +606,18 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase): string.strncpy(_sha_b, _tp_nm, _sp_l - 1) _sha_b[_sp_l - 1] = '\0' _def_sha1 = _sha_b - # ⑤ **本文件顶层类名真源**(与"窗口"、与类定义顺序无关):Translator 的文件 - # 入口已把"本文件顶层 ClassDef 的类名 + 本文件模块 SHA1"登记进 StructGen - # (register_file_classes)。模块级变量/前向声明**早于**类定义被翻译 - # (Translator.vp:592-601 < :602 translate_children)时,CurDefModuleSha1 - # 尚为 None ⇒ ①②③④ 全落空,裸类名(如 base.vp:148 `_append_child(..., - # lst: list[rawptr[AST]])` 的形参)会被冻结成裸名版本并与带 SHA1 形式分裂。 - # 判据是**正向事实**:该名字确由本文件声明(且本文件模块 SHA1 已知)⇒ 不猜。 - if _def_sha1 is None: - _file_sha: str = self.Gen.StructGen.get_file_module_sha1() - if _file_sha is not None: - if self.Gen.StructGen.is_file_class(pool, type_name) != 0: - _def_sha1 = _file_sha + # ⑤ **本文件顶层类名真源**(与"窗口"、与类定义顺序无关):Translator 的文件 + # 入口已把"本文件顶层 ClassDef 的类名 + 本文件模块 SHA1"登记进 StructGen + # (register_file_classes)。模块级变量/前向声明**早于**类定义被翻译 + # (Translator.vp:592-601 < :602 translate_children)时,CurDefModuleSha1 + # 尚为 None ⇒ ①②③④ 全落空,裸类名(如 base.vp:148 `_append_child(..., + # lst: list[rawptr[AST]])` 的形参)会被冻结成裸名版本并与带 SHA1 形式分裂。 + # 判据是**正向事实**:该名字确由本文件声明(且本文件模块 SHA1 已知)⇒ 不猜。 + if _def_sha1 is None: + _file_sha: str = self.Gen.StructGen.get_file_module_sha1() + if _file_sha is not None: + if self.Gen.StructGen.is_file_class(pool, type_name) != 0: + _def_sha1 = _file_sha if _def_sha1 is not None: res_d: str = self._concat_sha1_class(pool, _def_sha1, type_name) if res_d is not None: @@ -592,6 +638,18 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase): if _def_mod is not None and _w_cls_cur is not None: if string.strcmp(_w_cls_cur, type_name) != 0: _w_need_log = 1 + # 门控(2026-09-30):取证的前提是"这是个**类名**"——只有类名存在 + # "{定义模块SHA1}.类" 这第二个形式可分裂。CTypedef(如 builtins.vp 的 + # `typedef uint64 = t.CUInt64T`)/ 语言内置标量 / 泛型形参的名域就是它自身, + # 保留裸名即规范形式(TPC NormalizeGenericArgName 同口径)⇒ 不对它们报错。 + # 现场:includes/traceback.vp:532 `t.CArray[uint64, TRACEBACK_FRAME_BUF]` + # 每编译一次刷一条与真因无关的 ERROR。 + # 只对**结构体表里根本没有该名**(_bare_entry is None)的情形豁免:若它确 + # 是已注册的类(如 .vpi 半条目)只是缺定义模块 SHA1,那是真正的归属缺口, + # 照旧报出(不被同名 typedef 掩盖)。 + if _w_need_log != 0 and _bare_entry is None \ + and self._is_non_class_type_name(pool, type_name) != 0: + _w_need_log = 0 if _w_need_log != 0: _w_mod: str = "None" if _def_mod is not None: _w_mod = _def_mod