fix(gen): 泛型裸名构造补齐注解上下文与关键字实参两条推断来源

- 赋值目标/返回注解上下文作为最后一级类型实参来源(s: Stack[int] = Stack()、-> Stack[int] 里 return Stack()),注解解析复用 _extract_type_args_from_slice,以 CurAssignNode/CurRetNode identity 限定直接值避免嵌套误用

- 仅关键字实参构造按 __init__ 形参名定位槽位(Box(v=42)、Pair(b=string, a=1) 乱序),泛型构造码生成不再静默丢弃 cl.keywords(此前会生成少一个实参的错误调用);形参名查无/槽位空洞 fail-fast

- 抽取共用 __init__ 形参遍历(_get_ctor_init_params),位置对齐语义保持不变
This commit is contained in:
TermiNexus committed 2026-09-15 21:52:41 +08:00
1 parent 6394ea30e2
commit 5a59432733
5 files changed
+311 -35

No files matched your search

+263 -33
View File
@@ -949,24 +949,21 @@ class CallGenCtor(CallGenBase.CallGenBase):
return self._annotation_refers_type_param(bop_a.right, tp_name)
return 0
def _find_ctor_type_param_arg_index(self, class_name: str,
tp_name: str) -> int:
"""查找泛型类模板 __init__ 中注解为类型形参 tp_name 的形参对应的位置实参下标
def _get_ctor_init_params(self, class_name: str) -> list[ast.AST | t.CPtr] | t.CPtr:
"""取泛型类模板 __init__ 的形参列表(含 self,形参 0)
返回「位置实参下标」(0 = 第 1 个位置实参;形参 0 是 self,故等于形参
序号 - 1);找不到返回 -1(调用方退化为「同一序号」对齐)。
用途:类型形参 i 的推断来源不是第 i 个实参(Vector[T].__init__(
self, pool, capacity, _hint: T) 的 T 在第 3 个位置实参,pool/capacity
是非 T 参数),须按签名对齐。
遍历方式先例:ClassGenGeneric._clone_classdef_for_spec /
_clone_arguments 同样遍历 cd.children → FunctionDef → fd.args →
ast.Arg.annotation。
模板不存在 / 无 __init__ / args 形态不可用 → None。
遍历先例:ClassGenGeneric._clone_classdef_for_spec / _clone_arguments
同样遍历 cd.children → FunctionDef → fd.args → ast.Arg.annotation。
调用方(共用同一遍历,不另起一套):
_find_ctor_type_param_param_index(TYPE 形参 → 形参序号)
_ctor_init_arg_slot_by_name(关键字实参名 → 非 self 形参序号)
"""
if class_name is None or tp_name is None:
return -1
if class_name is None:
return None
template_cd: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(class_name)
if template_cd is None or template_cd.children is None:
return -1
return None
children: list[ast.AST | t.CPtr] | t.CPtr = template_cd.children
cn: sizet = len(children)
ci: sizet
@@ -978,30 +975,198 @@ class CallGenCtor(CallGenBase.CallGenBase):
if fd.name is None or string.strcmp(fd.name, "__init__") != 0:
continue
if fd.args is None or fd.args.kind() != ast.ASTKind.Arguments:
return -1
return None
fargs: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args)
if fargs.args is None:
return -1
plist: list[ast.AST | t.CPtr] | t.CPtr = fargs.args
pn: sizet = len(plist)
pi: sizet
for pi in range(pn):
if pi == 0:
continue # self:位置实参下标 = 形参序号 - 1
pa: ast.AST | t.CPtr = plist.get(pi)
if pa is None or pa.kind() != ast.ASTKind.Arg:
continue
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(pa)
if self._annotation_refers_type_param(ag.annotation, tp_name) != 0:
return int(pi) - 1
return None
return fargs.args
return None
def _find_ctor_type_param_param_index(self, class_name: str,
tp_name: str) -> int:
"""泛型类模板 __init__ 中注解为类型形参 tp_name 的形参序号(含 self,0 起)
找不到返回 -1。位置实参下标 = 本返回值 - 1(形参 0 是 self)。
用途:类型形参 i 的推断来源不是第 i 个实参(Vector[T].__init__(
self, pool, capacity, _hint: T) 的 T 在第 3 个位置实参,pool/capacity
是非 T 参数),须按签名对齐——位置实参对齐(_find_ctor_type_param_arg_index)
与关键字实参对齐(_find_ctor_type_param_kw_arg_index)共用本函数。
"""
if class_name is None or tp_name is None:
return -1
plist: list[ast.AST | t.CPtr] | t.CPtr = self._get_ctor_init_params(class_name)
if plist is None:
return -1
pn: sizet = len(plist)
pi: sizet
for pi in range(pn):
if pi == 0:
continue # self:位置实参下标 = 形参序号 - 1
pa: ast.AST | t.CPtr = plist.get(pi)
if pa is None or pa.kind() != ast.ASTKind.Arg:
continue
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(pa)
if self._annotation_refers_type_param(ag.annotation, tp_name) != 0:
return int(pi)
return -1
def _find_ctor_type_param_arg_index(self, class_name: str,
tp_name: str) -> int:
"""查找泛型类模板 __init__ 中注解为类型形参 tp_name 的形参对应的位置实参下标
返回「位置实参下标」(0 = 第 1 个位置实参;形参 0 是 self,故等于形参
序号 - 1);找不到返回 -1(调用方退化为「同一序号」对齐)。
用途:类型形参 i 的推断来源不是第 i 个实参(Vector[T].__init__(
self, pool, capacity, _hint: T) 的 T 在第 3 个位置实参,pool/capacity
是非 T 参数),须按签名对齐。
遍历(形参序号定位)委托 _find_ctor_type_param_param_index。
"""
pi_arg: int = self._find_ctor_type_param_param_index(class_name, tp_name)
if pi_arg < 0:
return -1
return pi_arg - 1
def _ctor_init_arg_slot_by_name(self, class_name: str,
kw_name: str) -> int:
"""按形参名把关键字实参定位到非 self 形参序号(= 位置实参槽位)
返回 >= 0 的槽位下标;模板/__init__ 缺失或无形参名 kw_name → -1。
场景:`Box(v=42)` 的 v → 槽 0;`Pair(b="a", a=1)` 的 a → 槽 0、b → 槽 1
(乱序关键字必须按名定位,不能按出现顺序当位次)。
按名匹配先例:CallGenCall._translate_method_call 的关键字分支
(CallGenCall.vp:1409-1418 遍历函数形参名逐个匹配关键字名)。
"""
if class_name is None or kw_name is None:
return -1
plist_sb: list[ast.AST | t.CPtr] | t.CPtr = self._get_ctor_init_params(class_name)
if plist_sb is None:
return -1
pn_sb: sizet = len(plist_sb)
pi_sb: sizet
for pi_sb in range(pn_sb):
if pi_sb == 0:
continue # self 不是实参槽位
pa_sb: ast.AST | t.CPtr = plist_sb.get(pi_sb)
if pa_sb is None or pa_sb.kind() != ast.ASTKind.Arg:
continue
ag_sb: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(pa_sb)
if ag_sb.arg is not None and string.strcmp(ag_sb.arg, kw_name) == 0:
return int(pi_sb) - 1
return -1
def _find_ctor_type_param_kw_arg_index(self, class_name: str,
tp_name: str,
keywords: list[ast.AST | t.CPtr] | t.CPtr,
kw_count: sizet,
pos_count: int) -> int:
"""仅关键字实参的泛型构造:类型形参 tp_name 对应的关键字实参下标
返回 keywords 列表下标(0 = 第 1 个关键字实参);找不到返回 -1。
场景:`Box(v=42)`(__init__(self, v: T))无位置实参,T 只能从关键字实参
推断——不能按「关键字出现顺序」当类型形参位次(`Pair(b="a", a=1)` 乱序
会把 b 的值当成第 1 个类型实参的来源),必须按 __init__ 形参名定位
(与 _find_ctor_type_param_arg_index 共用形参序号遍历)。
pos_count:位置实参个数——该形参位已被位置实参占用时返回 -1(位置优先,
与 _translate_method_call 的"位置参数优先、其余按名匹配"一致)。
重复关键字名:parser 不做重复检测(parser.vp:877-889 直接 append),
沿用仓库既有处理"按名取首个匹配"(CallGenCall.vp:1412-1418)。
"""
if class_name is None or tp_name is None or keywords is None:
return -1
pi_kw: int = self._find_ctor_type_param_param_index(class_name, tp_name)
if pi_kw < 1:
return -1 # 未找到,或落在 self 位(0 不是实参)
if pi_kw - 1 < pos_count:
return -1 # 该形参位已被位置实参占用
plist_kw: list[ast.AST | t.CPtr] | t.CPtr = self._get_ctor_init_params(class_name)
if plist_kw is None:
return -1
pa_kw: ast.AST | t.CPtr = plist_kw.get(sizet(pi_kw))
if pa_kw is None or pa_kw.kind() != ast.ASTKind.Arg:
return -1
ag_kw: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(pa_kw)
if ag_kw.arg is None:
return -1
ki_kw: sizet
for ki_kw in range(kw_count):
kw_tp: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_kw))
if kw_tp is None or kw_tp.arg is None or kw_tp.value is None:
continue
if string.strcmp(kw_tp.arg, ag_kw.arg) == 0:
return int(ki_kw)
return -1
def _infer_ctor_type_args_from_ctx(self, pool: rowptr[memhub.MemBuddy],
trans: HT.Translator | t.CPtr,
class_name: str,
tp_count: int,
cl: ast.Call | t.CPtr) -> list[str] | t.CPtr:
"""从「赋值目标注解 / 函数返回注解」上下文取泛型构造的类型实参
场景:`s: Stack[int] = Stack()`(__init__ 无参 ⇒ 实参推断不到 T)、
`def f() -> Stack[int]: return Stack()`。注解里已显式写出 T,必须按它
特化——这不是"取不到就默认 int"的兜底,而是用户显式写下的类型实参。
来源(两者都要求本次 Call 是注解语句的**直接值**,identity 判定先例:
CallGenCBuiltin 的 CurAssignNode 判定 L122-125):
① trans.CurAssignAnnot:AnnAssign 赋值目标注解(AssignGenMixin 在
翻译 RHS 前写入,L1760)+ trans.CurAssignNode 为本次 Call;
② trans.CurFuncRetAnnot:当前函数返回注解(FuncGenDef 进入函数体时
写入)+ trans.CurRetNode 为本次 Call。
注解 → 类型实参的解析复用 _extract_type_args_from_slice(与
_prespecialize_generic_annotation / translate_call 的 Subscript 分支
同一函数,不另写一套注解解析);返回的列表与显式 `Stack[int](...)`
完全相同 ⇒ _specialize_generic_class 幂等,特化名一致。
返回 None = 上下文不适用(调用方维持 fail-fast)。
"""
if pool is None or trans is None or class_name is None or cl is None:
return None
if tp_count <= 0:
return None
ctx_annot: ast.AST | t.CPtr = None
if trans.CurAssignNode is not None and uint64(cl) == uint64(trans.CurAssignNode):
ctx_annot = trans.CurAssignAnnot
if ctx_annot is None and trans.CurRetNode is not None \
and uint64(cl) == uint64(trans.CurRetNode):
ctx_annot = trans.CurFuncRetAnnot
if ctx_annot is None:
return None
# 取注解里的泛型 Subscript 一侧(与 _prespecialize_generic_annotation 同构:
# 支持 `X[T]` 与 `X[T] | t.CPtr` 两种形态)
spec_annot: ast.Subscript | t.CPtr = None
if ctx_annot.kind() == ast.ASTKind.Subscript:
spec_annot = (ast.Subscript | t.CPtr)(ctx_annot)
elif ctx_annot.kind() == ast.ASTKind.BinOp:
bop_ctx: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(ctx_annot)
if bop_ctx.op == ast.OpKind.BitOr:
if bop_ctx.left is not None and bop_ctx.left.kind() == ast.ASTKind.Subscript:
spec_annot = (ast.Subscript | t.CPtr)(bop_ctx.left)
elif bop_ctx.right is not None and bop_ctx.right.kind() == ast.ASTKind.Subscript:
spec_annot = (ast.Subscript | t.CPtr)(bop_ctx.right)
if spec_annot is None:
return None
# 注解必须与本次构造是同一个泛型类(不同类 ⇒ 上下文与本次构造无关)
sv_ctx: ast.AST | t.CPtr = spec_annot.value
if sv_ctx is None or sv_ctx.kind() != ast.ASTKind.Name:
return None
sn_ctx: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sv_ctx)
if sn_ctx.id is None or string.strcmp(sn_ctx.id, class_name) != 0:
return None
type_args_ctx: list[str] | t.CPtr = self._extract_type_args_from_slice(
pool, spec_annot.slice, trans._from_imports)
if type_args_ctx is None:
return None
# 类型实参个数必须与类型形参个数一致:不做补齐/截断(否则会用错特化)
if len(type_args_ctx) != sizet(tp_count):
return None
return type_args_ctx
def _translate_generic_ctor_call(self, pool: rowptr[memhub.MemBuddy],
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
spec_name: str,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
trans: HT.Translator | t.CPtr,
tmpl_name: str = None) -> llvmlite.Value | t.CPtr:
"""泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__"""
if pool is None or builder is None or mod is None or spec_name is None or cl is None:
return None
@@ -1023,16 +1188,31 @@ class CallGenCtor(CallGenBase.CallGenBase):
if tmp is None:
return None
# 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针)
# 翻译实参为参数指针数组(extra_args[slot] = Value 指针):
# 位置实参 → 槽 0..can-1;关键字实参 → 按 __init__ 形参名定位槽位
# ([C②] 与 _find_ctor_type_param_kw_arg_index 共用同一套形参遍历:
# Box(v=42) 的 v → 槽 0;Pair(b="a", a=1) 的 a → 槽 0、b → 槽 1。
# 关键字不能按"出现顺序"追加到位置实参之后——乱序会串位。
# 位置实参优先(先例:_translate_method_call L1406-1418 位置优先、
# 其余按形参名匹配)。此前只翻译 cl.args ⇒ 关键字实参被静默丢弃。)
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can: sizet = 0
if cargs is not None:
can = len(cargs)
keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
kw_count: sizet = 0
if keywords is not None:
kw_count = len(keywords)
extra_args: sizet | t.CPtr = pool.alloc(8 * 32)
if extra_args is None:
return None
string.memset(extra_args, 0, 8 * 32)
# 槽占用标志(1 字节/槽:0=空 1=已填),用于关键字定位后的连续性校验
arg_filled: sizet | t.CPtr = pool.alloc(32)
if arg_filled is None:
return None
string.memset(arg_filled, 0, 32)
for ai in range(can):
if ai >= 32:
@@ -1046,6 +1226,56 @@ class CallGenCtor(CallGenBase.CallGenBase):
builder, pool, mod, arg_node, None, 0, trans)
if arg_val is not None:
extra_args[ai] = sizet(arg_val)
arg_filled[ai] = 1
arg_max_filled: int = int(can) - 1
if kw_count > 0:
ki_slot: sizet
for ki_slot in range(kw_count):
kw_slot: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_slot))
if kw_slot is None or kw_slot.arg is None or kw_slot.value is None:
continue
slot_kw: int = self._ctor_init_arg_slot_by_name(tmpl_name, kw_slot.arg)
if slot_kw >= 32:
self.Gen.TypeGenErr.fatal_error(
kw_slot, "泛型构造实参超过 32 个上限", "TypeError")
continue
if slot_kw < 0:
# fail-fast:关键字名在 __init__ 形参中查无(含模板无 __init__/
# 模板名缺失)——静默丢弃会少传实参,__init__ 收到错位实参。
# 对齐 _translate_struct_ctor_kw 的"结构体 'X' 无字段 'kw'"。
self.Gen.TypeGenErr.fatal_error(
kw_slot,
f"泛型类 '{tmpl_name}' 的关键字实参 '{kw_slot.arg}' 无法定位到 __init__ 形参",
"TypeError")
continue
if arg_filled[sizet(slot_kw)] != 0:
# 该形参位已被位置实参/先前关键字占用:位置优先,本次跳过
# (先例 same as 上方:_translate_method_call 名匹配)
continue
kw_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
builder, pool, mod, kw_slot.value, None, 0, trans)
if kw_val is None:
continue
extra_args[sizet(slot_kw)] = sizet(kw_val)
arg_filled[sizet(slot_kw)] = 1
if slot_kw > arg_max_filled:
arg_max_filled = slot_kw
# 槽位必须连续(0..arg_max_filled 全满):出现空洞说明某形参既未给位置
# 实参也未给关键字实参(Python 会报缺参)——禁止把空洞当 0 传(会让
# __init__ 收到错位实参),fail-fast 暴露。
ci_hole: int = 0
while ci_hole <= arg_max_filled:
if arg_filled[sizet(ci_hole)] == 0:
self.Gen.TypeGenErr.fatal_error(
cl,
f"泛型类 '{tmpl_name}' 的关键字构造缺少前置形参(第 {ci_hole + 1} 个实参位置既无位置实参也无关键字实参)",
"TypeError")
break
ci_hole += 1
arg_count: int = 0
if arg_max_filled >= 0:
arg_count = arg_max_filled + 1
# 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针
# __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用
@@ -1056,7 +1286,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
has_new_flag = struct_entry.HasNew
if has_new_flag != 0:
new_ptr: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr(
pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans)
pool, builder, mod, spec_name, "__new__", tmp, extra_args, arg_count, trans)
if new_ptr is not None:
storage_ptr = new_ptr
# __new__ 只保证返回"实例存储指针",声明类型通常是
@@ -1076,8 +1306,8 @@ class CallGenCtor(CallGenBase.CallGenBase):
self.Gen.CallGenCall._call_method_on_ptr(
pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans)
# call __init__(storage_ptr, *args)
# call __init__(storage_ptr, *args)(arg_count = 槽位 0..已填最高槽)
self.Gen.CallGenCall._call_method_on_ptr(
pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans)
pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, arg_count, trans)
return storage_ptr
+27 -2
View File
@@ -120,8 +120,9 @@ class CallGenMixin(CallGenBase.CallGenBase):
# 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__
# 不能直接用 spec_name 作为 func_name(会走裸名调用路径,
# 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀)
# 末参传模板名:关键字实参需按 __init__ 形参名定位槽位
return self.Gen.CallGenCtor._translate_generic_ctor_call(
pool, builder, mod, spec_name, cl, trans)
pool, builder, mod, spec_name, cl, trans, gen_class_name)
else:
# 泛型类模板未找到:可能是泛型函数手动传类型参数调用 xxx[T](x)
# (对应 TPC _HandleGenericCallExplicitLlvm;TPV 无泛型函数特化,
@@ -418,6 +419,13 @@ class CallGenMixin(CallGenBase.CallGenBase):
# 下标与形参序号错位(Pair(1,"a") 误判为 Pair<str,str>)。
# 签名不可得(无 __init__/无 T 注解形参)时退化为同一
# 序号(第 tpi 个位置实参)。
# [C①] 注解上下文(赋值目标注解 / 函数返回注解)提供的
# 类型实参:优先级 = 显式 [...] > 位置/关键字实参推断 >
# 注解上下文 > fail-fast。仅当本次构造就是注解赋值/return
# 的直接值(identity 判定见 helper 内)时才返回非 None;
# 注解 → 类型实参的解析复用 _extract_type_args_from_slice。
ctx_args_bare: list[str] | t.CPtr = self.Gen.CallGenCtor._infer_ctor_type_args_from_ctx(
pool, trans, func_name, int(tp_count_bare), cl)
tpi_bare: sizet = 0
for tpi_bare in range(tp_count_bare):
aip_bare: int = self.Gen.CallGenCtor._find_ctor_type_param_arg_index(
@@ -435,6 +443,23 @@ class CallGenMixin(CallGenBase.CallGenBase):
if ais_bare < can:
ta_bare = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(
pool, cargs.get(ais_bare), func_name, trans)
if ta_bare is None:
# [C②] 仅关键字实参(Box(v=42)):按 __init__ 形参名
# 把该类型形参对应的关键字实参找出来再推断(关键字乱序
# 也能对齐;该形参位已被位置实参占用时返回 -1)。
kwi_bare: int = self.Gen.CallGenCtor._find_ctor_type_param_kw_arg_index(
func_name, tp_bare.get(tpi_bare),
keywords, kw_count, int(can))
if kwi_bare >= 0:
kwn_bare: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(
keywords.get(sizet(kwi_bare)))
if kwn_bare is not None and kwn_bare.value is not None:
ta_bare = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(
pool, kwn_bare.value, func_name, trans)
if ta_bare is None and ctx_args_bare is not None:
# [C①] 注解已显式给出类型实参(如
# s: Stack[int] = Stack())⇒ 用它特化,而非 fail-fast
ta_bare = ctx_args_bare.get(tpi_bare)
if ta_bare is None:
self.Gen.TypeGenErr.fatal_error(
cl,
@@ -447,7 +472,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
trans, func_name, inferred_args_bare)
if spec_name_bare is not None:
return self.Gen.CallGenCtor._translate_generic_ctor_call(
pool, builder, mod, spec_name_bare, cl, trans)
pool, builder, mod, spec_name_bare, cl, trans, func_name)
# REnum 变体构造检测: ClassName.VariantName(args...)
# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体
+6
View File
@@ -919,9 +919,13 @@ class FuncGenDef(CallGenBase.CallGenBase):
old_env_count: int = trans._closure_env_count
old_va_list_ptr: llvmlite.Value | t.CPtr = trans._va_list_ptr
old_vararg_name: str = trans._vararg_name
# 返回注解上下文([C①] 裸名泛型构造的类型实参回退来源之一):
# 进入函数体前记录本函数返回注解,退出时恢复外层函数的值
old_ret_annot: ast.AST | t.CPtr = trans.CurFuncRetAnnot
trans._cur_func = func
trans._cur_builder = func_builder
trans.CurFuncRetAnnot = fd.returns
# 清空 global/nonlocal 名称集合(新函数作用域)
GenApi.clear_scope_names(trans)
# 重置链内 nonlocal 堆预建标志(每函数只建一次;多嵌套函数定义
@@ -1095,6 +1099,8 @@ class FuncGenDef(CallGenBase.CallGenBase):
trans._closure_env_count = old_env_count
trans._va_list_ptr = old_va_list_ptr
trans._vararg_name = old_vararg_name
# 交还外层函数的返回注解([C①] 见上方 old_ret_annot)
trans.CurFuncRetAnnot = old_ret_annot
# 恢复外层函数(调用方)的 EH 输出参数——本函数体内的 raise 传播
# 使用本函数参数,翻译结束必须交还外层作用域,否则嵌套函数/链式
# 调用后 EH 状态残留导致 raise 写入错误的 out 指针。
+5
View File
@@ -558,9 +558,14 @@ class StmtGenCifMixin:
cur_func_rv: llvmlite.Function | t.CPtr = trans._cur_func
if cur_func_rv is not None:
ret_val_ty = llvmlite.function_get_ret_ty(cur_func_rv)
# [C①] 返回注解上下文:记录本次 return 的直接值节点,供裸名泛型
# 构造(`-> Stack[int]` 里 `return Stack()`)用 CurFuncRetAnnot
# 里的类型实参特化;仅该直接值生效(identity 判定在 CallGenCtor)。
trans.CurRetNode = rt.value
val = self.Gen.ExprGen.translate_value(
builder, pool, mod, rt.value,
trans._funcs, trans._func_count, trans, ret_val_ty)
trans.CurRetNode = None
# val 为 None 时(裸 return):检查当前函数返回类型
# void 函数(如 __init__/__before_init__)生成 ret void,
+10
View File
@@ -155,6 +155,16 @@ class Translator:
# _infer_deref_target_type 的直接 RHS 检查)。
CurAssignNode: ast.AST | t.CPtr
# 当前函数的返回注解节点(translate_function_def 进入函数体前设置,退出时
# 恢复外层函数的值)。供裸名泛型构造回退推断类型实参:`-> Stack[int]` 里
# `return Stack()` 用注解里的 int 特化(与 CurAssignAnnot 同类的上下文通道)。
CurFuncRetAnnot: ast.AST | t.CPtr
# 当前 Return 语句的直接值节点(translate_return 翻译返回值前设置,翻译后
# 清除)。与 CurAssignNode 同款的 identity 判定:仅「裸名泛型构造就是 return
# 的直接值」时才用 CurFuncRetAnnot(嵌套调用如 return f(Stack()) 不推断)。
CurRetNode: ast.AST | t.CPtr
# 循环控制流目标(break/continue)
_break_bb: llvmlite.BasicBlock | t.CPtr
_continue_bb: llvmlite.BasicBlock | t.CPtr