diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index e9ac946..32dfe68 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -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 \ No newline at end of file diff --git a/App/lib/core/Gen/Call/CallGenMixin.vp b/App/lib/core/Gen/Call/CallGenMixin.vp index 76d639c..8b4f2a3 100644 --- a/App/lib/core/Gen/Call/CallGenMixin.vp +++ b/App/lib/core/Gen/Call/CallGenMixin.vp @@ -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)。 # 签名不可得(无 __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 变体 diff --git a/App/lib/core/Gen/Func/FuncGenDef.vp b/App/lib/core/Gen/Func/FuncGenDef.vp index e0af937..ab4003f 100644 --- a/App/lib/core/Gen/Func/FuncGenDef.vp +++ b/App/lib/core/Gen/Func/FuncGenDef.vp @@ -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 指针。 diff --git a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp index 8157d4f..b81b600 100644 --- a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp @@ -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, diff --git a/App/lib/core/Gen/Translator.vp b/App/lib/core/Gen/Translator.vp index e6d727c..0eddfe2 100644 --- a/App/lib/core/Gen/Translator.vp +++ b/App/lib/core/Gen/Translator.vp @@ -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