Files
ViperC/App/lib/core/Gen/Class/ClassGenGeneric.vp
T
TermiNexus 1ad7abf33d refactor(TransPyV): 统一自举写法(novirtual / define / rawptr→* / 去续行反斜杠)
- @t.NoVTable class X → novirtual class X
- t.CDefine = N → define N
- rawptr[X]、X | t.CPtr → X*
- t.CPtr → rawptr(裸指针标记)
- t.Callable[...] → callable[...]
- 去掉 if/elif 条件的行续反斜杠(改单行写法)
- w32.win32file.X → win32file.X(已 import as)
- core/__init__.vp 去掉未使用的 import t, c / from stdint import *

涉及:CompilerFactory、IncludesScanner、Repl、core/__init__、
Gen/Call/{CallGenBase,CallGenCBuiltin,CallGenCall,CallGenDispatch,CallGenLeafKit}、
Gen/Class/ClassGenGeneric。
2026-10-02 02:16:37 +08:00

770 lines
40 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 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
# 泛型特化递归深度上限(泛型循环套用防护)
# 正常嵌套特化深度 ≤ 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 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
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 _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._find_generic_template_tp_params(pool, class_name)
if tp_names_pre is None:
tp_names_pre = template_cd.type_params
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._find_generic_template_tp_params(pool, class_name)
if tp_names is None:
tp_names = template_cd.type_params
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