feat(gen): P3 覆盖注解形态的属性/下标目标

- 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,不再有静默丢语句
This commit is contained in:
TermiNexus committed 2026-10-09 14:55:10 +08:00
1 parent d926987d44
commit ab30b264fc
1 file changed
+76 -1
+76 -1
View File
@@ -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."""