CallGenCtor._infer_generic_ctor_type_arg 的 Call 分支此前与泛型函数路径同款名字子串猜测(含 Int→int、Float→double),把 CUInt64T/CInt16T 静默归成 int=i32、CFloat32T 猜成 double。改为:把被调表达式交给注解解析器,命中标量才据精确位宽映射;非标量/不可解析仍 fail-fast(保持原有"明确的类型意图却无法解析"报错)。 新增 ClassGenGeneric.infer_scalar_type_arg_from_llvm_ty 作为两处共用的唯一入口(内部走 _infer_scalar_type_name_from_spec),泛型函数路径一并改为调用它,消除重复的 arena/SpecFromLLVMType 样板,保证两处同口径。
1339 lines
73 KiB
Plaintext
1339 lines
73 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
|
||
from . import ClassGenBase
|
||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||
|
||
|
||
# 泛型特化递归深度上限(泛型循环套用防护)
|
||
# 正常嵌套特化深度 ≤ 3(如 list[list[str]]);64 远超合理值,命中即循环。
|
||
define GENERIC_SPEC_MAX_DEPTH = 64
|
||
# 泛型模板表容量上限(与 GenericClassNames 等 pool 表可容纳的模板数对齐;
|
||
define GENERIC_TEMPLATE_MAX = 512
|
||
# 泛型特化缓存表容量
|
||
define SPEC_CACHE_MAX = 512
|
||
|
||
# ============================================================
|
||
# ClassGenGeneric - 泛型模板注册/特化/克隆
|
||
# ============================================================
|
||
novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||
"""泛型模板注册/特化/克隆"""
|
||
|
||
# ============================================================
|
||
# 簇 C:泛型模板注册/特化(P5-2 第三阶段迁移,函数体来自
|
||
# HandlesClassDef.vp,逻辑零改动)
|
||
#
|
||
# 说明:
|
||
# - _generic_class_* 全局表已迁入 self.GenericClassNames/
|
||
# GenericClassNodes/GenericClassSha1s(P5-2 收尾)
|
||
# - _spec_* 全局缓存迁移为 self.SpecKeys/SpecNames/SpecCount
|
||
# ============================================================
|
||
|
||
def _is_generic_class(self, tp: list[str]*) -> int:
|
||
"""检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否
|
||
|
||
接收 type_params 而非 cd,避免 cd.type_params 属性访问
|
||
因跨模块类型推断失败返回 None。
|
||
"""
|
||
if tp is None: return 0
|
||
return 1
|
||
def _dup_perm_str(self, s: str) -> str:
|
||
"""深拷贝字符串到永久池(无永久池/分配失败时原样返回入参)"""
|
||
if s is None: return None
|
||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||
if perm is None: return s
|
||
n: sizet = string.strlen(s)
|
||
b: str = perm.alloc(n + 1)
|
||
if b is None: return s
|
||
string.strcpy(b, s)
|
||
return b
|
||
def _register_generic_template(self, pool: memhub.MemBuddy*,
|
||
cd: ast.ClassDef*,
|
||
module_sha1: str) -> None:
|
||
"""注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)
|
||
|
||
[池归属修复] 这四张表 + GenericClassTpParams 的语义都是**永久表**:
|
||
批量编译下要在 Phase1 的 reset_to(mark1) 与 Phase2 的 reset_to(mark2) 之后
|
||
继续可读(读点见 _find_generic_template/_find_generic_template_sha1/
|
||
_find_generic_template_file/_find_generic_template_tp_params,均有"遍历
|
||
悬空内存 strcmp 即崩溃"的记录),REPL 下还要跨片段存活。但注册点有三个:
|
||
- Phase1Scan.vp:322 → perm(永久池);
|
||
- Phase2/__init__.vp:321 → perm(永久池);
|
||
- ClassGenDef.vp:78 → trans.Pool(**会被 reset_to 回收的池**)。
|
||
于是"表在哪个池"取决于哪条路径先注册到表:批量编译里两遍预注册
|
||
(_PreRegisterAllGenericTemplates / _PreRegisterAppGenericTemplates)在前,
|
||
表被建在永久池 ⇒ 第三条路径只是追加;而两遍预注册都没建成表时(例如
|
||
includes 的泛型 marker 文本预筛未命中),第三条路径把表建在 trans.Pool 上,
|
||
随 mark 回收 ⇒ 后续 _find_generic_template 遍历悬空表(UAF)。REPL 从不跑
|
||
Phase1/Phase2,第三条路径是**唯一**注册点 ⇒ 表必然落在会被每片段 reset 的
|
||
池上,M4 一旦在片段里定义泛型类就是必现 UAF。
|
||
故此处统一:表体一律用永久池(无永久池时退回入参池,即旧行为),并把
|
||
调用方池里的三个串(类名/SHA1/来源文件)深拷贝进永久池——它们同样会随
|
||
调用方池回收而悬空(挂名 strcmp 即读悬空内存)。
|
||
批量编译不变量:变更只影响"表与串分配在哪个池",写入的**内容**逐字不变
|
||
(同样的类名/节点/ SHA1/文件路径,同样的插入顺序与查重),发射的 IR 与
|
||
符号名不受池选择影响 ⇒ 逐字不变。
|
||
"""
|
||
if cd is None or cd.name is None: return
|
||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||
table_pool: memhub.MemBuddy* = perm
|
||
if table_pool is None:
|
||
table_pool = pool
|
||
if self.GenericClassNames is None:
|
||
self.GenericClassNames = list[str](table_pool, 8)
|
||
self.GenericClassNodes = list[ast.ClassDef*](table_pool, 8)
|
||
self.GenericClassSha1s = list[str](table_pool, 8)
|
||
self.GenericClassFiles = list[str](table_pool, 8)
|
||
if self.GenericClassTpParams is None:
|
||
if perm is None: return
|
||
self.GenericClassTpParams = perm.alloc(GENERIC_TEMPLATE_MAX * 8)
|
||
if self.GenericClassTpParams is None: return
|
||
string.memset(self.GenericClassTpParams, 0, GENERIC_TEMPLATE_MAX * 8)
|
||
# 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败)
|
||
names_local: list[str]* = self.GenericClassNames
|
||
cn: sizet = len(names_local)
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, cd.name) == 0:
|
||
# 同名条目已存在时不能直接 return:**首次注册的节点可能还没有
|
||
# type_params**(Phase1Scan 的泛型 marker 文本预筛构造的 ClassDef
|
||
# 就是这种情况),此时 _copy_type_params_stdlib 返回 None ⇒
|
||
# GenericClassTpParams[i] 留 0。而后续携带真实 type_params 的那次
|
||
# 注册会被这里的同名去重拦掉 ⇒ 类型参数名永久缺失 ⇒
|
||
# _find_generic_template_tp_params 因 buf_addr==0 返回 None ⇒
|
||
# _specialize_generic_class 退回过期的 template_cd.type_params
|
||
# (空/已回收)⇒ 泛型上下文为空 ⇒ 模板方法体里的 `T` 变成
|
||
# "NameError: 未定义名称 'T'"(现场:includes/vector.vp:12
|
||
# `self.elem_size = T.__sizeof__()`)。
|
||
# 故此处补缺:本次能拿到 tp 名就把空槽填上,并把节点换成信息更全的
|
||
# 这一个(节点也用于 _find_generic_template 的后续读取)。
|
||
if self.GenericClassTpParams is not None and i < GENERIC_TEMPLATE_MAX \
|
||
and self.GenericClassTpParams[i] == 0:
|
||
back_buf: str = self._copy_type_params_stdlib(cd.type_params)
|
||
if back_buf is not None:
|
||
self.GenericClassTpParams[i] = sizet(back_buf)
|
||
if self.GenericClassNodes is not None:
|
||
self.GenericClassNodes.set(i, cd)
|
||
return
|
||
# type_params stdlib 深拷贝:模板节点的 type_params 是 pool 分配的
|
||
tp_names_buf: str = self._copy_type_params_stdlib(cd.type_params)
|
||
self.GenericClassNames.append(self._dup_perm_str(cd.name))
|
||
self.GenericClassNodes.append(cd)
|
||
self.GenericClassSha1s.append(self._dup_perm_str(module_sha1))
|
||
# 同时保存模板来源文件路径(错误定位用,见字段注释)
|
||
self.GenericClassFiles.append(self._dup_perm_str(self.Gen.TypeGenResolve.get_current_file()))
|
||
if tp_names_buf is not None and cn < GENERIC_TEMPLATE_MAX:
|
||
self.GenericClassTpParams[cn] = sizet(tp_names_buf)
|
||
def _copy_type_params_stdlib(self, tp: list[str]*) -> str:
|
||
"""将模板 type_params 深拷贝为空格分隔、NUL 结尾的 stdlib 缓冲区
|
||
|
||
TPC Python 参考实现:type_params = [tp.name for tp in Node.type_params]
|
||
(Python 字符串不可变天然跨阶段存活);Viper 的 type_params 是 pool
|
||
分配 list,跨 Phase 内容可能被复用污染,必须注册时拷贝到 stdlib。
|
||
返回缓冲区指针;tp 为 None(非泛型)或分配失败返回 None。
|
||
"""
|
||
if tp is None:
|
||
return None
|
||
tp_n: sizet = len(tp)
|
||
if tp_n == 0:
|
||
return None
|
||
# 计算总长:各名字长度 + (n-1) 个空格 + NUL
|
||
total: sizet = 1
|
||
ti: sizet
|
||
for ti in range(tp_n):
|
||
tp_name: str = tp.get(ti)
|
||
if tp_name is not None:
|
||
total += string.strlen(tp_name) + 1
|
||
buf: str = CompilerFactory.factory.PermPool.alloc(total)
|
||
if buf is None:
|
||
return None
|
||
buf[0] = '\0'
|
||
for ti in range(tp_n):
|
||
tp_name = tp.get(ti)
|
||
if tp_name is None:
|
||
continue
|
||
if ti > 0 and buf[0] != '\0':
|
||
string.strcat(buf, " ")
|
||
string.strcat(buf, tp_name)
|
||
return buf
|
||
|
||
# ============================================================
|
||
# 泛型函数模板(PEP 695 def f[T](...) / def pair[T1,T2](...))
|
||
#
|
||
# 范式照搬同文件泛型类模板(_register_generic_template / _find_generic_template
|
||
# / _specialize_generic_class):注册表落永久池、tp 名 stdlib 深拷贝、特化名
|
||
# 复用 _mangle_generic_class_name 做唯一规范化、去重复用 SpecKeys/SpecNames。
|
||
# 差异:
|
||
# 1) 节点是 FunctionDef;表键含定义模块 SHA1("{sha1}.{fname}",避免跨模块
|
||
# 同名函数串味——函数名重复远多于类名);
|
||
# 2) 新增调用点推断(显式下标 / 按签名形参位 / 返回值注解上下文);
|
||
# 3) 特化定位是"发射 define"(translate_function_def);全局缓存命中而当前
|
||
# 模块无该符号时补 declare(_ensure_generic_func_declare)。
|
||
# ============================================================
|
||
def _is_generic_function(self, tp: list[str]*) -> int:
|
||
"""检查 FunctionDef 是否有类型参数(泛型函数),返回 1=是 / 0=否"""
|
||
if tp is None: return 0
|
||
return 1
|
||
|
||
def _register_generic_func_template(self, pool: memhub.MemBuddy*,
|
||
fd: ast.FunctionDef*,
|
||
module_sha1: str) -> None:
|
||
"""注册泛型函数模板(键 "{module_sha1}.{函数名}" + 节点 + tp 名)
|
||
|
||
表体一律落永久池(同 _register_generic_template 的池归属修复):扫描
|
||
预注册路径传永久池,但 forward_declare 兜底路径传的是会被 reset 的
|
||
trans.Pool,故键/SHA1/来源文件串统一深拷贝进永久池,防跨 mark 悬空。
|
||
"""
|
||
if fd is None or fd.name is None or module_sha1 is None: return
|
||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||
table_pool: memhub.MemBuddy* = perm
|
||
if table_pool is None:
|
||
table_pool = pool
|
||
if self.GenericFuncKeys is None:
|
||
self.GenericFuncKeys = list[str](table_pool, 8)
|
||
self.GenericFuncNodes = list[ast.FunctionDef*](table_pool, 8)
|
||
self.GenericFuncSha1s = list[str](table_pool, 8)
|
||
self.GenericFuncFiles = list[str](table_pool, 8)
|
||
if self.GenericFuncTpParams is None:
|
||
if perm is None: return
|
||
self.GenericFuncTpParams = perm.alloc(GENERIC_TEMPLATE_MAX * 8)
|
||
if self.GenericFuncTpParams is None: return
|
||
string.memset(self.GenericFuncTpParams, 0, GENERIC_TEMPLATE_MAX * 8)
|
||
# 键 = "{sha1}.{name}"(新缓冲区拼接,避免原地 strcat 溢出)
|
||
key_len: sizet = string.strlen(module_sha1) + string.strlen(fd.name) + 2
|
||
key_buf: str = table_pool.alloc(key_len)
|
||
if key_buf is None: return
|
||
viperlib.snprintf(key_buf, key_len, "%s.%s", module_sha1, fd.name)
|
||
keys_local: list[str]* = self.GenericFuncKeys
|
||
kn: sizet = len(keys_local)
|
||
ki: sizet
|
||
for ki in range(kn):
|
||
knm: str = keys_local.get(ki)
|
||
if knm is not None and string.strcmp(knm, key_buf) == 0: return
|
||
tp_names_buf: str = self._copy_type_params_stdlib(fd.type_params)
|
||
self.GenericFuncKeys.append(self._dup_perm_str(key_buf))
|
||
self.GenericFuncNodes.append(fd)
|
||
self.GenericFuncSha1s.append(self._dup_perm_str(module_sha1))
|
||
self.GenericFuncFiles.append(self._dup_perm_str(self.Gen.TypeGenResolve.get_current_file()))
|
||
if tp_names_buf is not None and kn < GENERIC_TEMPLATE_MAX:
|
||
self.GenericFuncTpParams[kn] = sizet(tp_names_buf)
|
||
|
||
def _find_generic_func_template(self, key: str) -> ast.FunctionDef*:
|
||
"""按 "{sha1}.{fname}" 键查找泛型函数模板节点,未找到返回 None"""
|
||
if self.GenericFuncKeys is None or key is None:
|
||
return None
|
||
keys_local: list[str]* = self.GenericFuncKeys
|
||
nodes_local: list[ast.FunctionDef*]* = self.GenericFuncNodes
|
||
kn: sizet = len(keys_local)
|
||
i: sizet
|
||
for i in range(kn):
|
||
knm: str = keys_local.get(i)
|
||
if knm is not None and string.strcmp(knm, key) == 0:
|
||
return nodes_local.get(i)
|
||
return None
|
||
|
||
def _find_generic_func_template_sha1(self, key: str) -> str:
|
||
"""按键查找泛型函数模板的来源模块 SHA1,未找到返回 None"""
|
||
if self.GenericFuncKeys is None or key is None:
|
||
return None
|
||
keys_local: list[str]* = self.GenericFuncKeys
|
||
sha1s_local: list[str]* = self.GenericFuncSha1s
|
||
kn: sizet = len(keys_local)
|
||
i: sizet
|
||
for i in range(kn):
|
||
knm: str = keys_local.get(i)
|
||
if knm is not None and string.strcmp(knm, key) == 0:
|
||
return sha1s_local.get(i)
|
||
return None
|
||
|
||
def _find_generic_func_template_file(self, key: str) -> str:
|
||
"""按键查找泛型函数模板来源文件路径(错误定位用),未找到返回 None"""
|
||
if self.GenericFuncKeys is None or key is None:
|
||
return None
|
||
keys_local: list[str]* = self.GenericFuncKeys
|
||
files_local: list[str]* = self.GenericFuncFiles
|
||
kn: sizet = len(keys_local)
|
||
i: sizet
|
||
for i in range(kn):
|
||
knm: str = keys_local.get(i)
|
||
if knm is not None and string.strcmp(knm, key) == 0:
|
||
return files_local.get(i)
|
||
return None
|
||
|
||
def _find_generic_func_tp_params(self, pool: memhub.MemBuddy*,
|
||
key: str) -> list[str]*:
|
||
"""查找泛型函数模板的类型参数名列表,未找到返回 None
|
||
|
||
从注册时深拷贝的 stdlib 缓冲区重建当前 pool 的 list[str](特化期间
|
||
pool 有效)。逐字节解析逻辑与 _find_generic_template_tp_params 一致:
|
||
空格分隔;elem_size 必须传 8(str 指针 8 字节)。
|
||
"""
|
||
if self.GenericFuncKeys is None or key is None \
|
||
or self.GenericFuncTpParams is None:
|
||
return None
|
||
keys_local: list[str]* = self.GenericFuncKeys
|
||
kn: sizet = len(keys_local)
|
||
i: sizet
|
||
for i in range(kn):
|
||
knm: str = keys_local.get(i)
|
||
if knm is not None and string.strcmp(knm, key) == 0:
|
||
if i >= GENERIC_TEMPLATE_MAX:
|
||
return None
|
||
buf_addr: sizet = self.GenericFuncTpParams[i]
|
||
if buf_addr == 0:
|
||
return None
|
||
buf_tp: str = rawptr(buf_addr)
|
||
tp_list: list[str]* = list[str](pool, 8)
|
||
if tp_list is None:
|
||
return None
|
||
seg_start: sizet = 0
|
||
pos: sizet = 0
|
||
blen: sizet = string.strlen(buf_tp)
|
||
while pos <= blen:
|
||
if buf_tp[pos] == ' ' or buf_tp[pos] == '\0':
|
||
seg_len: sizet = pos - seg_start
|
||
if seg_len > 0:
|
||
seg: str = pool.alloc(seg_len + 1)
|
||
if seg is not None:
|
||
string.strncpy(seg, buf_tp + seg_start, seg_len)
|
||
seg[seg_len] = '\0'
|
||
tp_list.append(seg)
|
||
seg_start = pos + 1
|
||
pos += 1
|
||
return tp_list
|
||
return None
|
||
|
||
def _find_generic_func_param_slot(self, fd: ast.FunctionDef*,
|
||
tp_name: str) -> int:
|
||
"""函数模板形参列表中注解恰为类型形参 tp_name 的形参槽位(0 起)
|
||
|
||
module 级函数无 self,槽位即位置实参下标;找不到返回 -1。判据复用
|
||
CallGenCtor._annotation_refers_type_param(只认 T 与 T|X,不认 Subscript
|
||
—— 实参是容器而非 T 本身,不能作为 T 的推断来源)。
|
||
"""
|
||
if fd is None or tp_name is None or fd.args is None: return -1
|
||
if fd.args.kind() != ast.ASTKind.Arguments: return -1
|
||
ags: ast.Arguments* = ast.Arguments*(fd.args)
|
||
if ags.args is None: return -1
|
||
alist: list[ast.AST*]* = ags.args
|
||
an: sizet = len(alist)
|
||
ai: sizet
|
||
for ai in range(an):
|
||
pa: ast.AST* = alist.get(ai)
|
||
if pa is None or pa.kind() != ast.ASTKind.Arg: continue
|
||
ag: ast.Arg* = ast.Arg*(pa)
|
||
if self.Gen.CallGenCtor._annotation_refers_type_param(ag.annotation, tp_name) != 0:
|
||
return int(ai)
|
||
return -1
|
||
|
||
def _infer_generic_func_type_arg(self, pool: memhub.MemBuddy*,
|
||
arg_node: ast.AST*,
|
||
func_name: str,
|
||
trans: HT.Translator*) -> str:
|
||
"""从调用实参 AST 推断泛型函数的类型实参名(不发射 IR,非 fatal)
|
||
|
||
与 CallGenCtor._infer_generic_ctor_type_arg 同源,但函数调用实参可以是
|
||
任意表达式(普通函数调用/c.Addr 等):推断不出返回 None,由调用方汇总
|
||
全部来源后统一 fail-fast(不在此 fail-fast,避免"某一实参推不出"就误杀
|
||
本来可由其它来源确定的类型形参)。
|
||
"""
|
||
if arg_node is None: return None
|
||
k: int = arg_node.kind()
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(arg_node)
|
||
if cn.const_kind == ast.CONST_FLOAT: return "double"
|
||
if cn.const_kind == ast.CONST_CHAR: return "char"
|
||
if cn.const_kind == ast.CONST_STR: return "str"
|
||
return "int"
|
||
# 一元正负号常量(clamp(-3, ...)):类型由操作数决定
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uo: ast.UnaryOp* = ast.UnaryOp*(arg_node)
|
||
return self._infer_generic_func_type_arg(pool, uo.operand, func_name, trans)
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(arg_node)
|
||
if nm.id is not None and trans is not None:
|
||
ve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
|
||
if ve is not None:
|
||
cn_nm: str = self.Gen.VarGen.var_annot_class_name(ve)
|
||
pl: int = 0
|
||
if ve.Spec is not None:
|
||
pl = ve.Spec.PtrLevel
|
||
if cn_nm is not None:
|
||
return self.Gen.CallGenCtor._ptr_layer_type_arg(pool, cn_nm, pl, trans._from_imports)
|
||
# 内建标量(str/char/bytes/bool/float/double 被
|
||
# extract_class_name_from_annotation 跳过 ⇒ SourceName 为 None):
|
||
# 从 Spec 的 LLVM 形态反推可解析的类型名(double/float/int/char/bool)。
|
||
return self._infer_scalar_type_name_from_spec(pool, ve.Spec)
|
||
return None
|
||
if k == ast.ASTKind.Attribute:
|
||
cn_at: str = self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, arg_node)
|
||
pl_at: int = 0
|
||
fe: GenTypes.FieldEntry* = self.Gen.ExprGenAttr._resolve_attr_field_entry(pool, trans, arg_node)
|
||
if fe is not None and fe.Spec is not None:
|
||
pl_at = fe.Spec.PtrLevel
|
||
fi: str = None
|
||
if trans is not None:
|
||
fi = trans._from_imports
|
||
if cn_at is not None:
|
||
return self.Gen.CallGenCtor._ptr_layer_type_arg(pool, cn_at, pl_at, fi)
|
||
# 内建标量字段:同 Name 分支的 Spec 反推
|
||
if fe is not None:
|
||
return self._infer_scalar_type_name_from_spec(pool, fe.Spec)
|
||
return None
|
||
if k == ast.ASTKind.Call:
|
||
cl_f: ast.Call* = ast.Call*(arg_node)
|
||
if cl_f.func is not None:
|
||
fk_f: int = cl_f.func.kind()
|
||
# 只认「被调名本身可解析为**标量类型**」的转换调用(int(x) /
|
||
# t.CDouble(x) / CUInt64T(x) 等):用注解解析器解析被调表达式,
|
||
# 命中标量即按**精确位宽**映射(复用 _infer_scalar_type_name_from_spec
|
||
# 这一唯一真源);非标量(构造调用/普通函数调用)或不可解析一律
|
||
# None,交由调用方汇总后 fail-fast。
|
||
# 彻底移除原来的**名字子串猜测**(含 "Int" → int 等):它把
|
||
# CUInt64T/CInt16T 一律归成 int=i32,静默窄化/扩宽位宽
|
||
# (现场:GenericOopTest `fxi2(a, b, CUInt64T(178900))` 的 T3=u64
|
||
# 被猜成 i32)。此处不做兜底猜测,宁缺毋错。
|
||
if (fk_f == ast.ASTKind.Name or fk_f == ast.ASTKind.Attribute) and trans is not None:
|
||
cty_f: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||
pool, cl_f.func, trans._imported_modules, trans._from_imports, trans, 0)
|
||
if cty_f is not None:
|
||
return self.infer_scalar_type_arg_from_llvm_ty(pool, cty_f)
|
||
return None
|
||
return None
|
||
|
||
def _infer_scalar_type_name_from_spec(self, pool: memhub.MemBuddy*,
|
||
sp: TSpec.TypeSpec*) -> str:
|
||
"""从变量的 TypeSpec 反推可解析的内建标量类型名
|
||
|
||
仅覆盖 extract_class_name_from_annotation 会跳过的内建标量
|
||
(str/char/bytes/bool/float/double 的 SourceName 为 None):按 LLVM
|
||
形态映射为源码可解析名(double/float/int/char/bool)。指针/结构体返回
|
||
None(交由注解来源名路径处理;此处不做猜测,避免错特化)。
|
||
|
||
**只映射"位宽精确对应到某个裸名"的形态**(i1→bool、i8→char、i32→int、
|
||
f32→float、f64→double)。i16/i64/f16 在 Viper 没有等位宽的裸名别名
|
||
(裸 int=int32、裸 float=float32),映射过去会静默窄化/扩宽位宽
|
||
(i64→int 即 i64→i32,直接改变 ABI 与数据),违反"禁止静默默认/兜底"
|
||
原则 ⇒ 一律返回 None,由调用方汇总后 fail-fast 提示显式标注。
|
||
"""
|
||
if pool is None or sp is None: return None
|
||
buf: str = pool.alloc(32)
|
||
if buf is None: return None
|
||
buf[0] = '\0'
|
||
# SpecToLLVMText 约定 0=成功 / 1=失败(见 TypeSpec.vp 定义与 ClassGenVTable
|
||
# 的 `!= 0` 用法):原判据写成 `== 0` 恰好把"成功"当失败返回 None,导致本
|
||
# 函数对任何内建标量都恒返回 None —— 泛型函数隐式推断里"实参是内建标量的
|
||
# 形参"(如 fxi 体内 fxi2(a, ...),a: double)永远推不出,报
|
||
# "无法从实参推断泛型函数 ... 禁止静默默认 int"。
|
||
if TSpec.SpecToLLVMText(sp, buf, 32) != 0:
|
||
return None
|
||
if string.strcmp(buf, "double") == 0: return "double"
|
||
if string.strcmp(buf, "float") == 0: return "float"
|
||
if string.strcmp(buf, "i1") == 0: return "bool"
|
||
if string.strcmp(buf, "i8") == 0: return "char"
|
||
if string.strcmp(buf, "i32") == 0: return "int"
|
||
return None
|
||
|
||
def infer_scalar_type_arg_from_llvm_ty(self, pool: memhub.MemBuddy*,
|
||
ty: llvmlite.LLVMType*) -> str:
|
||
"""LLVM **标量**类型 → 泛型类型实参票名(精确位宽;非标量返回 None)
|
||
|
||
泛型函数(ClassGenGeneric._infer_generic_func_type_arg)与泛型类构造
|
||
(CallGenCtor._infer_generic_ctor_type_arg)的 Call 实参推断共用,保证
|
||
"转换调用实参 → 类型实参" 两处同口径(唯一真源
|
||
_infer_scalar_type_name_from_spec)。非标量(结构体/指针/数组/函数)返回
|
||
None ⇒ 调用方不据此推断(宁缺毋错,不按名字子串猜)。
|
||
"""
|
||
if pool is None or ty is None:
|
||
return None
|
||
arena: TSpec.TypeSpecArena* = self.Gen.TypeGenBase.ensure_spec_arena()
|
||
if arena is None:
|
||
return None
|
||
return self._infer_scalar_type_name_from_spec(pool, TSpec.SpecFromLLVMType(arena, ty))
|
||
|
||
def _clone_funcdef_for_spec(self, pool: memhub.MemBuddy*,
|
||
fd: ast.FunctionDef*,
|
||
spec_base: str,
|
||
tp_names: list[str]*,
|
||
type_args: list[str]*) -> ast.FunctionDef*:
|
||
"""拷贝 FunctionDef 用于泛型函数特化
|
||
|
||
- 函数名替换为 spec_base(如 "f[int,double]")
|
||
- type_params 清空(特化后非泛型,避免 translate_function_def 再入模板分支)
|
||
- 形参/返回注解经 _clone_annotation 替换 T 为具体类型
|
||
- 函数体直接引用原始节点(T 在体内的用法由 generic_context 处理,与
|
||
_clone_classdef_for_spec 对方法体的处理同口径)
|
||
"""
|
||
if fd is None: return None
|
||
new_args: ast.AST* = self._clone_arguments(pool, fd.args, tp_names, type_args)
|
||
new_returns: ast.AST* = self._clone_annotation(pool, fd.returns, tp_names, type_args)
|
||
new_fd: ast.FunctionDef* = ast.FunctionDef(pool, spec_base, new_args,
|
||
fd.decorator_list, new_returns, 0)
|
||
if fd.children is not None:
|
||
body: list[ast.AST*]* = fd.children
|
||
bn: sizet = len(body)
|
||
bi: sizet
|
||
for bi in range(bn):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
new_fd.append(stmt)
|
||
return new_fd
|
||
|
||
def _ensure_generic_func_declare(self, trans: HT.Translator*,
|
||
pool: memhub.MemBuddy*,
|
||
spec_name: str,
|
||
template_key: str,
|
||
tp_names: list[str]*,
|
||
type_args: list[str]*) -> llvmlite.Function*:
|
||
"""确保当前模块存在特化函数的 declare(跨模块缓存命中时用)
|
||
|
||
特化 define 全局只发射一份(SpecKeys 去重);命中缓存的调用方模块里没有
|
||
该符号的 LLVM 声明,按"模板签名 + 实参"在本模块补一条 declare。返回该
|
||
declare;失败返回 None。
|
||
"""
|
||
if trans is None or pool is None or spec_name is None: return None
|
||
mod: llvmlite.LLVMModule* = trans.Module
|
||
if mod is None: return None
|
||
existing: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, spec_name)
|
||
if existing is not None: return existing
|
||
template_fd: ast.FunctionDef* = self._find_generic_func_template(template_key)
|
||
if template_fd is None: return None
|
||
template_sha1: str = self._find_generic_func_template_sha1(template_key)
|
||
if template_sha1 is None: return None
|
||
spec_base: str = self._mangle_generic_class_name(pool, template_fd.name, type_args, trans._from_imports)
|
||
if spec_base is None: return None
|
||
spec_fd: ast.FunctionDef* = self._clone_funcdef_for_spec(pool, template_fd, spec_base, tp_names, type_args)
|
||
if spec_fd is None: return None
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
saved_ms: str = trans.ModuleSha1
|
||
saved_imp: str = trans._imported_modules
|
||
saved_gtpn: list[str]* = trans.GenericTypeParamNames
|
||
saved_gta: list[str]* = trans.GenericTypeArgs
|
||
trans.ModuleSha1 = template_sha1
|
||
self._merge_template_imports(trans, template_sha1)
|
||
trans.GenericTypeParamNames = tp_names
|
||
trans.GenericTypeArgs = type_args
|
||
self.Gen.TypeGenBase.set_generic_context(tp_names, type_args)
|
||
saved_cur: str = self.Gen.TypeGenResolve.get_current_file()
|
||
tpl_file: str = self._find_generic_func_template_file(template_key)
|
||
if tpl_file is not None:
|
||
self.Gen.TypeGenResolve.set_current_file(tpl_file)
|
||
ret_ty: llvmlite.LLVMType* = None
|
||
if spec_fd.returns is not None:
|
||
ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, spec_fd.returns, trans._imported_modules, trans._from_imports, trans, 0)
|
||
if ret_ty is None:
|
||
ret_ty = i32_ty
|
||
func: llvmlite.Function* = llvmlite.create_declare(pool, mod, spec_name, ret_ty)
|
||
if func is not None and spec_fd.args is not None and spec_fd.args.kind() == ast.ASTKind.Arguments:
|
||
ags: ast.Arguments* = ast.Arguments*(spec_fd.args)
|
||
if ags.args is not None:
|
||
alist: list[ast.AST*]* = ags.args
|
||
an: sizet = len(alist)
|
||
ai: sizet
|
||
for ai in range(an):
|
||
pa: ast.AST* = alist.get(ai)
|
||
if pa is None or pa.kind() != ast.ASTKind.Arg: continue
|
||
arg: ast.Arg* = ast.Arg*(pa)
|
||
if arg.arg is None: continue
|
||
param_ty: llvmlite.LLVMType* = i32_ty
|
||
if arg.annotation is not None:
|
||
resolved: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||
if resolved is not None:
|
||
match resolved:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
param_ty = llvmlite.Ptr(pool, resolved)
|
||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||
case _:
|
||
param_ty = resolved
|
||
pname: str = pool.alloc(32)
|
||
if pname is not None:
|
||
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
|
||
llvmlite.add_param(pool, func, param_ty, pname)
|
||
if tpl_file is not None:
|
||
self.Gen.TypeGenResolve.set_current_file(saved_cur)
|
||
trans.ModuleSha1 = saved_ms
|
||
trans._imported_modules = saved_imp
|
||
trans.GenericTypeParamNames = saved_gtpn
|
||
trans.GenericTypeArgs = saved_gta
|
||
self.Gen.TypeGenBase.clear_generic_context()
|
||
return func
|
||
|
||
def _specialize_generic_function(self, trans: HT.Translator*,
|
||
template_key: str,
|
||
type_args: list[str]*) -> str:
|
||
"""特化泛型函数,返回特化函数 mangled 名("{模板sha1}.{f}[args]")
|
||
|
||
1. 查找模板;2. 逐实参规范化生成特化名;3. SpecKeys 去重
|
||
(命中且本模块无该符号 → 补 declare);4. 克隆模板 + generic_context
|
||
翻译发射 define(translate_function_def),命名/签名与调用点一致。
|
||
"""
|
||
if trans is None or template_key is None or type_args is None:
|
||
return None
|
||
self.GenericSpecDepth += 1
|
||
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH:
|
||
self.Gen.TypeGenErr.fatal_error(None, "泛型函数特化递归过深(疑似泛型循环套用)", "InternalCompilerError")
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
template_fd: ast.FunctionDef* = self._find_generic_func_template(template_key)
|
||
if template_fd is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
template_sha1: str = self._find_generic_func_template_sha1(template_key)
|
||
if template_sha1 is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
# 防御:泛型上下文内收集的实参若残留未替换的类型形参名(如 "T"),
|
||
# 统一替换为具体类型名(嵌套特化:泛型函数体内再调泛型函数)。
|
||
ta_cnt_g: sizet = len(type_args)
|
||
ta_i_g: sizet
|
||
for ta_i_g in range(ta_cnt_g):
|
||
ta_raw_g: str = type_args.get(ta_i_g)
|
||
if ta_raw_g is not None:
|
||
ta_rsv_g: str = self.Gen.TypeGenBase.resolve_generic_type_name(ta_raw_g)
|
||
if ta_rsv_g is not None and string.strcmp(ta_raw_g, ta_rsv_g) != 0:
|
||
type_args.set(ta_i_g, ta_rsv_g)
|
||
tp_names: list[str]* = self._find_generic_func_tp_params(pool, template_key)
|
||
if tp_names is None:
|
||
tp_names = template_fd.type_params
|
||
if tp_names is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
if len(tp_names) != len(type_args):
|
||
err_tp: str = pool.alloc(256)
|
||
if err_tp is not None:
|
||
viperlib.snprintf(err_tp, 256,
|
||
"泛型函数 '%s' 类型实参个数不匹配(需要 %d,给定 %d)",
|
||
template_fd.name, len(tp_names), len(type_args))
|
||
self.Gen.TypeGenErr.fatal_error(None, err_tp, "TypeError")
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
# CExport/CExtern/State 存储标记的泛型函数不支持(特化名会绕过裸名导出语义)
|
||
if template_fd.returns is not None:
|
||
if self.Gen.TypeGenErr.has_decorator_marker(template_fd.returns, "CExport", 0) != 0 \
|
||
or self.Gen.TypeGenErr.has_decorator_marker(template_fd.returns, "CExtern", 0) != 0 \
|
||
or self.Gen.TypeGenErr.has_decorator_marker(template_fd.returns, "State", 0) != 0:
|
||
self.Gen.TypeGenErr.fatal_error(template_fd, "泛型函数暂不支持 t.CExport/t.CExtern/t.State 存储标记", "TypeError")
|
||
# 生成特化名(唯一生成器内部逐实参规范化,裸名/带前缀在此收敛为同一名)
|
||
spec_base: str = self._mangle_generic_class_name(pool, template_fd.name, type_args, trans._from_imports)
|
||
if spec_base is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
spec_name: str = self.Gen.FuncGenBase._mangle_name_with_sha1(template_sha1, spec_base)
|
||
# spec_key 用「模板键 + 归一化后的特化基名」构造:与 spec_name 一一对应
|
||
# (都用 spec_base),避免原始实参书写差异(裸名/带前缀)导致同一特化名
|
||
# 算出两个缓存键 → 重复发射同名 define。含模板键(带 SHA1)故与泛型类
|
||
# 缓存键(裸类名<...>)不冲突。
|
||
spec_key: str = pool.alloc(string.strlen(template_key) + string.strlen(spec_base) + 2)
|
||
if spec_key is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
spec_key[0] = '\0'
|
||
string.strcat(spec_key, template_key)
|
||
string.strcat(spec_key, "#")
|
||
string.strcat(spec_key, spec_base)
|
||
cached: str = self._find_cached_spec(spec_key)
|
||
if cached is not None:
|
||
self._ensure_generic_func_declare(trans, pool, spec_name, template_key, tp_names, type_args)
|
||
self.GenericSpecDepth -= 1
|
||
return cached
|
||
# 本模块已存在同名 define(多遍重译/同 pass 重复):直接复用,禁止再克隆
|
||
# 发射(translate_function_def 对已 define 的同名会新建 → 模块内重复符号)。
|
||
# 仅 declare(跨模块补的声明)时继续走发射路径(translate_function_def 会
|
||
# 复用该 declare 并补函数体转 define)。
|
||
existing_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(trans.Module, spec_name)
|
||
if existing_fn is not None and existing_fn.IsDeclared == 0:
|
||
self._cache_spec(pool, spec_key, spec_name)
|
||
self.GenericSpecDepth -= 1
|
||
return spec_name
|
||
# 克隆 + 上下文翻译发射 define
|
||
spec_fd: ast.FunctionDef* = self._clone_funcdef_for_spec(pool, template_fd, spec_base, tp_names, type_args)
|
||
if spec_fd is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
# 预注册缓存(防止递归特化)
|
||
self._cache_spec(pool, spec_key, spec_name)
|
||
saved_ms: str = trans.ModuleSha1
|
||
saved_imp: str = trans._imported_modules
|
||
saved_gtpn: list[str]* = trans.GenericTypeParamNames
|
||
saved_gta: list[str]* = trans.GenericTypeArgs
|
||
# 类定义窗口必须与 ModuleSha1 一起保存/恢复(特化翻译内部会按模板模块
|
||
# sha1 + 特化名刷新窗口,见 _specialize_generic_class 的"窗口同进同出")
|
||
saved_def_mod: str = self.Gen.StructGen.CurDefModuleSha1
|
||
saved_def_cls: str = self.Gen.StructGen.CurDefClassName
|
||
# 切换 ModuleSha1 为模板定义模块的 SHA1:特化函数符号名 = {模板SHA1}.f[args],
|
||
# 跨模块一致;同时并入模板模块 imports(模板体内跨模块调用可见)。
|
||
trans.ModuleSha1 = template_sha1
|
||
self._merge_template_imports(trans, template_sha1)
|
||
trans.GenericTypeParamNames = tp_names
|
||
trans.GenericTypeArgs = type_args
|
||
self.Gen.TypeGenBase.set_generic_context(tp_names, type_args)
|
||
# 错误定位:特化体 node.lineno 是模板文件行号,临时切换 CurrentFile 到
|
||
# 模板文件并压 trace 帧(翻译完恢复)。
|
||
saved_cur: str = self.Gen.TypeGenResolve.get_current_file()
|
||
tpl_file: str = self._find_generic_func_template_file(template_key)
|
||
if tpl_file is not None:
|
||
self.Gen.TypeGenResolve.set_current_file(tpl_file)
|
||
self.Gen.TypeGenBase.push_trace(tpl_file, template_fd.lineno)
|
||
self.Gen.FuncGenDef.translate_function_def(trans, spec_fd)
|
||
if tpl_file is not None:
|
||
self.Gen.TypeGenBase.pop_trace()
|
||
self.Gen.TypeGenResolve.set_current_file(saved_cur)
|
||
trans.ModuleSha1 = saved_ms
|
||
trans._imported_modules = saved_imp
|
||
self.Gen.StructGen.CurDefModuleSha1 = saved_def_mod
|
||
self.Gen.StructGen.CurDefClassName = saved_def_cls
|
||
trans.GenericTypeParamNames = saved_gtpn
|
||
trans.GenericTypeArgs = saved_gta
|
||
self.Gen.TypeGenBase.clear_generic_context()
|
||
self.GenericSpecDepth -= 1
|
||
return spec_name
|
||
|
||
def _find_generic_template_tp_params(self, pool: memhub.MemBuddy*,
|
||
class_name: str) -> list[str]*:
|
||
"""查找泛型类模板的类型参数名列表,未找到返回 None
|
||
|
||
从注册时深拷贝的 stdlib 缓冲区重建当前 pool 的 list[str]
|
||
(特化期间 pool 有效,方法与体翻译共用)。与 GenericClassNames 同序。
|
||
"""
|
||
if self.GenericClassNames is None or class_name is None \
|
||
or self.GenericClassTpParams is None:
|
||
return None
|
||
names_local: list[str]* = self.GenericClassNames
|
||
cn: sizet = len(names_local)
|
||
i: sizet
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||
if i >= GENERIC_TEMPLATE_MAX:
|
||
return None
|
||
buf_addr: sizet = self.GenericClassTpParams[i]
|
||
if buf_addr == 0:
|
||
return None
|
||
buf_tp: str = rawptr(buf_addr)
|
||
# 空格分隔 → list[str]
|
||
# 注意:list[str](pool, 8) 第二个参数是 elem_size(指针 8 字节),
|
||
# 不是容量!传 4 会导致 get(i) 偏移算错、append 相互覆盖
|
||
# (Pair[T1,T2] 的 seg1 写 data+4 覆盖 seg0 高 4 字节 → strcmp
|
||
# 收到 0x15B78D5015B78CB0 混合垃圾崩溃,GenericTest 回归根因)
|
||
tp_list: list[str]* = list[str](pool, 8)
|
||
if tp_list is None:
|
||
return None
|
||
seg_start: sizet = 0
|
||
pos: sizet = 0
|
||
blen: sizet = string.strlen(buf_tp)
|
||
while pos <= blen:
|
||
if buf_tp[pos] == ' ' or buf_tp[pos] == '\0':
|
||
seg_len: sizet = pos - seg_start
|
||
if seg_len > 0:
|
||
seg: str = pool.alloc(seg_len + 1)
|
||
if seg is not None:
|
||
string.strncpy(seg, buf_tp + seg_start, seg_len)
|
||
seg[seg_len] = '\0'
|
||
tp_list.append(seg)
|
||
seg_start = pos + 1
|
||
pos += 1
|
||
return tp_list
|
||
return None
|
||
def _find_generic_template(self, class_name: str) -> ast.ClassDef*:
|
||
"""查找泛型类模板,返回 ClassDef 节点或 None"""
|
||
if self.GenericClassNames is None or class_name is None:
|
||
return None
|
||
# 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败)
|
||
names_local: list[str]* = self.GenericClassNames
|
||
nodes_local: list[ast.ClassDef*] | t.CPtr = self.GenericClassNodes
|
||
cn: sizet = len(names_local)
|
||
i: sizet
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||
node: ast.ClassDef* = nodes_local.get(i)
|
||
return node
|
||
return None
|
||
def _find_generic_template_sha1(self, class_name: str) -> str:
|
||
"""查找泛型类模板的来源模块 SHA1,未找到返回 None"""
|
||
if self.GenericClassNames is None or class_name is None:
|
||
return None
|
||
# 用局部变量接收 list,触发类型推断
|
||
names_local: list[str]* = self.GenericClassNames
|
||
sha1s_local: list[str]* = self.GenericClassSha1s
|
||
cn: sizet = len(names_local)
|
||
i: sizet
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||
sha1_val: str = sha1s_local.get(i)
|
||
return sha1_val
|
||
return None
|
||
def _find_generic_template_file(self, class_name: str) -> str:
|
||
"""查找泛型类模板的来源文件路径,未找到返回 None
|
||
|
||
与 _find_generic_template_sha1 同表同序;供特化翻译模板方法体时
|
||
临时切换 CurrentFile(错误定位:模板 node.lineno 需配模板文件路径)。
|
||
"""
|
||
if self.GenericClassNames is None or class_name is None:
|
||
return None
|
||
names_local: list[str]* = self.GenericClassNames
|
||
files_local: list[str]* = self.GenericClassFiles
|
||
cn: sizet = len(names_local)
|
||
i: sizet
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||
f_val: str = files_local.get(i)
|
||
return f_val
|
||
return None
|
||
def _mangle_generic_class_name(self, pool: memhub.MemBuddy*,
|
||
class_name: str,
|
||
type_args: list[str]*,
|
||
from_imports: str = None) -> str:
|
||
"""生成特化类名: list + [int] -> list[int]
|
||
|
||
**唯一生成器 + 唯一规范化点**:所有特化名(结构体注册名、方法符号里的
|
||
后缀段、查找键)都由这里产出,故类型实参的 SHA1 规范化只在这里做一次 ——
|
||
每个实参经 `TypeGenResolve._norm_type_arg_name` 归一到
|
||
`{定义模块SHA1}.{Class}`(该函数对已规范化的串**幂等**:规则 2/3/6 原样
|
||
返回,嵌套 `rawptr[X]` 也递归同形)⇒ 无论调用方(注解侧 / 构造侧 /
|
||
基类侧 / 字面量推断侧)传进来的实参是裸名还是已带前缀,注册名与查找名
|
||
**必然同形**。此前裸露名与已带前缀的两侧会分裂成两个特化结构体,已出现
|
||
三种现场:形参侧/实参侧(stmts.vp:60)、字段侧/构造侧(base.vp:357)、
|
||
基类侧/注解侧(ClassGenBase._get_base_name 的裸 Name.id)。
|
||
|
||
分配新缓冲区拼接,避免原地 strcat 导致缓冲区溢出
|
||
"""
|
||
if class_name is None or type_args is None or pool is None:
|
||
return class_name
|
||
n: sizet = len(type_args)
|
||
if n == 0:
|
||
return class_name
|
||
# 逐实参规范化(幂等):先归一成新列表,长度计算与拼接都用归一后的串
|
||
norm_args: list[str]* = list[str](pool, 8)
|
||
if norm_args is None:
|
||
return class_name
|
||
i: sizet
|
||
for i in range(n):
|
||
ta_raw: str = type_args.get(i)
|
||
if ta_raw is None:
|
||
continue
|
||
ta_norm: str = self.Gen.TypeGenResolve._norm_type_arg_name(pool, ta_raw, from_imports)
|
||
if ta_norm is None:
|
||
ta_norm = ta_raw
|
||
norm_args.append(ta_norm)
|
||
n = len(norm_args)
|
||
if n == 0:
|
||
return class_name
|
||
# 计算总长度: class_name + "[" + arg0 + "," + arg1 + ... + "]" + NUL
|
||
total_len: sizet = string.strlen(class_name) + 2 # "[" 和 "]"
|
||
for i in range(n):
|
||
if i > 0:
|
||
total_len += 1 # ","
|
||
ta: str = norm_args.get(i)
|
||
if ta is not None:
|
||
total_len += string.strlen(ta)
|
||
total_len += 1 # NUL
|
||
# 分配新缓冲区
|
||
mangled: str = pool.alloc(total_len)
|
||
if mangled is None:
|
||
return class_name
|
||
mangled[0] = '\0'
|
||
string.strcat(mangled, class_name)
|
||
string.strcat(mangled, "[")
|
||
for i in range(n):
|
||
if i > 0:
|
||
string.strcat(mangled, ",")
|
||
ta: str = norm_args.get(i)
|
||
if ta is not None:
|
||
string.strcat(mangled, ta)
|
||
string.strcat(mangled, "]")
|
||
return mangled
|
||
def _clone_annotation(self, pool: memhub.MemBuddy*,
|
||
node: ast.AST*,
|
||
tp_names: list[str]*,
|
||
type_args: list[str]*) -> ast.AST*:
|
||
"""拷贝类型注解表达式,替换类型参数 T 为具体类型名
|
||
|
||
tp_names: 类型参数名列表 ['T']
|
||
type_args: 类型实参名列表 ['int']
|
||
"""
|
||
if node is None:
|
||
return None
|
||
k: int = node.kind()
|
||
|
||
# Name: 可能是类型参数 T
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(node)
|
||
if nm.id is not None:
|
||
n: sizet = len(tp_names) if tp_names is not None else 0
|
||
i: sizet
|
||
for i in range(n):
|
||
tpn: str = tp_names.get(i)
|
||
if tpn is not None and string.strcmp(nm.id, tpn) == 0:
|
||
ta: str = type_args.get(i)
|
||
# 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string 解析
|
||
parsed_node: ast.AST* = self.Gen.TypeGenResolve._parse_type_string(pool, ta, nm.ctx)
|
||
return parsed_node
|
||
return ast.Name(pool, nm.id, nm.ctx)
|
||
return None
|
||
|
||
# Attribute: t.CPtr 等
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(node)
|
||
new_value: ast.AST* = self._clone_annotation(pool, at.value, tp_names, type_args)
|
||
return ast.Attribute(pool, new_value, at.attr, at.ctx)
|
||
|
||
# BinOp: T | t.CPtr 等
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp* = ast.BinOp*(node)
|
||
new_left: ast.AST* = self._clone_annotation(pool, bop.left, tp_names, type_args)
|
||
new_right: ast.AST* = self._clone_annotation(pool, bop.right, tp_names, type_args)
|
||
return ast.BinOp(pool, new_left, bop.op, new_right)
|
||
|
||
# Subscript: list[int] 等
|
||
if k == ast.ASTKind.Subscript:
|
||
sub: ast.Subscript* = ast.Subscript*(node)
|
||
new_value2: ast.AST* = self._clone_annotation(pool, sub.value, tp_names, type_args)
|
||
new_slice: ast.AST* = self._clone_annotation(pool, sub.slice, tp_names, type_args)
|
||
return ast.Subscript(pool, new_value2, new_slice, sub.ctx)
|
||
|
||
# Tuple: (T, int) 等
|
||
if k == ast.ASTKind.Tuple:
|
||
tup: ast.Tuple* = ast.Tuple*(node)
|
||
new_elts: list[ast.AST*]* = list[ast.AST*](pool, 8)
|
||
if tup.elts is not None:
|
||
tup_elts: list[ast.AST*]* = tup.elts
|
||
en: sizet = len(tup_elts)
|
||
ei: sizet
|
||
for ei in range(en):
|
||
el: ast.AST* = tup_elts.get(ei)
|
||
new_el: ast.AST* = self._clone_annotation(pool, el, tp_names, type_args)
|
||
if new_el is not None:
|
||
new_elts.append(new_el)
|
||
return ast.Tuple(pool, new_elts, tup.ctx)
|
||
|
||
# Constant: 默认值等
|
||
if k == ast.ASTKind.Constant:
|
||
cnst: ast.Constant* = ast.Constant*(node)
|
||
return ast.Constant(pool, cnst.const_kind, cnst.int_val, cnst.float_val,
|
||
cnst.str_val, cnst.lineno, cnst.col_offset)
|
||
|
||
# 其他: 直接引用(不拷贝)
|
||
return node
|
||
def _clone_arguments(self, pool: memhub.MemBuddy*,
|
||
args: ast.AST*,
|
||
tp_names: list[str]*,
|
||
type_args: list[str]*) -> ast.AST*:
|
||
"""拷贝 Arguments 节点,替换 arg annotation 中的 T"""
|
||
if args is None:
|
||
return None
|
||
if args.kind() != ast.ASTKind.Arguments:
|
||
return args
|
||
old_args: ast.Arguments* = ast.Arguments*(args)
|
||
# 拷贝 args 列表,替换每个 Arg 的 annotation
|
||
new_arg_list: list[ast.AST*]* = list[ast.AST*](pool, 8)
|
||
if old_args.args is not None:
|
||
old_arg_list: list[ast.AST*]* = old_args.args
|
||
an: sizet = len(old_arg_list)
|
||
ai: sizet
|
||
for ai in range(an):
|
||
arg_node: ast.AST* = old_arg_list.get(ai)
|
||
if arg_node is None:
|
||
continue
|
||
if arg_node.kind() == ast.ASTKind.Arg:
|
||
ag: ast.Arg* = ast.Arg*(arg_node)
|
||
new_anno: ast.AST* = self._clone_annotation(pool, ag.annotation, tp_names, type_args)
|
||
new_arg: ast.Arg* = ast.Arg(pool, ag.arg, new_anno)
|
||
new_arg_list.append(new_arg)
|
||
else:
|
||
new_arg_list.append(arg_node)
|
||
return ast.Arguments(pool, new_arg_list, old_args.vararg, old_args.kwarg,
|
||
old_args.defaults, old_args.kw_defaults)
|
||
def _clone_classdef_for_spec(self, pool: memhub.MemBuddy*,
|
||
cd: ast.ClassDef*,
|
||
spec_name: str,
|
||
tp_names: list[str]*,
|
||
type_args: list[str]*) -> ast.ClassDef*:
|
||
"""拷贝 ClassDef 节点用于泛型特化
|
||
|
||
- 替换类名为 spec_name
|
||
- 清除 type_params(特化后不是泛型类)
|
||
- 拷贝 children 中的 AnnAssign 和 FunctionDef,替换类型注解中的 T
|
||
- 方法体直接引用原始节点(通过 type_map 上下文处理 T)
|
||
"""
|
||
# 创建新 ClassDef(type_params=None 表示非泛型)
|
||
new_cd: ast.ClassDef* = ast.ClassDef(pool, spec_name, cd.bases, cd.keywords,
|
||
cd.decorator_list, None)
|
||
# 拷贝 children
|
||
if cd.children is not None:
|
||
cd_children: list[ast.AST*]* = cd.children
|
||
cn: sizet = len(cd_children)
|
||
ci: sizet
|
||
for ci in range(cn):
|
||
child: ast.AST* = cd_children.get(ci)
|
||
if child is None:
|
||
continue
|
||
ck: int = child.kind()
|
||
|
||
if ck == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign* = ast.AnnAssign*(child)
|
||
new_target: ast.AST* = aa.target
|
||
new_anno2: ast.AST* = self._clone_annotation(pool, aa.annotation, tp_names, type_args)
|
||
new_value3: ast.AST* = aa.value
|
||
new_aa: ast.AnnAssign* = ast.AnnAssign(pool, new_target, new_anno2, new_value3, aa.simple)
|
||
new_cd.append(new_aa)
|
||
|
||
elif ck == ast.ASTKind.FunctionDef:
|
||
fd: ast.FunctionDef* = ast.FunctionDef*(child)
|
||
new_args2: ast.AST* = self._clone_arguments(pool, fd.args, tp_names, type_args)
|
||
new_returns2: ast.AST* = self._clone_annotation(pool, fd.returns, tp_names, type_args)
|
||
new_fd: ast.FunctionDef* = ast.FunctionDef(pool, fd.name, new_args2,
|
||
fd.decorator_list, new_returns2, 0)
|
||
# 方法体直接引用原始节点
|
||
if fd.children is not None:
|
||
fd_children: list[ast.AST*]* = fd.children
|
||
bcn: sizet = len(fd_children)
|
||
bci: sizet
|
||
for bci in range(bcn):
|
||
body_stmt: ast.AST* = fd_children.get(bci)
|
||
if body_stmt is not None:
|
||
new_fd.append(body_stmt)
|
||
new_cd.append(new_fd)
|
||
|
||
else:
|
||
new_cd.append(child)
|
||
|
||
return new_cd
|
||
def _find_cached_spec(self, spec_key: str) -> str:
|
||
"""查找已缓存的特化名,未找到返回 None"""
|
||
if self.SpecKeys is None or spec_key is None:
|
||
return None
|
||
i: int
|
||
for i in range(self.SpecCount):
|
||
key_addr: sizet = self.SpecKeys[i]
|
||
if key_addr != 0:
|
||
k: str = rawptr(key_addr)
|
||
if k is not None and string.strcmp(k, spec_key) == 0:
|
||
name_addr: sizet = self.SpecNames[i]
|
||
if name_addr != 0:
|
||
return rawptr(name_addr)
|
||
return None
|
||
def _cache_spec(self, pool: memhub.MemBuddy*, spec_key: str, spec_name: str):
|
||
"""缓存特化结果(stdlib 深拷贝存储,跨文件安全)"""
|
||
if spec_key is None or spec_name is None:
|
||
return
|
||
if self.SpecKeys is None:
|
||
self.SpecKeys = CompilerFactory.factory.PermPool.alloc(SPEC_CACHE_MAX * 8)
|
||
self.SpecNames = CompilerFactory.factory.PermPool.alloc(SPEC_CACHE_MAX * 8)
|
||
if self.SpecKeys is None or self.SpecNames is None:
|
||
return
|
||
string.memset(self.SpecKeys, 0, SPEC_CACHE_MAX * 8)
|
||
string.memset(self.SpecNames, 0, SPEC_CACHE_MAX * 8)
|
||
self.SpecCount = 0
|
||
if self.SpecCount >= SPEC_CACHE_MAX:
|
||
return
|
||
# 深拷贝字符串到 stdlib 区
|
||
key_len: sizet = string.strlen(spec_key)
|
||
name_len: sizet = string.strlen(spec_name)
|
||
key_copy: str = CompilerFactory.factory.PermPool.alloc(key_len + 1)
|
||
name_copy: str = CompilerFactory.factory.PermPool.alloc(name_len + 1)
|
||
if key_copy is None or name_copy is None:
|
||
return
|
||
string.strcpy(key_copy, spec_key)
|
||
string.strcpy(name_copy, spec_name)
|
||
self.SpecKeys[self.SpecCount] = sizet(key_copy)
|
||
self.SpecNames[self.SpecCount] = sizet(name_copy)
|
||
self.SpecCount += 1
|
||
def _merge_template_imports(self, trans: HT.Translator*,
|
||
template_sha1: str) -> None:
|
||
"""将模板模块的 imports 并入 trans._imported_modules(空格分隔)"""
|
||
if trans is None or template_sha1 is None:
|
||
return
|
||
tdeps: str = StubMergerStore.LookupIncludesDeps(template_sha1)
|
||
if tdeps is None or tdeps[0] == '\0':
|
||
return
|
||
cur: str = trans._imported_modules
|
||
if cur is None or cur[0] == '\0':
|
||
trans._imported_modules = tdeps
|
||
return
|
||
cur_len: sizet = string.strlen(cur)
|
||
td_len: sizet = string.strlen(tdeps)
|
||
merged: str = trans.Pool.alloc(cur_len + td_len + 2)
|
||
if merged is None:
|
||
return
|
||
string.strcpy(merged, cur)
|
||
merged[cur_len] = ' '
|
||
string.strcpy(merged + cur_len + 1, tdeps)
|
||
trans._imported_modules = merged
|
||
def _record_spec_trigger(self, pool: memhub.MemBuddy*,
|
||
spec_name: str, trigger_sha1: str) -> int:
|
||
"""记录泛型特化类的触发文件 sha1(StructEntry.SpecTriggerSha1)
|
||
|
||
特化类 ModuleSha1=模板 sha1(方法名带模板前缀),Phase A _deps_pending
|
||
作废重译时 reset_module_methods_emitted 按当前文件 sha1 匹配不到 →
|
||
特化方法体 MethodsEmitted 残留 1 → 下遍不补译 → 链接 undefined symbol。
|
||
记录触发文件 sha1 后按此精确重置(见 StructGenMixin.reset_module_methods_emitted)。
|
||
"""
|
||
if spec_name is None or trigger_sha1 is None:
|
||
return 0
|
||
entry_rt: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||
if entry_rt is None:
|
||
return 0
|
||
if string.strcmp(entry_rt.Name, spec_name) != 0:
|
||
return 0
|
||
ts_len_r: sizet = string.strlen(trigger_sha1)
|
||
ts_buf_r: str = CompilerFactory.factory.PermPool.alloc(ts_len_r + 1)
|
||
if ts_buf_r is None:
|
||
return 0
|
||
string.strcpy(ts_buf_r, trigger_sha1)
|
||
entry_rt.SpecTriggerSha1 = ts_buf_r
|
||
return 1
|
||
def _tp_names_for_spec(self, pool: memhub.MemBuddy*, class_name: str,
|
||
template_cd: ast.ClassDef*) -> list[str]*:
|
||
"""取特化用的类型参数名列表(优先 stdlib 深拷贝表,退化模板节点)
|
||
|
||
两条来源都拿不到/为空时 fail-fast,**绝不**用空泛型上下文继续特化:
|
||
空上下文会让模板方法体里的类型形参(如 `T.__sizeof__()`)落到普通名字
|
||
查找 → 报 "NameError: 未定义名称 'T'",现象与真因(元数据缺失)严重脱节。
|
||
"""
|
||
tp: list[str]* = self._find_generic_template_tp_params(pool, class_name)
|
||
if tp is not None and len(tp) > 0:
|
||
return tp
|
||
if template_cd is not None and template_cd.type_params is not None \
|
||
and len(template_cd.type_params) > 0:
|
||
return template_cd.type_params
|
||
self.Gen.TypeGenErr.fatal_error(None,
|
||
f"泛型类模板 '{class_name}' 的类型参数名缺失(GenericClassTpParams 对应槽为空,"
|
||
f"模板节点也无 type_params)——拒绝用空泛型上下文特化", "InternalCompilerError")
|
||
return None
|
||
|
||
def _specialize_generic_class(self, trans: HT.Translator*,
|
||
class_name: str,
|
||
type_args: list[str]*) -> str:
|
||
"""特化泛型类,返回特化类名
|
||
|
||
1. 查找泛型模板
|
||
2. 生成特化名
|
||
3. 检查缓存
|
||
4. 拷贝 ClassDef 节点(替换类型注解中的 T)
|
||
5. 设置 type_map 上下文(用于方法体中的 T 替换)
|
||
6. 调用 translate_class_def 翻译特化类
|
||
7. 返回特化名
|
||
"""
|
||
if trans is None or class_name is None or type_args is None:
|
||
return None
|
||
# 泛型循环套用防护:递归深度 +1,超过上限立即报错终止(防 F-bounded
|
||
# 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。
|
||
self.GenericSpecDepth += 1
|
||
# 特化触发文件 sha1:进入函数时 trans.ModuleSha1 是触发方文件,
|
||
# 翻译特化类时会被切换为模板 sha1(见下方),作废重译时按此重置
|
||
# 特化类 MethodsEmitted(见 _record_spec_trigger / reset_module_methods_emitted)
|
||
spec_trigger_sha1: str = trans.ModuleSha1
|
||
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH:
|
||
err_spec: str = trans.Pool.alloc(256)
|
||
if err_spec is not None:
|
||
viperlib.snprintf(err_spec, 256,
|
||
"泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d",
|
||
class_name, self.GenericSpecDepth)
|
||
self.Gen.TypeGenErr.fatal_error(None, err_spec, "InternalCompilerError")
|
||
self.Gen.TypeGenErr.fatal_error(None, "泛型特化递归过深(疑似泛型循环套用)", "InternalCompilerError")
|
||
# 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"),
|
||
# 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。
|
||
# 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。
|
||
ta_cnt_g: sizet = len(type_args)
|
||
ta_i_g: sizet
|
||
for ta_i_g in range(ta_cnt_g):
|
||
ta_raw_g: str = type_args.get(ta_i_g)
|
||
if ta_raw_g is not None:
|
||
ta_rsv_g: str = self.Gen.TypeGenBase.resolve_generic_type_name(ta_raw_g)
|
||
if ta_rsv_g is not None and string.strcmp(ta_raw_g, ta_rsv_g) != 0:
|
||
type_args.set(ta_i_g, ta_rsv_g)
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
|
||
# 1. 查找泛型模板
|
||
template_cd: ast.ClassDef* = self._find_generic_template(class_name)
|
||
if template_cd is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
|
||
# 2. 生成特化名(唯一生成器内部逐实参规范化:裸名/带前缀在此收敛为同一名)
|
||
_from_imports: str = None
|
||
if trans is not None:
|
||
_from_imports = trans._from_imports
|
||
spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args, _from_imports)
|
||
if spec_name is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
|
||
# Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前):Phase 1a
|
||
# 特化时只注册结构体不译方法体(MethodsEmitted==0),Phase B 重复进入时补译以生成
|
||
# define,避免符号只有 declare 无 define → 链接失败。
|
||
# 首次 Phase B 特化(Phase 1a 未特化)find_struct 返回 None,不补译,走下方正常全量翻译。
|
||
if trans._declare_only == 0:
|
||
pre_existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||
if pre_existing is not None and pre_existing.MethodsEmitted == 0:
|
||
# 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解
|
||
# 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr)
|
||
# 导致无限递归补译 → OOM。补译完成后已设置,无需恢复。
|
||
# 注意:此处提前置位后调用 _translate_oop_methods 必须传 reemit=1
|
||
# (补译模式),否则其 MethodsEmitted==1 防重复检查会拦截补译,
|
||
# 方法体永不发射 → 特化方法只有 call 无 define → 链接 undefined symbol。
|
||
pre_existing.MethodsEmitted = 1
|
||
# 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效)
|
||
tp_names_pre: list[str]* = self._tp_names_for_spec(pool, class_name, template_cd)
|
||
spec_cd_pre: ast.ClassDef* = self._clone_classdef_for_spec(pool, template_cd, spec_name, tp_names_pre, type_args)
|
||
if spec_cd_pre is not None:
|
||
trans.GenericTypeParamNames = tp_names_pre
|
||
trans.GenericTypeArgs = type_args
|
||
self.Gen.TypeGenBase.set_generic_context(tp_names_pre, type_args)
|
||
saved_ms_pre: str = trans.ModuleSha1
|
||
saved_imp_pre: str = trans._imported_modules
|
||
template_sha1_pre: str = self._find_generic_template_sha1(class_name)
|
||
if template_sha1_pre is not None:
|
||
trans.ModuleSha1 = template_sha1_pre
|
||
self._merge_template_imports(trans, template_sha1_pre)
|
||
# 错误定位上下文:补译的是模板方法体(spec_cd_pre 克隆自模板,
|
||
# node.lineno 是模板文件行号)。切换 CurrentFile 到模板文件并压入
|
||
# trace 帧,使 fatal_error 正确显示模板文件位置(翻译完恢复)。
|
||
saved_cur_pre: str = self.Gen.TypeGenResolve.get_current_file()
|
||
tpl_file_pre: str = self._find_generic_template_file(class_name)
|
||
if tpl_file_pre is not None:
|
||
self.Gen.TypeGenResolve.set_current_file(tpl_file_pre)
|
||
self.Gen.TypeGenBase.push_trace(tpl_file_pre, template_cd.lineno)
|
||
self.Gen.ClassGenVTable._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0, 1)
|
||
if tpl_file_pre is not None:
|
||
self.Gen.TypeGenBase.pop_trace()
|
||
self.Gen.TypeGenResolve.set_current_file(saved_cur_pre)
|
||
trans.ModuleSha1 = saved_ms_pre
|
||
trans._imported_modules = saved_imp_pre
|
||
trans.GenericTypeParamNames = None
|
||
trans.GenericTypeArgs = None
|
||
self.Gen.TypeGenBase.clear_generic_context()
|
||
|
||
# 3. 检查缓存(spec_key 包含所有类型实参,避免多参数泛型缓存冲突)
|
||
# 分配新缓冲区避免原地 strcat 溢出
|
||
sk_n: sizet = len(type_args)
|
||
sk_total: sizet = string.strlen(class_name) + 2 # "<" 和 ">"
|
||
sk_i: sizet
|
||
for sk_i in range(sk_n):
|
||
if sk_i > 0:
|
||
sk_total += 1 # ","
|
||
sk_ta: str = type_args.get(sk_i)
|
||
if sk_ta is not None:
|
||
sk_total += string.strlen(sk_ta)
|
||
sk_total += 1 # NUL
|
||
spec_key: str = pool.alloc(sk_total)
|
||
if spec_key is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
spec_key[0] = '\0'
|
||
string.strcat(spec_key, class_name)
|
||
string.strcat(spec_key, "<")
|
||
for sk_i in range(sk_n):
|
||
if sk_i > 0:
|
||
string.strcat(spec_key, ",")
|
||
sk_ta: str = type_args.get(sk_i)
|
||
if sk_ta is not None:
|
||
string.strcat(spec_key, sk_ta)
|
||
string.strcat(spec_key, ">")
|
||
cached: str = self._find_cached_spec(spec_key)
|
||
if cached is not None:
|
||
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
|
||
self.GenericSpecDepth -= 1
|
||
return cached
|
||
|
||
# 4. 检查是否已注册(Phase B 重复特化)
|
||
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||
if existing is not None:
|
||
self._cache_spec(pool, spec_key, spec_name)
|
||
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
|
||
self.GenericSpecDepth -= 1
|
||
return spec_name
|
||
|
||
# 预注册缓存(防止递归)
|
||
self._cache_spec(pool, spec_key, spec_name)
|
||
|
||
# 5. 拷贝 ClassDef 节点
|
||
# 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效)
|
||
tp_names: list[str]* = self._tp_names_for_spec(pool, class_name, template_cd)
|
||
spec_cd: ast.ClassDef* = self._clone_classdef_for_spec(pool, template_cd, spec_name, tp_names, type_args)
|
||
if spec_cd is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
|
||
# 6. 设置 type_map 上下文(用于方法体中的 T 替换)
|
||
trans.GenericTypeParamNames = tp_names
|
||
trans.GenericTypeArgs = type_args
|
||
self.Gen.TypeGenBase.set_generic_context(tp_names, type_args)
|
||
|
||
# 7. 翻译特化类
|
||
# 切换 trans.ModuleSha1 为泛型模板定义模块的 SHA1,
|
||
# 使结构体类型名与特化方法函数符号名都用定义模块的 SHA1 前缀
|
||
# (跨模块一致,单态化特化名 = {模板SHA1}.Class[param].method)。
|
||
# 同时并入模板模块的 imports(见 _merge_template_imports 注释),
|
||
# 避免模板方法体内的跨模块调用被误报"模块未导入"。
|
||
saved_module_sha1: str = trans.ModuleSha1
|
||
saved_imported: str = trans._imported_modules
|
||
# 【窗口同进同出】类定义窗口(CurDefModuleSha1/CurDefClassName)必须与
|
||
# ModuleSha1 一起保存/恢复:下方 translate_class_def(:729)内部会按
|
||
# **模板模块 sha1 + 特化类名** 调 mark_module_class(ClassGenDef.vp:50),
|
||
# 覆盖这两个窗口变量。原实现只恢复 trans.ModuleSha1 ⇒ 调用方文件在此之后
|
||
# 解析任何裸类名时,规则 5.5 的归属判据(证据 ② is_module_class /
|
||
# ③ CurDefClassName 逐字相同)全都在对着"模板模块 / 特化类"判 ⇒ 判不到
|
||
# ⇒ 该实参以**裸名**形式被首次注册并永久复用,与同一特化在别处解析出的
|
||
# 带 SHA1 形式分裂成两个名字,最终以"被指类型是非基本类型……不可隐式转换"
|
||
# 报出(现场:includes/ast/base.vp:359 `_append_child(self.children, ...)`
|
||
# 源 list[rawptr[AST]] vs 目标 list[rawptr<定义模块SHA1>.AST])。
|
||
saved_def_mod: str = self.Gen.StructGen.CurDefModuleSha1
|
||
saved_def_cls: str = self.Gen.StructGen.CurDefClassName
|
||
template_sha1: str = self._find_generic_template_sha1(class_name)
|
||
if template_sha1 is not None:
|
||
trans.ModuleSha1 = template_sha1
|
||
self._merge_template_imports(trans, template_sha1)
|
||
# 错误定位上下文:spec_cd 克隆自模板,方法体的 node.lineno 是模板文件
|
||
# 行号,而 CurrentFile 仍是调用方文件 → 错误显示错位。切换 CurrentFile
|
||
# 到模板文件并压入 trace 帧(翻译完恢复),使 fatal_error 正确溯源。
|
||
saved_cur_full: str = self.Gen.TypeGenResolve.get_current_file()
|
||
tpl_file_full: str = self._find_generic_template_file(class_name)
|
||
if tpl_file_full is not None:
|
||
self.Gen.TypeGenResolve.set_current_file(tpl_file_full)
|
||
self.Gen.TypeGenBase.push_trace(tpl_file_full, template_cd.lineno)
|
||
self.Gen.ClassGenDef.translate_class_def(trans, spec_cd)
|
||
if tpl_file_full is not None:
|
||
self.Gen.TypeGenBase.pop_trace()
|
||
self.Gen.TypeGenResolve.set_current_file(saved_cur_full)
|
||
# 恢复原始 ModuleSha1 / imports / **类定义窗口**(窗口不平移,见上方说明)
|
||
trans.ModuleSha1 = saved_module_sha1
|
||
trans._imported_modules = saved_imported
|
||
self.Gen.StructGen.CurDefModuleSha1 = saved_def_mod
|
||
self.Gen.StructGen.CurDefClassName = saved_def_cls
|
||
|
||
# 8. 清除 type_map 上下文
|
||
trans.GenericTypeParamNames = None
|
||
trans.GenericTypeArgs = None
|
||
self.Gen.TypeGenBase.clear_generic_context()
|
||
|
||
# 特化结果字段名完整性检查(fail-fast:字段名缺失 = 字段表损坏,
|
||
# 静默继续会让后续 GEP 按错索引访问)
|
||
if string.strcmp(class_name, "GSListNode") == 0:
|
||
result_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||
if result_entry is not None:
|
||
for ri in range(result_entry.FieldCount):
|
||
rfe: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(result_entry, ri)
|
||
if rfe is not None:
|
||
rfn: str = self.Gen.StructGen.get_field_name_ptr(rfe)
|
||
if rfn is None:
|
||
VLogger.error("SPEC 字段名缺失(字段表损坏)", "SPEC")
|
||
self.Gen.TypeGenErr.fatal_error(None, "SPEC 字段名缺失(字段表损坏)", "TypeError")
|
||
|
||
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
|
||
self.GenericSpecDepth -= 1
|
||
return spec_name |