feat(generic): 泛型函数类型实参推断与单态化

支持 def f[T](x: T) -> T 及 f(x)/f[T](x):模板注册(Phase1Scan/Phase2 顶层 FunctionDef,键 {sha1}.{name})、按形参注解对齐从实参推断类型实参(无来源即 fail-fast,不静默默认 int)、克隆模板并 set_generic_context 后翻译生成特化体(名字 {sha1}.f[int],规范化复用 _mangle_generic_class_name)、同签名去重、跨模块按模板签名补 declare。泛型函数模板不再发 vpi(模板签名含未绑定 T),也不再发射 int 兜底版本。已知限制(未静默):bound [T: bound] 解析期已被丢弃;t.CExport/t.CExtern/t.State 泛型函数、关键字/默认参数调用、mod.f[T](x) 显式下标等暂 fail-fast 或走既有报错。
This commit is contained in:
TermiNexus committed 2026-10-03 11:59:26 +08:00
1 parent 1fbebb2a62
commit 692998820c
10 files changed
+886 -57

No files matched your search

+72 -14
View File
@@ -245,6 +245,50 @@ def _BufHasGenericClassMarker(buf: bytes, blen: sizet) -> int:
pos += 1
return 0
# ============================================================
# _BufHasGenericFuncMarker - 文本扫描检测文件是否含泛型函数标记
#
# 泛型函数(PEP 695)语法: def name[(函数名后紧跟 '[',如 def f[T](...):)。
# 与 _BufHasGenericClassMarker 同款逐字节词边界扫描;用于泛型函数模板的
# 轻量预筛(避免为无泛型函数的文件 parse AST)。误报无害、漏报有害(模板未
# 预注册),故保守只匹配单行形式。
# ============================================================
def _BufHasGenericFuncMarker(buf: bytes, blen: sizet) -> int:
"""文本扫描:buf 中是否有 'def 标识符[' 泛型函数标记,返回 1/0"""
if buf is None or blen <= 4:
return 0
pos: sizet = 0
while pos + 3 < blen:
if buf[pos] == 'd' and buf[pos + 1] == 'e' and buf[pos + 2] == 'f':
# def 前是词边界(行首或非标识符字符)
prev_ok: int = 1
if pos > 0:
pc: char = buf[pos - 1]
if(pc >= 'a' and pc <= 'z') or(pc >= 'A' and pc <= 'Z') \
or(pc >= '0' and pc <= '9') or pc == '_':
prev_ok = 0
if prev_ok != 0:
p: sizet = pos + 3
# 跳过空白
while p < blen and(buf[p] == ' ' or buf[p] == '\t'):
p += 1
# 读函数名标识符
if p < blen and((buf[p] >= 'a' and buf[p] <= 'z')
or(buf[p] >= 'A' and buf[p] <= 'Z') or buf[p] == '_'):
while p < blen and((buf[p] >= 'a' and buf[p] <= 'z')
or(buf[p] >= 'A' and buf[p] <= 'Z')
or(buf[p] >= '0' and buf[p] <= '9')
or buf[p] == '_'):
p += 1
# 函数名后非空白是 '[' → 泛型函数
while p < blen and(buf[p] == ' ' or buf[p] == '\t'):
p += 1
if p < blen and buf[p] == '[':
return 1
pos += 1
else:
pos += 1
return 0
# ============================================================
# _PreRegisterAllGenericTemplates - 预注册 includes 泛型类模板(mark1 前)
#
# 泛型模板表(GenericClassNames/GenericClassNodes/GenericClassSha1s/GenericClassFiles + 模板节点)是懒分配的跨文件持久表,
@@ -289,8 +333,10 @@ def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy*,
continue
if bytes_read_pg < Phase1.SRC_BUF_SIZE:
src_buf_pg[bytes_read_pg] = 0
# 文本扫描筛选:非泛型文件跳过(不 parse、不驻留,防 OOM)
if _BufHasGenericClassMarker(src_buf_pg, bytes_read_pg) == 0:
# 文本扫描筛选:非泛型文件跳过(不 parse、不驻留,防 OOM)。
# 泛型类(class X[)与泛型函数(def f[)任一命中即进入 parse。
if _BufHasGenericClassMarker(src_buf_pg, bytes_read_pg) == 0 \
and _BufHasGenericFuncMarker(src_buf_pg, bytes_read_pg) == 0:
stdlib.free(src_buf_pg)
continue
# 泛型文件:永久池解析 → 注册模板(节点/表进 perm_pool,跨 reset 存活)
@@ -304,26 +350,38 @@ def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy*,
if tree_pg is None:
stdlib.free(src_buf_pg)
continue
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
# 遍历顶层 ClassDef/FunctionDef,注册泛型模板(type_params 非 None)
ch_pg: list[ast.AST*]* = tree_pg.children
if ch_pg is not None:
cn_pg: sizet = len(ch_pg)
for ci_pg in range(cn_pg):
child_pg: ast.AST* = ch_pg.get(ci_pg)
if child_pg is None or child_pg.kind() != ast.ASTKind.ClassDef:
if child_pg is None:
continue
cd_pg: ast.ClassDef* = ast.ClassDef*(child_pg)
if cd_pg is None or cd_pg.name is None:
continue
tp_pg: list[str]* = cd_pg.type_params
if tp_pg is None:
continue
GenApi.set_current_file_type(file_path_pg)
GenApi._register_generic_template(perm, cd_pg, entry_pg.Sha1)
handled_count += 1
ck_pg: int = child_pg.kind()
if ck_pg == ast.ASTKind.ClassDef:
cd_pg: ast.ClassDef* = ast.ClassDef*(child_pg)
if cd_pg is None or cd_pg.name is None:
continue
tp_pg: list[str]* = cd_pg.type_params
if tp_pg is None:
continue
GenApi.set_current_file_type(file_path_pg)
GenApi._register_generic_template(perm, cd_pg, entry_pg.Sha1)
handled_count += 1
elif ck_pg == ast.ASTKind.FunctionDef:
fd_pg: ast.FunctionDef* = ast.FunctionDef*(child_pg)
if fd_pg is None or fd_pg.name is None:
continue
tf_pg: list[str]* = fd_pg.type_params
if tf_pg is None:
continue
GenApi.set_current_file_type(file_path_pg)
GenApi._register_generic_func_template(perm, fd_pg, entry_pg.Sha1)
handled_count += 1
stdlib.free(src_buf_pg)
if handled_count > 0:
VLogger.info(f"mark1 前永久池预注册 {handled_count} 个 includes 泛型类模板", "Phase1")
VLogger.info(f"mark1 前永久池预注册 {handled_count} 个 includes 泛型模板(类+函数)", "Phase1")
else:
VLogger.info(f"mark1 前永久池预注册 0 个泛型模板(扫描 {result.Count} 个文件,可能 marker 未命中或全量扫描失败)", "Phase1")
return handled_count
+24 -12
View File
@@ -303,26 +303,38 @@ def _PreRegisterAppGenericTemplates(mb: memhub.MemBuddy*,
if tree_pa is None:
stdlib.free(src_buf_pa)
continue
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
# 遍历顶层 ClassDef/FunctionDef,注册泛型模板(type_params 非 None)
ch_pa: list[ast.AST*]* = tree_pa.children
if ch_pa is not None:
cn_pa: sizet = len(ch_pa)
for ci_pa in range(cn_pa):
child_pa: ast.AST* = ch_pa.get(ci_pa)
if child_pa is None or child_pa.kind() != ast.ASTKind.ClassDef:
if child_pa is None:
continue
cd_pa: ast.ClassDef* = ast.ClassDef*(child_pa)
if cd_pa is None or cd_pa.name is None:
continue
tp_pa: list[str]* = cd_pa.type_params
if tp_pa is None:
continue
GenApi.set_current_file_type(ent_pa.Path)
GenApi._register_generic_template(perm_pa, cd_pa, ent_pa.Sha1)
handled += 1
ck_pa: int = child_pa.kind()
if ck_pa == ast.ASTKind.ClassDef:
cd_pa: ast.ClassDef* = ast.ClassDef*(child_pa)
if cd_pa is None or cd_pa.name is None:
continue
tp_pa: list[str]* = cd_pa.type_params
if tp_pa is None:
continue
GenApi.set_current_file_type(ent_pa.Path)
GenApi._register_generic_template(perm_pa, cd_pa, ent_pa.Sha1)
handled += 1
elif ck_pa == ast.ASTKind.FunctionDef:
fd_pa: ast.FunctionDef* = ast.FunctionDef*(child_pa)
if fd_pa is None or fd_pa.name is None:
continue
tf_pa: list[str]* = fd_pa.type_params
if tf_pa is None:
continue
GenApi.set_current_file_type(ent_pa.Path)
GenApi._register_generic_func_template(perm_pa, fd_pa, ent_pa.Sha1)
handled += 1
stdlib.free(src_buf_pa)
if handled > 0:
VLogger.info(f"mark2 前预注册 {handled} 个 App 泛型类模板", "PhaseA")
VLogger.info(f"mark2 前预注册 {handled} 个 App 泛型模板(类+函数)", "PhaseA")
return handled
+7
View File
@@ -984,6 +984,13 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
# 函数定义(_PyiFunction 已以 "\n" 收尾,不再补空行)
elif k == ast.ASTKind.FunctionDef:
fn: ast.FunctionDef* = ast.FunctionDef*(stmt)
# 泛型函数模板(def f[T])不发 vpi:模板签名含未绑定类型形参 T,
# 注入侧无法解析(旧行为会写出 `def f(x: T)` 的错误/失败签名)。
# 特化体按调用点单态化生成({模板SHA1}.f[args]),其签名由编译器
# 内存中的模板表 + 实参跨模块复现(见 ClassGenGeneric.
# _ensure_generic_func_declare),不落 vpi。
if fn.type_params is not None:
continue
pos = _PyiFunction(buf, buf_size, pos, fn, 0, "")
# 类定义
+219
View File
@@ -27,6 +27,225 @@ import lib.core.Gen.GenApi as GenApi
novirtual class CallGenDispatch(CallGenBase.CallGenBase):
"""translate_call 前置检测 helper(继承 Base)"""
# ============================================================
# _tc_h0_generic_func - 泛型函数调用(隐式/显式类型实参 → 单态化 → 调用)
#
# 未命中(不是泛型函数调用)返回 None;命中即发射调用并用 hit_box 标记
# (返回 None 但 hit_box=1 表示返回 void 的调用,不可再走主路径)。
# 必须在普通函数/类构造分派之前拦截:泛型函数模板在定义处不发射普通函数,
# 走主路径会"裸名调用未定义"。
# ============================================================
def _tc_h0_generic_func(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
cl: ast.Call*,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator*,
func_name: str,
cargs: list[ast.AST*]*,
can: sizet,
hit_box: t.CPtr = None) -> llvmlite.Value*:
if cl is None or trans is None: return None
if self.Gen.ClassGenGeneric.GenericFuncKeys is None: return None
if cl.func is None: return None
# ---- 判定泛型函数调用形态 + 模板名/显式类型实参 ----
tpl_name: str = None
explicit_slice: ast.AST* = None
tpl_mod_sha1: str = None
is_attr_call: int = 0
fk: int = cl.func.kind()
if fk == ast.ASTKind.Subscript:
sub: ast.Subscript* = ast.Subscript*(cl.func)
if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
sn: ast.Name* = ast.Name*(sub.value)
tpl_name = sn.id
explicit_slice = sub.slice
elif fk == ast.ASTKind.Name:
tpl_name = func_name
elif fk == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(cl.func)
if at.attr is not None and at.value is not None and at.value.kind() == ast.ASTKind.Name:
mn: ast.Name* = ast.Name*(at.value)
if mn.id is not None and trans._imported_modules is not None:
if self.Gen.ImportsGen.is_module_imported_or_known(trans._imported_modules, mn.id) != 0:
tpl_mod_sha1 = self._lookup_module_sha1(mn.id)
# 仅当基座是**已导入模块**时才按模块限定泛型函数处理;
# 否则 `obj.add(x)` 里 obj 不是模块,绝不能按裸名 local 键
# 命中同名模块级泛型函数 add 而劫持方法调用。
if tpl_mod_sha1 is not None:
is_attr_call = 1
tpl_name = at.attr
if tpl_name is None: return None
# ---- 解析模板键("{sha1}.{fname}"):模块限定 > 本模块 > from_imports ----
tpl_key: str = None
if is_attr_call != 0:
# 模块限定调用:只认该模块 SHA1 的键
if tpl_mod_sha1 is not None:
cand_q: str = self._generic_func_key(pool, tpl_mod_sha1, tpl_name)
if self.Gen.ClassGenGeneric._find_generic_func_template(cand_q) is not None:
tpl_key = cand_q
else:
if trans.ModuleSha1 is not None:
cand_l: str = self._generic_func_key(pool, trans.ModuleSha1, tpl_name)
if self.Gen.ClassGenGeneric._find_generic_func_template(cand_l) is not None:
tpl_key = cand_l
if tpl_key is None and trans._from_imports is not None:
imp_sha: str = self._lookup_mod_sha1(pool, trans._from_imports, tpl_name, 0)
if imp_sha is not None:
cand_f: str = self._generic_func_key(pool, imp_sha, tpl_name)
if self.Gen.ClassGenGeneric._find_generic_func_template(cand_f) is not None:
tpl_key = cand_f
if tpl_key is None: return None
template_fd: ast.FunctionDef* = self.Gen.ClassGenGeneric._find_generic_func_template(tpl_key)
if template_fd is None: return None
tp_names: list[str]* = self.Gen.ClassGenGeneric._find_generic_func_tp_params(pool, tpl_key)
if tp_names is None: tp_names = template_fd.type_params
if tp_names is None: return None
tp_count: sizet = len(tp_names)
if tp_count == 0: return None
# ---- 汇总类型实参 ----
type_args: list[str]* = None
if explicit_slice is not None:
type_args = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, explicit_slice, trans._from_imports)
if type_args is None or len(type_args) != tp_count:
self.Gen.TypeGenErr.fatal_error(cl,
f"泛型函数 '{tpl_name}' 显式类型实参个数不匹配(需要 {tp_count}):请写 {tpl_name}[类型1, 类型2](...)",
"TypeError")
return None
else:
# 隐式推断:按模板签名的形参位对齐(形参注解恰为 T 的那一位实参)
ctx_args: list[str]* = self.Gen.CallGenCtor._infer_ctor_type_args_from_ctx(pool, trans, tpl_name, int(tp_count), cl)
type_args = list[str](pool, 8)
if type_args is None: return None
tpi: sizet
for tpi in range(tp_count):
tp_name: str = tp_names.get(tpi)
ta: str = None
slot: int = self.Gen.ClassGenGeneric._find_generic_func_param_slot(template_fd, tp_name)
if slot >= 0 and sizet(slot) < can:
ta = self.Gen.ClassGenGeneric._infer_generic_func_type_arg(pool, cargs.get(sizet(slot)), tpl_name, trans)
if ta is None and slot >= 0:
# 关键字实参:按模板形参名定位(位置优先,槽位已被位置实参占用则 -1)
kwi: int = self._generic_func_kw_arg_index(template_fd, slot, cl.keywords, int(can))
if kwi >= 0:
kwn: rawptr[ast.Keyword] = rawptr[ast.Keyword](cl.keywords.get(sizet(kwi)))
if kwn is not None and kwn.value is not None:
ta = self.Gen.ClassGenGeneric._infer_generic_func_type_arg(pool, kwn.value, tpl_name, trans)
if ta is None and ctx_args is not None and sizet(tpi) < len(ctx_args):
ta = ctx_args.get(tpi)
if ta is None:
self.Gen.TypeGenErr.fatal_error(cl,
f"无法从实参推断泛型函数 '{tpl_name}' 的第 {tpi + 1} 个类型实参(类型形参 {tp_name});"
f"禁止静默默认 int。请显式标注如 {tpl_name}[类型](...) 或为对应实参标注类型",
"TypeError")
return None
type_args.append(ta)
# ---- 单态化 ----
spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_function(trans, tpl_key, type_args)
if spec_name is None:
self.Gen.TypeGenErr.fatal_error(cl, f"泛型函数 '{tpl_name}' 特化失败", "TypeError")
return None
# ---- 发射调用 ----
return self._emit_generic_func_call(pool, builder, mod, trans, cl, spec_name, cargs, can, hit_box)
def _generic_func_key(self, pool: memhub.MemBuddy*,
sha1: str, name: str) -> str:
"""构造泛型函数模板键 "{sha1}.{name}"(新缓冲区)"""
if sha1 is None or name is None: return None
klen: sizet = string.strlen(sha1) + string.strlen(name) + 2
kbuf: str = pool.alloc(klen)
if kbuf is None: return None
viperlib.snprintf(kbuf, klen, "%s.%s", sha1, name)
return kbuf
def _generic_func_kw_arg_index(self, template_fd: ast.FunctionDef*,
slot: int, keywords: list[ast.AST*]*,
pos_count: int) -> int:
"""类型形参对应的形参槽位由关键字实参传入时,返回 keywords 下标;否则 -1
slot 已被位置实参占用(slot < pos_count)时返回 -1(位置优先)。
"""
if template_fd is None or keywords is None: return -1
if slot < pos_count: return -1
if template_fd.args is None or template_fd.args.kind() != ast.ASTKind.Arguments: return -1
ags: ast.Arguments* = ast.Arguments*(template_fd.args)
if ags.args is None: return -1
alist: list[ast.AST*]* = ags.args
if sizet(slot) >= len(alist): return -1
pa: ast.AST* = alist.get(sizet(slot))
if pa is None or pa.kind() != ast.ASTKind.Arg: return -1
ag: ast.Arg* = ast.Arg*(pa)
if ag.arg is None: return -1
kn: sizet = len(keywords)
ki: sizet
for ki in range(kn):
kw: rawptr[ast.Keyword] = rawptr[ast.Keyword](keywords.get(ki))
if kw is None or kw.arg is None:
continue
if string.strcmp(kw.arg, ag.arg) == 0:
return int(ki)
return -1
def _emit_generic_func_call(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
cl: ast.Call*,
spec_name: str,
cargs: list[ast.AST*]*,
can: sizet,
hit_box: t.CPtr = None) -> llvmlite.Value*:
"""发射对特化函数的调用(按特化 define/declare 的形参类型 coerce 实参)
泛型函数调用只支持位置实参(关键字实参/默认参数缺口 fail-fast,不静默)。
"""
func: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, spec_name)
if func is None:
self.Gen.TypeGenErr.fatal_error(cl,
f"泛型函数特化符号未在当前模块注册: {spec_name}", "InternalCompilerError")
return None
kw: list[ast.AST*]* = cl.keywords
if kw is not None and len(kw) > 0:
self.Gen.TypeGenErr.fatal_error(cl, "泛型函数调用暂不支持关键字实参,请改用位置实参", "TypeError")
return None
if hit_box is not None:
hit_box[0] = 1
param_count: int = 0
pp: llvmlite.Param* = llvmlite.function_get_param_head(func)
while pp is not None:
param_count += 1
pp = llvmlite.param_get_next(pp)
if int(can) < param_count:
self.Gen.TypeGenErr.fatal_error(cl,
"泛型函数调用实参个数少于形参个数(默认参数暂不支持),请补齐实参", "TypeError")
return None
ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(func)
head: llvmlite.Value* = None
tail: llvmlite.Value* = None
fp: llvmlite.Param* = llvmlite.function_get_param_head(func)
ai: sizet = 0
while ai < can:
arg: ast.AST* = cargs.get(ai)
fpty: llvmlite.LLVMType* = None
if fp is not None:
fpty = llvmlite.param_get_ty(fp)
if arg is not None:
av: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, fpty, "形参")
if av is not None:
if fpty is not None:
av = self.Gen.ExprGenBase.coerce_to_type(builder, av, fpty, arg, trans)
av.Next = None
if head is None:
head = av
else:
tail.Next = av
tail = av
if fp is not None:
fp = llvmlite.param_get_next(fp)
ai += 1
return llvmlite.build_call(builder, func, head, int(can), ret_ty, 0)
def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
+16
View File
@@ -112,6 +112,22 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
can: sizet = 0
if cargs is not None:
can = len(cargs)
# ---- 泛型函数调用(PEP 695 def f[T])优先拦截 ----
# 泛型函数模板在定义处不发射普通函数(见 FuncGenDef 守护),必须在此
# 之前完成类型实参推断 + 单态化。命中即返回(含 void 返回:hit_box=1
# 区分"已处理无返回值"与"未命中")。未命中返回 None 继续既有分派。
h0_hit: t.CPtr = stdlib.malloc(4)
if h0_hit is not None:
h0_hit[0] = 0
_tc_h0_generic_func_res: llvmlite.Value* = self.Gen.CallGenDispatch._tc_h0_generic_func(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h0_hit)
h0_hit_val: int = 0
if h0_hit is not None:
h0_hit_val = h0_hit[0]
stdlib.free(h0_hit)
if _tc_h0_generic_func_res is not None:
return _tc_h0_generic_func_res
if h0_hit_val != 0:
return None
# super()/ctraits 检测:void 方法(如 __init__)命中后 build_call 返回
# None 属预期(void call 无 SSA 值),必须用 hit_box 区分"命中已处理"
# 与"未命中",否则 None 被误判继续主路径 → 内层 Call(super) 当裸名
+5
View File
@@ -1237,6 +1237,11 @@ novirtual class ClassGenBase:
self.GenericClassSha1s = None
self.GenericClassFiles = None
self.GenericClassTpParams = None
self.GenericFuncKeys = None
self.GenericFuncNodes = None
self.GenericFuncSha1s = None
self.GenericFuncFiles = None
self.GenericFuncTpParams = None
self.VtFullNames = None
self.VtMethodNames = None
self.VtParentSha1s = None
+510
View File
@@ -11,6 +11,7 @@ import lib.core.CompilerFactory as CompilerFactory
from . import ClassGenBase
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
import lib.core.Gen.Type.TypeSpec as TSpec
# 泛型特化递归深度上限(泛型循环套用防护)
@@ -144,6 +145,515 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
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:
fn_id: str = None
if cl_f.func.kind() == ast.ASTKind.Name:
fn_nm: ast.Name* = ast.Name*(cl_f.func)
fn_id = fn_nm.id
elif cl_f.func.kind() == ast.ASTKind.Attribute:
fn_at: ast.Attribute* = ast.Attribute*(cl_f.func)
fn_id = fn_at.attr
if fn_id is not None:
if string.strcmp(fn_id, "float") == 0 or string.strcmp(fn_id, "double") == 0 \
or string.strstr(fn_id, "Float") is not None or string.strstr(fn_id, "Double") is not None:
return "double"
if string.strcmp(fn_id, "char") == 0 or string.strstr(fn_id, "Char") is not None:
return "char"
if string.strcmp(fn_id, "int") == 0 or string.strstr(fn_id, "Int") is not None \
or string.strstr(fn_id, "UInt") is not None or string.strstr(fn_id, "Short") is not None \
or string.strstr(fn_id, "Long") is not None:
return "int"
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(交由注解来源名路径处理;此处不做猜测,避免错特化)。
"""
if pool is None or sp is None: return None
buf: str = pool.alloc(32)
if buf is None: return None
buf[0] = '\0'
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, "half") == 0: return "float"
if string.strcmp(buf, "i1") == 0: return "bool"
if string.strcmp(buf, "i8") == 0: return "char"
if string.strcmp(buf, "i16") == 0: return "int"
if string.strcmp(buf, "i32") == 0: return "int"
if string.strcmp(buf, "i64") == 0: return "int"
return None
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
+19 -31
View File
@@ -87,22 +87,16 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
fd: ast.FunctionDef* = ast.FunctionDef*(child)
if fd is None or fd.name is None: continue
# PEP 695 泛型函数(def f[T](...) -> T)按普通函数编译(TPV 无泛型
# 函数特化机制,与 translate_function_def L678-691 一致):此处先设置
# 类型参数上下文(T→"int"),使返回/参数注解中的 T 可解析,否则
# forward_declare 阶段 "函数返回类型解析失败:注解不可解析"
# (ExpandKeywordsTest fn ident[T] 根因)。所有退出路径(continue /
# 循环末尾)必须 clear_generic_context,避免污染后续函数注解解析。
tp_names_fd: list[str]* = None
# PEP 695 泛型函数(def f[T](...) -> T)**不发射前向声明**:注册为
# 泛型函数模板,调用点单态化时经 _specialize_generic_function 克隆
# 发射特化 define({模板SHA1}.f[args])。旧行为(T 映射 int 兜底、
# 按普通函数编译)已废弃——那会让 f(1.5) 被误编译成 int 版
# (违反 D25「禁止静默默认 int」),且与特化路径的符号名冲突。
# 与 translate_function_def 顶部同判据(幂等注册)。
if fd.type_params is not None:
tp_names_fd = fd.type_params
tp_args_fd: list[str]* = list[str](pool, 8)
if tp_args_fd is not None:
tpn_fd: sizet = len(fd.type_params)
tpi_fd: sizet = 0
for tpi_fd in range(tpn_fd):
tp_args_fd.append("int")
self.Gen.TypeGenBase.set_generic_context(tp_names_fd, tp_args_fd)
self.Gen.ClassGenGeneric._register_generic_func_template(pool, fd, trans.ModuleSha1)
continue
tp_names_fd: list[str]* = None
# 推断返回类型
ret_ty: llvmlite.LLVMType* = None
@@ -303,6 +297,13 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
if fd is None or fd.name is None:
return 0
# PEP 695 泛型函数模板不直接发射(与 forward_declare_functions 同口径):
# 调用点单态化时由 ClassGenGeneric._specialize_generic_function 克隆发射
# (克隆体的 type_params 已清空,不会落到此分支)。此处仅确保模板已注册。
if fd.type_params is not None:
self.Gen.ClassGenGeneric._register_generic_func_template(trans.Pool, fd, trans.ModuleSha1)
return 0
# async def(TPV-M1 协程):FLAG_IS_ASYNC=1(includes/ast/stmts.vp L342-345,
# 解析器把 async def 存为 FunctionDef 且 flags & 1)。
# → 走 AsyncGenMixin 状态机翻译(create_<name>/resume_<name>),
@@ -739,20 +740,9 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
# 进入函数作用域(嵌套符号表)
self.Gen.VarGen.enter_scope(trans.SymTab, FuncGenMixin.SCOPE_FUNCTION)
# PEP 695 泛型函数: def f[T](...) — 设置泛型上下文,类型参数映射到 "int" 兜底。
# TPV 无泛型函数特化机制(类泛型走 _specialize_generic_class),泛型函数按普通
# 函数编译;设置上下文使参数注解 T / 方法体中的 T(x) 转换可解析为 int。
# (注意与类特化的 set_generic_context 一样是全局状态,需在退出作用域前清除。)
tp_names_fn: list[str]* = None
if fd.type_params is not None:
tp_names_fn = fd.type_params
tp_args_fn: list[str]* = list[str](pool, 8)
if tp_args_fn is not None:
tpn_fn: sizet = len(fd.type_params)
tpi_fn: sizet = 0
for tpi_fn in range(tpn_fn):
tp_args_fn.append("int")
self.Gen.TypeGenBase.set_generic_context(tp_names_fn, tp_args_fn)
# 泛型函数模板在入口处已早返回(见本函数顶部);到此处 fd.type_params 恒为
# None(特化克隆清空 type_params),泛型上下文由 _specialize_generic_function
# 在调用 translate_function_def 前用具体类型实参设置。
# 为参数创建 alloca
if args_node is not None:
@@ -1043,8 +1033,6 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
# 恢复模块级作用域(退出函数作用域)
if tp_names_fn is not None:
self.Gen.TypeGenBase.clear_generic_context()
self.Gen.VarGen.exit_scope(trans.SymTab)
trans._cur_func = old_func
trans._cur_builder = old_builder
+7
View File
@@ -531,6 +531,13 @@ def _register_generic_template(pool: memhub.MemBuddy*, cd: ast.ClassDef*, module
_g_gen.ClassGenGeneric._register_generic_template(pool, cd, module_sha1)
# ---------------- _register_generic_func_template(委托 ClassGenGeneric._register_generic_func_template) ----------------
def _register_generic_func_template(pool: memhub.MemBuddy*, fd: ast.FunctionDef*, module_sha1: str):
"""委托到 gen.ClassGenGeneric._register_generic_func_template(扫描预注册用)"""
if _g_gen is not None:
_g_gen.ClassGenGeneric._register_generic_func_template(pool, fd, module_sha1)
# ---------------- _mangle_name_with_sha1(委托 FuncGenBase._mangle_name_with_sha1) ----------------
def _mangle_name_with_sha1(sha1: str, name: str) -> str:
"""委托到 gen._mangle_name_with_sha1(原 Handles 壳)"""
+7
View File
@@ -89,6 +89,13 @@ novirtual class TranslatorGenMixin:
self.Gen.ImportsGen.translate_import_from_module(trans, child)
self.Gen.ImportsGen.translate_import_from_names(trans, child)
elif kd == ast.ASTKind.FunctionDef:
# PEP 695 泛型函数(def f[T]):定义处不发射(模板已由 Phase1Scan/
# Phase2 扫描或 forward_declare_functions 注册),调用点单态化。
# 必须在此跳过——否则 1a 的 _prescan_funcdef_signatures 会把未绑定
# 类型形参 T 当注解解析(落空/误导)。
fd_tc: ast.FunctionDef* = ast.FunctionDef*(child)
if fd_tc is not None and fd_tc.type_params is not None:
continue
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
# Phase 1b 全量翻译:正常翻译函数体
if trans._declare_only == 0: