From 40691567f593badd69204e214e8502ff16e18d7b Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 4 Nov 2026 16:01:42 +0800 Subject: [PATCH] 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. --- App/lib/core/Gen/MatchGenMixin.vp | 27 +++++++++++++++++++++++++++ App/lib/lsp/LspSymbols.vp | 19 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/App/lib/core/Gen/MatchGenMixin.vp b/App/lib/core/Gen/MatchGenMixin.vp index 32190ed..3ab52b3 100644 --- a/App/lib/core/Gen/MatchGenMixin.vp +++ b/App/lib/core/Gen/MatchGenMixin.vp @@ -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)): diff --git a/App/lib/lsp/LspSymbols.vp b/App/lib/lsp/LspSymbols.vp index 65d7b5c..f34ad34 100644 --- a/App/lib/lsp/LspSymbols.vp +++ b/App/lib/lsp/LspSymbols.vp @@ -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