feat(selfhost): double mutable borrow detection in @[Checked] functions

Detect when the same variable is passed as &mut argument twice
in a single function call (e.g. Swap(&x, &x)) inside checked functions.
Matches bootstrap sema.nim behavior (lines 1078-1089).
This commit is contained in:
2026-06-09 17:32:21 +03:00
parent f809827bea
commit 41c0fb1d6f
+28
View File
@@ -388,6 +388,34 @@ func Sema_CheckExpr(sema: *Sema, expr: *Expr) -> int {
discard Sema_CheckExpr(sema, arg.expr); discard Sema_CheckExpr(sema, arg.expr);
arg = arg.next; arg = arg.next;
} }
// Borrow check: reject double mutable borrow in @[Checked] functions
if sema.checkedFunc {
var a: *ExprList = expr.callArgs;
var ai: int = 0;
while a != null as *ExprList {
if a.expr != null as *Expr && a.expr.kind == ekUnary && a.expr.intValue == tkAmp {
if a.expr.child1 != null as *Expr && a.expr.child1.kind == ekIdent {
let name1: String = a.expr.child1.strValue;
var b: *ExprList = a.next;
var bi: int = ai + 1;
while b != null as *ExprList {
if b.expr != null as *Expr && b.expr.kind == ekUnary && b.expr.intValue == tkAmp {
if b.expr.child1 != null as *Expr && b.expr.child1.kind == ekIdent {
if String_Eq(name1, b.expr.child1.strValue) {
Sema_EmitError(sema, expr.line, expr.column,
String_Concat("mutable borrow conflict: multiple &mut references to '", String_Concat(name1, "'")));
}
}
}
b = b.next;
bi = bi + 1;
}
}
}
a = a.next;
ai = ai + 1;
}
}
// Indirect call through function-typed value // Indirect call through function-typed value
if calleeType == tyFunc { if calleeType == tyFunc {
if expr.child1.refType != null as *TypeExpr && expr.child1.refType.kind == tekFunc { if expr.child1.refType != null as *TypeExpr && expr.child1.refType.kind == tekFunc {