From ab30b264fc9286e8dbf224626dae2bf36d1a675a Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 9 Oct 2026 14:55:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(gen):=20P3=20=E8=A6=86=E7=9B=96=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=E5=BD=A2=E6=80=81=E7=9A=84=E5=B1=9E=E6=80=A7/?= =?UTF-8?q?=E4=B8=8B=E6=A0=87=E7=9B=AE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - translate_annassign 原先对非 Name 目标直接 return 0,obj.f: T = v / rr[i]: T = v 整条语句被静默丢弃(既不报错也不写出) - 新增 _translate_lvalue_annassign:解析注解(先特化泛型)→ get_attribute_ptr / get_subscript_ptr 求左值指针 → 走同一处 P3 长命左值检查 → RHS 以注解为靶型求值 → coerce_to_type 后写出;const / volatile / f-string 逃逸与普通 Assign 同口径 - 所有失败路径 fail-fast,不再有静默丢语句 --- App/lib/core/Gen/AssignGenMixin.vp | 77 +++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 02dc840..9bca80d 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1580,7 +1580,10 @@ novirtual class AssignGenMixin: if aa is None: return 0 target: ast.AST* = aa.target - if target is None or target.kind() != ast.ASTKind.Name: return 0 + if target is None: return 0 + # 属性/下标目标(`obj.f: T = v` / `arr[i]: T = v`):走独立路径——不建局部变量,而是按注解 + # 类型对既有存储做一次"带 P3 长命左值检查"的写出。原先这里直接 return 0,整条语句被**静默丢弃**。 + if target.kind() != ast.ASTKind.Name: return self._translate_lvalue_annassign(trans, aa, target) nm: ast.Name* = ast.Name*(target) if nm.id is None: return 0 @@ -2000,6 +2003,78 @@ novirtual class AssignGenMixin: return 0 + # _translate_lvalue_annassign - 注解赋值的**属性/下标目标**:`obj.f: T = v` / `arr[i]: T = v`。 + # 与 Name 目标同口径:注解是源码级权威类型(RHS 以它为靶型求值);并且必须过 P3 + # "长命左值不得接收本帧栈地址"的检查(= propagate_life 的非 Name 分支)。 + # 存储目标复用既有左值指针求解:Attribute → get_attribute_ptr,Subscript → get_subscript_ptr。 + def _translate_lvalue_annassign(self, trans: HT.Translator*, aa: ast.AnnAssign*, target: ast.AST*) -> int: + """注解赋值的属性/下标目标;0=完成""" + if trans is None or aa is None or target is None: return 0 + tk: int = target.kind() + if tk != ast.ASTKind.Attribute and tk != ast.ASTKind.Subscript: + self.Gen.TypeGenErr.fatal_error(target, "the target of an annotated assignment must be a variable, an attribute or a subscript", "SyntaxError") + return 0 + pool: memhub.MemBuddy* = trans.Pool + builder: mlirlite.IRBuilder* = trans._cur_builder + mod: mlirlite.LLVMModule* = trans.Module + annot: ast.AST* = aa.annotation + if annot is None: + self.Gen.TypeGenErr.fatal_error(aa, "AnnAssign is missing a type annotation", "SyntaxError") + return 0 + # 与 Name 路径同口径解析注解:先特化泛型(避免 list[X] 退化成裸 list*),解析失败即 fail-fast。 + self.Gen.TypeGenResolve.reject_ref_marker_position(annot, trans._imported_modules, "an annotated assignment to an attribute/subscript") + self._prespecialize_generic_annotation(trans, pool, annot) + ann_ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, annot, trans._imported_modules, trans._from_imports, trans, 0) + if ann_ty is None: + self.Gen.TypeGenErr.fatal_error(aa, "cannot resolve the annotation type of an annotated assignment to an attribute/subscript", "TypeError") + return 0 + if self.Gen.StmtGenDecl._is_void_type(ann_ty) != 0: + self.Gen.TypeGenErr.fatal_error(aa, "cannot assign to an attribute/subscript of void type (void may only be used for void* and typedef aliases)", "TypeError") + return 0 + # 左值存储指针:属性/下标各走既有求解器。失败一律 fail-fast——绝不静默丢掉整条语句。 + is_attr: int = 0 + ptr: mlirlite.Value* = None + if tk == ast.ASTKind.Attribute: + is_attr = 1 + at_lv: ast.Attribute* = ast.Attribute*(target) + if at_lv.attr is not None and self.Gen.ExprGenAttr.attr_field_is_const(pool, trans, target) != 0: + self.const_assign_fail(target, "field assignment", at_lv.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, target)) + ptr = self.Gen.ExprGenAttr.get_attribute_ptr(builder, pool, mod, target, trans) + else: + ptr = self.Gen.ExprGenName.get_subscript_ptr(builder, pool, mod, target, trans) + if ptr is None or ptr.Ty is None or ptr.Ty.Pointee == 0: + self.Gen.TypeGenErr.fatal_error(target, "cannot resolve the storage of the annotated assignment target (the attribute/subscript pointer or its element type is missing)", "TypeError") + return 0 + target_ty: mlirlite.LLVMType* = ptr.Ty.Pointee + # P3:左值存储比右值长命时,右值不得交出本帧栈地址(如 `h.p: T* = &local`)。 + self._fail_if_lvalue_outlives_rhs(trans, target, aa.value, target_ty) + # 与普通 Assign 同口径:f-string 结果是函数内临时量,写出即悬垂。 + if aa.value is not None: + if is_attr != 0: GenApi.fail_if_fstring_escape(aa.value, "field assignment") + else: GenApi.fail_if_fstring_escape(aa.value, "element assignment") + # RHS 以注解靶型求值(CurAssignAnnot/CurAssignNode 供裸泛型构造推断;求值完即复位,不跨语句泄漏)。 + trans.CurAssignAnnot = annot + trans.CurAssignNode = aa.value + rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, ann_ty, "annotated assignment to an attribute/subscript") + trans.CurAssignAnnot = None + trans.CurAssignNode = None + if rhs_val is None: + self.Gen.TypeGenErr.fatal_error(aa, "the right-hand side of the annotated assignment to an attribute/subscript could not be translated", "TypeError") + return 0 + store_val: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, aa, trans) + if store_val is None: + self.Gen.TypeGenErr.fatal_error(aa, "type coercion failed for the annotated assignment to an attribute/subscript", "TypeError") + return 0 + # t.CVolatile 字段 / rawptr[t.CVolatile|T] 基址:写出同样带 volatile。 + vol_lv: int = 0 + if is_attr != 0: + vol_lv = self.Gen.ExprGenAttr.attr_field_is_volatile(pool, trans, target) + else: + sub_lv: ast.Subscript* = ast.Subscript*(target) + if sub_lv.value is not None: vol_lv = self.Gen.ExprGenAttr.base_pointee_is_volatile(pool, trans, sub_lv.value) + mlirlite.build_store(builder, store_val, ptr, vol_lv) + return 0 + # translate_assign - handle an Assign statement; returns the number of new variables def translate_assign(self, trans: HT.Translator*, node: ast.AST*) -> int: """Translate an Assign statement; return the number of new variables."""