feat: for-in range loops in selfhost + bootstrap

- Parser: add parseRange for selfhost (.. / ..=)
- Sema: determine loop variable type from range bounds
- HIR Lower: desugar range for-in to while loop with counter
- Bootstrap sema: fix range-based for variable type (was unknown)
- Selfhost loop remains deterministic
This commit is contained in:
2026-06-09 21:53:12 +03:00
parent 6414ef236b
commit 74db8a5790
4 changed files with 194 additions and 4 deletions
+27 -1
View File
@@ -828,7 +828,7 @@ func Sema_CheckStmt(sema: *Sema, stmt: *Stmt) {
// For
if kind == skFor {
discard Sema_CheckExpr(sema, stmt.child1);
let iterType: int = Sema_CheckExpr(sema, stmt.child1);
var forScope: Scope = Scope_NewChild(sema.scope);
var loopSym: Symbol;
loopSym.kind = skVar;
@@ -839,6 +839,32 @@ func Sema_CheckStmt(sema: *Sema, stmt: *Stmt) {
loopSym.isMutable = true;
loopSym.isPublic = false;
loopSym.decl = null as *Decl;
// Determine loop variable type from iterator expression
if stmt.child1 != null as *Expr {
// Range-based: type from lower bound (selfhost parses .. as ekBinary)
if stmt.child1.kind == ekRange || (stmt.child1.kind == ekBinary && (stmt.child1.intValue == tkDotDot || stmt.child1.intValue == tkDotDotEqual)) {
let boundType: int = Sema_CheckExpr(sema, stmt.child1.child1);
loopSym.typeKind = boundType;
}
// Array-based: extract element type from Array<T> annotation
if stmt.child1.kind == ekIdent {
let sym: Symbol = Scope_Lookup(sema.scope, stmt.child1.strValue);
if sym.refType != null as *TypeExpr {
if String_Eq(sym.refType.typeName, "Array") && sym.refType.typeArgCount > 0 {
let elemTe: *TypeExpr = bux_alloc(sizeof(TypeExpr)) as *TypeExpr;
elemTe.kind = tekNamed;
elemTe.typeName = sym.refType.typeArgName0;
elemTe.line = stmt.line;
elemTe.column = stmt.column;
loopSym.typeKind = Sema_ResolveType(sema, elemTe);
loopSym.typeName = sym.refType.typeArgName0;
loopSym.refType = elemTe;
}
}
}
}
discard Scope_Define(&forScope, loopSym);
let prevScope: *Scope = sema.scope;
sema.scope = &forScope;