From 3ed5891de2f53680d2d4e8ab2a8842f9e4ce8326 Mon Sep 17 00:00:00 2001 From: dimgigov Date: Tue, 9 Jun 2026 15:56:16 +0300 Subject: [PATCH] fix(selfhost): block scoping for if/while/loop/match bodies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create child scope in Sema_CheckBlock for every block, matching bootstrap sema.nim behavior (newScope for ekBlock). - Fixes "var scoping bug in selfhost sema" where variables declared with var inside if/while blocks shared parent function scope, causing duplicate-definition errors between sibling if/else blocks, and C scoping mismatch between user variables and compiled output. - Remove stale workaround comments from lib/Json.bux (let instead of var inside if blocks — no longer needed). - Update sema.bux TODO comment for type table. --- lib/Json.bux | 2 -- src/sema.bux | 15 ++++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/Json.bux b/lib/Json.bux index c783818..e0ecd68 100644 --- a/lib/Json.bux +++ b/lib/Json.bux @@ -89,7 +89,6 @@ func Json_ArrayGet(v: JsonValue, index: uint) -> JsonValue { func Json_ArrayPush(self: *JsonValue, val: JsonValue) { if self.tag != JsonTagArray { return; } if self.arrLen >= self.arrCap { - // Compute new capacity (avoid var scoping bug in selfhost sema) let arrNewCap: uint = self.arrCap; if arrNewCap == 0 { self.arrCap = 4; @@ -145,7 +144,6 @@ func Json_ObjectSet(self: *JsonValue, key: String, val: JsonValue) { i = i + 1; } if self.objLen >= self.objCap { - // Compute new capacity (avoid var scoping bug in selfhost sema) let objNewCap: uint = self.objCap; if objNewCap == 0 { self.objCap = 4; diff --git a/src/sema.bux b/src/sema.bux index f02a1b5..e39f807 100644 --- a/src/sema.bux +++ b/src/sema.bux @@ -134,10 +134,9 @@ func Sema_ResolveType(sema: *Sema, te: *TypeExpr) -> int { if String_Eq(name, "float64") { return tyFloat64; } if String_Eq(name, "float") { return tyFloat64; } - // Check type table for user-defined types (StringMap not yet supported) - // TODO: re-enable when StringMap generic is available - // if sema.typeTable != null as *void { ... } - return tyNamed; // assume named type + // Type resolution uses scope-based lookup via Sema_CollectGlobals + // TODO: add StringMap-based type table for faster named-type validation + return tyNamed; } // --------------------------------------------------------------------------- @@ -177,14 +176,16 @@ func Sema_TypeName(kind: int) -> String { func Sema_CheckBlock(sema: *Sema, block: *Block) { if block == null as *Block { return; } - // Use current scope directly — only function bodies create new scopes. - // This matches Nim bootstrap behavior and fixes variable visibility - // in nested blocks (if/while bodies). + // Create child scope for block (matching Nim bootstrap behavior) + var blockScope: Scope = Scope_NewChild(sema.scope); + let prevScope: *Scope = sema.scope; + sema.scope = &blockScope; var stmt: *Stmt = block.firstStmt; while stmt != null as *Stmt { Sema_CheckStmt(sema, stmt); stmt = stmt.nextStmt; } + sema.scope = prevScope; } // ---------------------------------------------------------------------------