Files
ViperC/App/lib/core/Gen/Class/ClassGenGeneric.vp
T
TermiNexus 28b7437e21 fix(generic): 泛型类构造 Call 实参推断同步收紧,抽出共用精确映射
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 样板,保证两处同口径。
2026-10-03 15:51:12 +08:00

1339 lines
73 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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