fix catch handlers / match statements yielding past scope

This commit is contained in:
2026-06-30 23:21:47 +02:00
parent d6f9c24314
commit 7fe3552c01
6 changed files with 117 additions and 44 deletions
+10 -9
View File
@@ -4417,7 +4417,7 @@ build_block :: proc(
if typed {
expected = type_from_syntax(statement.type)
}
value, value_type := build_value_source(ctx, &body, statement.body, expected, statement.span, statement.label)
value, value_type := build_value_source(ctx, &body, statement.body, expected, statement.span, statement.label, statement.value_control_flow)
if _, found := find_build_local(ctx.locals^[duplicate_start:], statement.name); found {
id := source.addf(
checker.diagnostics, statement.span,
@@ -4628,7 +4628,7 @@ build_block :: proc(
} else if statement.expr == ast.INVALID_EXPR {
// `target = { ... yield v }`: build the value block against the
// target's type (build_value_block coerces internally).
value, _ = build_value_source(ctx, &body, statement.body, target_type, statement.span, statement.label)
value, _ = build_value_source(ctx, &body, statement.body, target_type, statement.span, statement.label, statement.value_control_flow)
} else {
value = build_expr(
checker, statement.expr, ctx.locals^[:], ctx.global_reads, ctx.calls,
@@ -4648,7 +4648,7 @@ build_block :: proc(
if statement.name == checker.sink_symbol {
value: hir.Expr_Id
if statement.expr == ast.INVALID_EXPR {
value, _ = build_value_source(ctx, &body, statement.body, types.INVALID, statement.span, statement.label)
value, _ = build_value_source(ctx, &body, statement.body, types.INVALID, statement.span, statement.label, statement.value_control_flow)
} else {
value = build_expr(checker, statement.expr, ctx.locals^[:], ctx.global_reads, ctx.calls, types.INVALID, ctx.pkg, ctx.file)
}
@@ -4692,7 +4692,7 @@ build_block :: proc(
}
value: hir.Expr_Id
if statement.expr == ast.INVALID_EXPR {
value, _ = build_value_source(ctx, &body, statement.body, local.type, statement.span, statement.label)
value, _ = build_value_source(ctx, &body, statement.body, local.type, statement.span, statement.label, statement.value_control_flow)
} else {
value = build_expr(
checker, statement.expr, ctx.locals^[:], ctx.global_reads, ctx.calls,
@@ -5430,10 +5430,10 @@ build_value_block :: proc(
return value, value_type
}
// build_value_source feeds a declaration/assignment RHS into the right value builder:
// a labeled `blk: { ... }` block, a plain `{ ... }` block, an `if` whose branches yield,
// or a `for`/`while` whose iterations yield. All return the produced value and its type
// for the enclosing binding. `label` is the labeled-block label (INVALID otherwise).
// build_value_source feeds a declaration/assignment RHS into the right value builder.
// Braced blocks are plain value blocks and must end in their own `yield`; bare RHS
// control flow (`x :: match ...`) sets `value_control_flow` and can produce directly.
// `label` is the labeled-block label (INVALID otherwise).
build_value_source :: proc(
ctx: ^Build_Ctx,
body: ^[dynamic]hir.Stmt_Id,
@@ -5441,12 +5441,13 @@ build_value_source :: proc(
expected: types.Type,
span: source.Span,
label := symbol.INVALID,
value_control_flow := false,
) -> (value: hir.Expr_Id, value_type: types.Type) {
checker := ctx.checker
if symbol.is_valid(label) {
return build_value_labeled_block(ctx, body, body_stmts, label, expected, span)
}
if len(body_stmts) == 1 {
if value_control_flow && len(body_stmts) == 1 {
#partial switch checker.ast_module.statements[body_stmts[0]].kind {
case .If:
return build_value_if(ctx, body, body_stmts[0], expected, span)