feat(obs): move own values into fields and elements
`A.n = B` / `arr[i] = B` now transfer ownership: the source shadow stops owning the object (no double free) and later uses of B fail as moved. The language server marks the source moved too.
This commit is contained in:
1 parent
17c7e1f896
commit
6f45fc016b
2 files changed
+29
No files matched your search
@@ -1075,6 +1075,23 @@ novirtual class AssignGenMixin:
|
||||
return (ast.Name*)(uo_b.operand).id
|
||||
return None
|
||||
|
||||
def _move_out_assigned_source(self, trans: HT.Translator*, rhs: ast.AST*,
|
||||
pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*) -> int:
|
||||
"""OBS move: after `field = ownVar` / `arr[i] = ownVar`, the source no longer owns the value."""
|
||||
if trans is None or rhs is None or trans.StrictOBS == 0: return 0
|
||||
if rhs.kind() != ast.ASTKind.Name: return 0
|
||||
src_nm: ast.Name* = ast.Name*(rhs)
|
||||
if src_nm.id is None: return 0
|
||||
src_slot: mlirlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, src_nm.id)
|
||||
if src_slot is None: return 0
|
||||
if self.Gen.VarGen._SlifeOwned(src_slot) == 0: return 0
|
||||
# Cancel the source's scope-exit release (the field/element now holds the pointer) and
|
||||
# reject later uses of the moved binding.
|
||||
ssh: mlirlite.Value* = self.Gen.VarGen._SlifeShadow(src_slot)
|
||||
if ssh is not None: self.Gen.VarGen._SlifeNoteStore(pool, builder, ssh, 0)
|
||||
self.Gen.VarGen._FreedMark(src_slot)
|
||||
return 1
|
||||
|
||||
def _is_ptr_element_annotation(self, annot: ast.AST*) -> int:
|
||||
"""Return 1 if the annotation is a bytes* or str* form."""
|
||||
if annot is None: return 0
|
||||
@@ -3838,6 +3855,7 @@ novirtual class AssignGenMixin:
|
||||
vol_sw: int = 0
|
||||
if sub_wr is not None: vol_sw = self.Gen.ExprGenAttr.base_pointee_is_volatile(pool, trans, sub_wr.value)
|
||||
mlirlite.build_store(builder, store_val, elem_ptr, vol_sw)
|
||||
self._move_out_assigned_source(trans, asgn.value, pool, builder)
|
||||
continue
|
||||
# get_subscript_ptr returned None: try the __setitem__ overload for custom classes
|
||||
sub_asgn: ast.Subscript* = ast.Subscript*(target)
|
||||
@@ -3920,6 +3938,7 @@ novirtual class AssignGenMixin:
|
||||
if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None:
|
||||
if elem_ptr_gen.Ty.Pointee != 0: store_val_gen = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, elem_ptr_gen.Ty.Pointee, node, trans)
|
||||
mlirlite.build_store(builder, store_val_gen, elem_ptr_gen)
|
||||
self._move_out_assigned_source(trans, asgn.value, pool, builder)
|
||||
setitem_done = 1
|
||||
if setitem_done == 0: self.Gen.TypeGenErr.fatal_error(target, "subscript ptr is None")
|
||||
continue
|
||||
@@ -4018,6 +4037,7 @@ novirtual class AssignGenMixin:
|
||||
if at_wr is not None:
|
||||
if self.Gen.ExprGenAttr.base_pointee_is_volatile(pool, trans, at_wr.value) != 0: vol_fw = 1
|
||||
mlirlite.build_store(builder, store_val, field_ptr, vol_fw)
|
||||
self._move_out_assigned_source(trans, asgn.value, pool, builder)
|
||||
continue
|
||||
# Guard: field_ptr is None -> build a detailed error message
|
||||
attr_node: ast.Attribute* = ast.Attribute*(target)
|
||||
|
||||
@@ -1645,6 +1645,15 @@ def _WalkChecks(pool: memhub.MemManager*, doc: LspDocuments.LspDocument*,
|
||||
tn_m: ast.Name* = ast.Name*(tm)
|
||||
if tn_m.id is not None and _OwnHas(tn_m.id) != 0:
|
||||
_MovedAdd(pool, sn_a.id)
|
||||
# `obj.field = ownVar` / `arr[i] = ownVar`: the field/element takes ownership.
|
||||
ti_m2: int = 0
|
||||
while ti_m2 < int(len(asn.targets)):
|
||||
tm2: ast.AST* = asn.targets.get(sizet(ti_m2))
|
||||
ti_m2 += 1
|
||||
if tm2 is not None and (tm2.kind() == ast.ASTKind.Attribute
|
||||
or tm2.kind() == ast.ASTKind.Subscript):
|
||||
_MovedAdd(pool, sn_a.id)
|
||||
break
|
||||
ti_c: int = 0
|
||||
while ti_c < int(len(asn.targets)):
|
||||
tc: ast.AST* = asn.targets.get(sizet(ti_c))
|
||||
|
||||
Reference in new issue
Block a user