fix(tpc): 补齐单/多参泛型类下标注解(list[str] → %"{模板sha1}.list[str]"*)

类别:a 编译器缺陷(机制缺失:两个注解解析器都只认双参定长 list[T, N])。

现场(前序报错):CallGenMixin.vp:149 调 ClassGenGeneric._specialize_generic_class
报「%\"650c1c3366d09e39.list[str]\"* 不能隐式转 i32」——实参侧正确、**形参侧
`type_args: list[str]*` 在符号表里成 i32**。同类:字段
`TypeGenBase.CTypedefNames: list[str] | t.CPtr` 在共享符号表里成 i8*(实测
temp/_shared_sym.json)。

真根因:单参泛型类下标在两处注解解析器里都无人处理,直接落到"未知类型"兜底:
  · TypeAnnotationResolver._from_node_subscript(IsListAnnotation 只认双参)
    → `return CTypeInfo()`(空 ⇒ i32 / 与 t.CPtr 合并成 i8*);
  · LLVMTypeMapper._resolve_subscript → warn + 'i32'。
而声明端 DeclarationGenerator._get_type_str 的泛型分支(L1393-1423)**一直是对的**
(`%"<模板sha1>.<特化名>"*`),三处规则分裂。

修复(一条规则源 + 两处消费 + 一处物化):
1. SymbolUtils 新增 ResolveGenericClassSpecName / IsGenericClassSubscriptBase ——
   与 DeclarationGenerator 泛型分支逐字同口径:
   spec = 基名 + '[' + ']['.join(ResolveGenericTypeArgStr(实参)) + ']';
   判据=该基名**有类定义**(符号表条目 IsStruct 或任一命名空间命中,实测 list
   条目 IsStruct=True,故等价覆盖声明端 non_struct_types ∪ _generic_class_names)。
   另加 GetStructSha1MapFromSymtab / GetTCAliasMapFromSymtab(从
   SymbolTable.translator 取 Phase2 已挂好的 _struct_sha1_map /
   _t_c_imported_names),供实参串跨模块类引用解析('<sha1>.AST')。
2. TypeAnnotationResolver._from_node_subscript 末尾(既有 rawptr/CPtr/CArray/
   list[T,N]/tuple 分支**之后**)接入:产出
   CTypeInfo(BaseType=CStruct(spec), IsStruct=True, Name=spec)(PtrCount 保持 0,
   与本文件既有结构体 promotion 同口径:`X | t.CPtr` 取 max→1 层、
   `rawptr[X]` +1→1 层,均与 declare 侧一致)。
3. LLVMTypeMapper._resolve_subscript 同样位置接入:产出 `%struct.<spec>*`
   (与 _resolve_name / _resolve_attribute 的类引用同一表示)。
4. BaseGen._get_or_create_struct:特化名(含 '[')先按**基名**查
   _struct_sha1_map 取模板 sha1 再拼 IR 名 —— 否则会用**使用方模块** sha1 拼出
   '<本模块sha1>.list[str]',与 declare/define 端 '<模板sha1>.list[str]' 分裂。

自测(vast AST):list[str]→'list[str]'、dict[str,int]→'dict[str][int]'、
list[rawptr[AST]]→'list[AST*]'、rawptr[int]/tuple[…]→None(仍由既有分支处理)。
This commit is contained in:
TermiNexus committed 2026-09-29 13:17:36 +08:00
1 parent a6c9003a19
commit 25cda80995
4 files changed
+130 -4

No files matched your search

