feat: match guards, HOF inference, ownership C.2/C.3, LSP sema hover

Sessions 18–23 quality work:

- B.3c match arm guards + sequential found-flag lower (bootstrap + selfhost)
- Generic HOF type inference (Array/Iter map/filter/fold without type args)
- Pattern binding shadowing via unique C locals (__pN_src)
- Ownership C.2 exclusive &mut data-flow + C.4 goldens; *p= store-through fix
- Ownership C.3 auto-drop on early return/branches: scoped defers, move-on-return,
  Drop monomorphization, materialize return before Drop
- LSP 0.3.0: hover from real sema types
- Examples and QUALITY_PLAN session log; selfhost-loop identical
This commit is contained in:
2026-07-18 21:52:14 +03:00
parent 66f11d1869
commit 3eb1ad3a82
25 changed files with 2246 additions and 457 deletions
+34 -2
View File
@@ -58,14 +58,27 @@ func parserPeek(p: *Parser, ahead: int) -> int {
return tkEndOfFile;
}
// Lookahead to determine if '<' starts a type argument list.
// Lookahead to determine if '<' starts a type argument list (`Foo<int>`).
// Must not treat value comparisons `x < 0` as generics when a later `x > 0`
// exists (e.g. multiple match arm guards).
func parserIsTypeArgListAhead(p: *Parser) -> bool {
if !parserCheck(p, tkLt) { return false; }
var depth: int = 0;
var ahead: int = 0;
while true {
let kind: int = parserPeek(p, ahead);
if kind == tkEndOfFile || kind == tkLBrace || kind == tkSemicolon {
// Hard stops: cannot appear inside <...> type args
if kind == tkEndOfFile || kind == tkLBrace || kind == tkRBrace || kind == tkSemicolon
|| kind == tkFatArrow || kind == tkIf || kind == tkElse || kind == tkWhile
|| kind == tkFor || kind == tkMatch || kind == tkReturn || kind == tkLet || kind == tkVar
|| kind == tkEq || kind == tkNe || kind == tkLe || kind == tkGe
|| kind == tkAmpAmp || kind == tkPipePipe || kind == tkAssign {
return false;
}
// Literals / arithmetic ⇒ value expression, not type args
if kind == tkIntLiteral || kind == tkFloatLiteral || kind == tkStringLiteral
|| kind == tkCharLiteral || kind == tkBoolLiteral
|| kind == tkPlus || kind == tkMinus || kind == tkSlash || kind == tkPercent {
return false;
}
if kind == tkLt {
@@ -729,6 +742,7 @@ func parserMakePattern(kind: int, line: uint32, col: uint32) -> *Pattern {
pat.patChild2 = null as *Pattern;
pat.patArgs = null as *Pattern;
pat.patNext = null as *Pattern;
pat.patGuardExpr = null as *Expr;
return pat;
}
@@ -904,6 +918,24 @@ func parserParsePattern(p: *Parser) -> *Pattern {
pat.patRangeInclusive = inclusive;
pat.patChild1 = left;
pat.patChild2 = right;
// Range can still take a guard: `1..10 if x % 2 == 0`
if parserCheck(p, tkIf) {
discard parserAdvance(p);
let guard: *Expr = parserParseExpr(p);
let gpat: *Pattern = parserMakePattern(pkGuarded, line, col);
gpat.patChild1 = pat;
gpat.patGuardExpr = guard;
return gpat;
}
return pat;
}
// Guarded pattern: `p if cond` (bindings from p visible in cond)
if parserCheck(p, tkIf) {
discard parserAdvance(p);
let guard: *Expr = parserParseExpr(p);
let pat: *Pattern = parserMakePattern(pkGuarded, line, col);
pat.patChild1 = left;
pat.patGuardExpr = guard;
return pat;
}
return left;