diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index b18f39e..8e5496d 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -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 名字的对象可能已由**别的键** diff --git a/lib/core/LLVMTypeMapper.py b/lib/core/LLVMTypeMapper.py index 4243b10..9143c1a 100644 --- a/lib/core/LLVMTypeMapper.py +++ b/lib/core/LLVMTypeMapper.py @@ -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' diff --git a/lib/core/SymbolUtils.py b/lib/core/SymbolUtils.py index c60c0f0..3c2796c 100644 --- a/lib/core/SymbolUtils.py +++ b/lib/core/SymbolUtils.py @@ -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 的单参数)。 diff --git a/lib/core/TypeAnnotationResolver.py b/lib/core/TypeAnnotationResolver.py index ec526e3..fc63c69 100644 --- a/lib/core/TypeAnnotationResolver.py +++ b/lib/core/TypeAnnotationResolver.py @@ -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