+10 -2
View File
@@ -546,10 +546,18 @@ class BaseGenMixin:
if Entry.BaseType is _t.CEnum:
return self._enum_int_type(clean_name, Entry)
ns_name: str
# 泛型特化名('list[str]' / 'dict[str][int]'):类→模块 sha1 表是按**基名**
# 登记的 ClassDef('list' 来自 includes/_list.vp),特化名本身不在表里 ⇒
# 若不先按基名取 sha1,_mangle_name 会拼出 '<使用方模块sha1>.list[str]',
# 与 declare 端(DeclarationGenerator `gc_sha1 = struct_sha1_map.get(gc_name,
# module_sha1)` → '%"{模板sha1}.list[str]"*')及定义端
# (HandlesClassDef 特化时 Gen.module_sha1 = 模板模块)**三处分裂**。
_tmpl_name: str = clean_name.split('[', 1)[0] if '[' in clean_name else clean_name
_tmpl_sha1: str | None = self._struct_sha1_map.get(_tmpl_name, '') or None
if source_sha1:
ns_name = f"{source_sha1}.{clean_name}"
elif clean_name in self._struct_sha1_map:
ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}"
elif _tmpl_sha1:
ns_name = f"{_tmpl_sha1}.{clean_name}"
else:
ns_name = self._mangle_name(clean_name)
# 按 IR 名去重(见 _FindStructByIrName):该 IR 名字的对象可能已由**别的键**
+16 -1
View File
@@ -20,7 +20,8 @@ if TYPE_CHECKING:
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap
from lib.core.SymbolUtils import (
IsTModule, IsListAnnotation, IsCPtrNode, IsCPtrSubscriptNode,
IsRawPtrSubscriptNode, EnumIntWidth)
IsRawPtrSubscriptNode, EnumIntWidth,
ResolveGenericClassSpecName, GetStructSha1MapFromSymtab, GetTCAliasMapFromSymtab)
from lib.includes import t as _t
from lib.includes.t import CTypeRegistry
@@ -410,6 +411,20 @@ class LLVMTypeMapper:
else:
elem_type = self.get_llvm_type_str(slice_node)
return elem_type + '*'
# 泛型类下标(单/多参):list[str] / dict[str][int] / 用户泛型 Box[Node]。
# 特化名与声明端(DeclarationGenerator 泛型分支)同口径,见
# SymbolUtils.ResolveGenericClassSpecName;输出与 _resolve_name /
# _resolve_attribute 的类引用**同一表示**(%struct.<名>*,短名交给
# TypeConvert._type_str_to_llvm_base 按 _struct_sha1_map 物化到
# %"{模板sha1}.<特化名>"*)。此前单参泛型下标落到下方 warn + 'i32' ⇒
# 形参类型串成 i32(现场:ClassGenGeneric._specialize_generic_class 的
# 形参 `type_args: list[str]*`)。
_Spec: str | None = ResolveGenericClassSpecName(
node, self._symtab,
GetStructSha1MapFromSymtab(self._symtab),
GetTCAliasMapFromSymtab(self._symtab))
if _Spec:
return f'%struct.{_Spec}*'
self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型,回退到 i32")
return 'i32'
+83
View File
@@ -2733,6 +2733,89 @@ def _ResolveUnionArgStr(Node: ast.BinOp, TCAliasMap: dict[str, tuple[str, str]]
return AddPointerLayers(BaseType, Layers)
def GetStructSha1MapFromSymtab(Symtab: object | None) -> dict[str, str]:
"""从符号表取「类名 → 定义模块 sha1」表(Phase2 在 Convert 前挂到 translator)。"""
_Tr: Any = getattr(Symtab, 'translator', None)
_Map: Any = getattr(_Tr, '_struct_sha1_map', None) if _Tr is not None else None
return _Map if isinstance(_Map, dict) else {}
def GetTCAliasMapFromSymtab(Symtab: object | None) -> dict | None:
"""从符号表取 t/c 导入别名表(`from t import CInt as myint`)。缺则 None。"""
_Tr: Any = getattr(Symtab, 'translator', None)
_Map: Any = getattr(_Tr, '_t_c_imported_names', None) if _Tr is not None else None
return _Map if isinstance(_Map, dict) and _Map else None
def IsGenericClassSubscriptBase(Node: ast.AST, Symtab: object | None = None,
StructSha1Map: dict[str, str] | None = None) -> bool:
"""下标基名是否为「有类定义的泛型类」(内建 list/dict/set… 或用户泛型类)。
判据与 DeclarationGenerator._get_type_str 的泛型分支(L1393-1423)同一条规则源:
**该名有类定义**即按泛型特化处理。内建容器本身在 includes/_list.vp / _dict.vp 等
就是类(实测符号表 `list` 条目 IsStruct=True),故本判据等价覆盖声明端的
`non_struct_types ∪ _generic_class_names`;用户泛型类(Box[T])同样命中。
只认 Name 形态:`t.CPtr[...]` / `t.CArray[...]` / 裸 `array[...]` / 定长
`list[T, N]` / `rawptr[...]` 等由调用方各自分支先行处理,不走这里。
"""
if not isinstance(Node, ast.Name) or not Node.id:
return False
if StructSha1Map and Node.id in StructSha1Map:
return True
if Symtab is not None:
_Entry: Any = None
try:
if hasattr(Symtab, 'lookup'):
_Entry = Symtab.lookup(Node.id)
elif hasattr(Symtab, 'get'):
_Entry = Symtab.get(Node.id)
except Exception:
_Entry = None
if _Entry is not None and getattr(_Entry, 'IsStruct', False):
return True
for _Ns in (getattr(Symtab, '_namespaces', {}) or {}).values():
if not isinstance(_Ns, dict):
continue
_Cand: Any = _Ns.get(Node.id)
if _Cand is not None and getattr(_Cand, 'IsStruct', False):
return True
return False
def ResolveGenericClassSpecName(Node: ast.Subscript, Symtab: object | None = None,
StructSha1Map: dict[str, str] | None = None,
TCAliasMap: dict | None = None) -> str | None:
"""泛型类下标注解 → 声明端同口径的**特化名**('list[str]' / 'dict[str][int]')。
与 DeclarationGenerator._get_type_str 的泛型分支(L1393-1423)逐字同口径:
spec = 基名 + '[' + ']['.join(实参串) + ']'
实参串走 ResolveGenericTypeArgStr(与定义端 _mangle_generic_class_name 同一规则源)。
非泛型类下标(指针下标 / 定长数组 / t 模块类型 / 未知名)返回 None,由调用方各自
既有分支处理(调用点必须放在那些分支**之后**)。
必要性:单参泛型下标此前在两个注解解析器里都 miss(TypeAnnotationResolver 只认
双参定长 list[T, N];LLVMTypeMapper 亦然)⇒ 落到"未知类型"兜底 i32 / 空 CTypeInfo,
形参与成员类型整体错位(现场:ClassGenGeneric._specialize_generic_class 的
形参 `type_args: list[str]*` 在符号表里成 i32;字段
`TypeGenBase.CTypedefNames: list[str] | t.CPtr` 成 i8*)。
"""
if not isinstance(Node, ast.Subscript):
return None
Base: ast.AST = Node.value
if not IsGenericClassSubscriptBase(Base, Symtab, StructSha1Map):
return None
SliceNode: ast.AST = Node.slice
Args: list[ast.AST] = list(SliceNode.elts) if isinstance(SliceNode, ast.Tuple) else [SliceNode]
if not Args:
return None
Mangled: list[str] = [
ResolveGenericTypeArgStr(A, TCAliasMap, StructSha1Map) for A in Args]
if not any(Mangled):
return None
return Base.id + '[' + ']['.join(Mangled) + ']'
def ResolveGenericTypeArgStr(Node: ast.AST, TCAliasMap: dict[str, tuple[str, str]] | None = None,
StructSha1Map: dict[str, str] | None = None) -> str:
"""泛型实参的最终 mangled 串(喂给 _mangle_generic_class_name 的单参数)。
+21 -1
View File
@@ -8,7 +8,9 @@ from typing import TYPE_CHECKING
from lib.core.Handles.HandlesBase import CTypeInfo, BuiltinTypeMap, CTypeHelper
from lib.core.ConstEvaluator import ConstEvaluator
from lib.core.SymbolUtils import IsTModule, IsTModulePath, IsListAnnotation
from lib.core.SymbolUtils import (
IsTModule, IsTModulePath, IsListAnnotation,
ResolveGenericClassSpecName, GetStructSha1MapFromSymtab, GetTCAliasMapFromSymtab)
from lib.includes import t
from lib.constants.config import mode as _config_mode
@@ -1020,6 +1022,24 @@ class TypeAnnotationResolver:
Result.BaseType = SliceInfo.BaseType if (SliceInfo and SliceInfo.BaseType) else t.CVoid()
Result.PtrCount = (SliceInfo.PtrCount if SliceInfo else 0) + base_info.PtrCount
return Result
# 泛型类下标(单/多参):list[str] / dict[str][int] / 用户泛型 Box[Node]。
# 特化名与声明端(DeclarationGenerator 泛型分支)同口径,见
# SymbolUtils.ResolveGenericClassSpecName。此前单参泛型下标在下方直接落到
# "未知类型"空 CTypeInfo ⇒ 形参/成员类型退化成 i32 或 void 指针链
# (现场:type_args: list[str]* 的形参 i32;CTypedefNames: list[str] | t.CPtr → i8*)。
# 表示口径与本文件既有结构体 promotion 逐字一致(BaseType=CStruct + IsStruct +
# Name,PtrCount 保持 0):`X | t.CPtr` 由 _from_node_binop 取 max → 1 层,
# `rawptr[X]` 由上方分支 +1 → 1 层,均与 declare 侧 %"{sha}.X[*]"* 一致。
_Spec: str | None = ResolveGenericClassSpecName(
Node, SymbolTable,
GetStructSha1MapFromSymtab(SymbolTable),
GetTCAliasMapFromSymtab(SymbolTable))
if _Spec:
Result = CTypeInfo()
Result.BaseType = t.CStruct(name=_Spec)
Result.IsStruct = True
Result.Name = _Spec
return Result
return CTypeInfo()
@staticmethod