feat(obs): bind case Some(&v) by reference

The capture is a read-only reference to the payload (RefKind=1) and registers a borrow of the subject base, so the owner cannot be del-ed while the arm runs and writes through the capture are rejected. The language server binds the capture so v.a resolves.
This commit is contained in:
TermiNexus committed 2026-11-04 16:01:42 +08:00
1 parent b9d84c6bda
commit 40691567f5
2 files changed
+46

No files matched your search

+27
View File
@@ -318,6 +318,17 @@ novirtual class MatchGenMixin:
if pk == 2 and (self._pattern_is_nil(mc.pattern) != 0 or self._pattern_is_none_singleton(mc.pattern) != 0): return 1
return 0
def _borrow_owner_name(self, expr: ast.AST*) -> str:
"""Base binding name of a match subject (`_U` for `_U.n`), used as the borrow owner."""
if expr is None: return None
if expr.kind() == ast.ASTKind.Name:
return (ast.Name*)(expr).id
if expr.kind() == ast.ASTKind.Attribute:
return self._borrow_owner_name((ast.Attribute*)(expr).value)
if expr.kind() == ast.ASTKind.Subscript:
return self._borrow_owner_name((ast.Subscript*)(expr).value)
return None
# _handle_optional_ptr_match - match over a nullable pointer (`own U?` / `T?`):
# Some(v) -> non-null branch, v = the pointer; None / Nil() -> null branch.
def _handle_optional_ptr_match(self, trans: HT.Translator*, node: ast.Match*, subject_val: mlirlite.Value*) -> int:
@@ -398,6 +409,22 @@ novirtual class MatchGenMixin:
mlirlite.build_store(builder, subject_val, slot)
self.Gen.VarGen.define_var(trans.SymTab, ma_s.name, slot)
self.Gen.VarGen.set_var_life(trans.SymTab, ma_s.name, GenTypes.LIFE_FRAME)
elif sub is not None and sub.kind() == ast.ASTKind.UnaryOp:
# `Some(&v)`: bind the payload by reference (a borrow, not an owner).
uo_s: ast.UnaryOp* = ast.UnaryOp*(sub)
if uo_s.op == ast.OpKind.AddrOf and uo_s.operand is not None \
and uo_s.operand.kind() == ast.ASTKind.Name:
nm_s: ast.Name* = ast.Name*(uo_s.operand)
if nm_s.id is not None:
slot2: mlirlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, ptr_ty)
if slot2 is not None:
mlirlite.build_store(builder, subject_val, slot2)
self.Gen.VarGen.define_var(trans.SymTab, nm_s.id, slot2)
self.Gen.VarGen.set_var_life(trans.SymTab, nm_s.id, GenTypes.LIFE_FRAME)
self.Gen.VarGen.set_var_ref_kind(trans.SymTab, nm_s.id, 1)
own_r: str = self._borrow_owner_name(node.subject)
if own_r is not None:
self.Gen.StmtGen._BorrowAdd(trans, own_r, nm_s.id)
if some_body is not None and some_body.children is not None:
bi: int = 0
while bi < int(len(some_body.children)):
+19
View File
@@ -1134,6 +1134,16 @@ def _WalkPattern(pool: memhub.MemManager*, a: LspAnalysis*, scope: LspScope*,
_WalkPattern(pool, a, scope, mc.kwd_patterns.get(sizet(pi)))
pi += 1
return
if k == ast.ASTKind.UnaryOp:
# `case Some(&v)`: v is a reference binding inside the case body.
uo_wp: ast.UnaryOp* = (ast.UnaryOp*)(node)
if uo_wp.op == ast.OpKind.AddrOf and uo_wp.operand is not None \
and uo_wp.operand.kind() == ast.ASTKind.Name:
nm_wp: ast.Name* = (ast.Name*)(uo_wp.operand)
if nm_wp.id is not None:
_Declare(pool, a, scope, nm_wp.id, LSP_KIND_VARIABLE, node,
nm_wp.lineno, nm_wp.col_offset, None)
return
if k == ast.ASTKind.MatchAs:
ma_p: ast.MatchAs* = (ast.MatchAs*)(node)
if ma_p.pattern is not None:
@@ -1352,6 +1362,15 @@ def _WalkStmt(pool: memhub.MemManager*, a: LspAnalysis*, scope: LspScope*,
if ma_b.name is not None:
bs: LspSymbol* = _FindSymbol(scope, ma_b.name)
if bs is not None and bs.type_sym is None: bs.type_sym = subj_ts
elif sp is not None and sp.kind() == ast.ASTKind.UnaryOp:
# `case Some(&v)`: bind v through the subject's class too.
uo_b: ast.UnaryOp* = (ast.UnaryOp*)(sp)
if uo_b.op == ast.OpKind.AddrOf and uo_b.operand is not None \
and uo_b.operand.kind() == ast.ASTKind.Name:
nm_b: ast.Name* = (ast.Name*)(uo_b.operand)
if nm_b.id is not None:
bs2: LspSymbol* = _FindSymbol(scope, nm_b.id)
if bs2 is not None and bs2.type_sym is None: bs2.type_sym = subj_ts
_WalkExpr(pool, a, scope, mc.guard)
_WalkBody(pool, a, scope, mc.children)
i += 1