bug fixes

This commit is contained in:
2026-07-13 23:34:14 +02:00
parent 0eeacc2e37
commit 0b0b00a050
6 changed files with 114 additions and 17 deletions
+25 -9
View File
@@ -5913,6 +5913,7 @@ build_compound_expr :: proc(
body: []hir.Stmt_Id
capture := hir.INVALID_LOCAL
block_handler := false
void_fallthrough := false
fallback := hir.INVALID_EXPR
if expr.right != ast.INVALID_EXPR {
fallback = build_nested_expr(checker, expr.right, locals, global_reads, calls, success, pkg, file)
@@ -5932,14 +5933,19 @@ build_compound_expr :: proc(
handler: [dynamic]hir.Stmt_Id
handler.allocator = checker.allocator
fallback, _ = build_value_source(ctx, &handler, expr.body, success, expr.span, allow_exit=true)
void_fallthrough = fallback == hir.INVALID_EXPR && !all_paths_exit(&checker.module, handler[:])
body = handler[:]
resize(ctx.locals, capture_start)
}
catch_mode := hir.CATCH_EXPRESSION
if block_handler {
catch_mode = hir.CATCH_VOID_FALLTHROUGH if void_fallthrough else hir.CATCH_BLOCK
}
return add_hir_expr(checker, hir.Expr{
kind=.Catch,
span=expr.span,
type=success,
integer=1 if block_handler else 0,
integer=catch_mode,
left=channel,
right=fallback,
body=body,
@@ -8236,10 +8242,11 @@ build_block :: proc(
}
// build_value_block builds a `{ ... yield v }` value block whose final statement
// must be a `yield`. Catch handlers may instead exit on every path, in which case
// `allow_exit` leaves the fallback expression invalid. Otherwise it builds the leading
// statements inline, evaluates the yield in their scope, then captures the value before
// running defers. `expected` is the binding's type (INVALID for an untyped `::`).
// must be a `yield`. Catch handlers may instead exit on every path or complete with
// void, in which case `allow_exit` leaves the fallback expression invalid. Otherwise
// it builds the leading statements inline, evaluates the yield in their scope, then
// captures the value before running defers. `expected` is the binding's type (INVALID
// for an untyped `::`).
build_value_block :: proc(
ctx: ^Build_Ctx,
body: ^[dynamic]hir.Stmt_Id,
@@ -8257,7 +8264,7 @@ build_value_block :: proc(
for s in inner {
append(body, s)
}
if allow_exit && all_paths_exit(&checker.module, inner) {
if allow_exit && (types.is_void(expected) || all_paths_exit(&checker.module, inner)) {
delete(inner, checker.allocator)
return hir.INVALID_EXPR, expected
}
@@ -9785,7 +9792,16 @@ build_function :: proc(checker: ^Checker, id: Spec_Id) {
}
delete(block, checker.allocator)
if !types.is_void(spec.result) && !returns {
fallible_void := types.kind(spec.result, &checker.module.types) == .Fallible &&
types.is_void(types.fallible_success(spec.result, &checker.module.types))
if !returns && fallible_void {
value := fallible_aggregate(checker, function.span, spec.result, hir.INVALID_EXPR, false)
append(&body, hir.stmt_id(len(checker.module.statements)))
append(&checker.module.statements, hir.Stmt{
kind=.Return, span=function.span, expr=value, local=hir.INVALID_LOCAL,
diagnostic=source.INVALID_DIAGNOSTIC,
})
} else if !types.is_void(spec.result) && !returns {
id := source.addf(
checker.diagnostics,
function.span,
@@ -9944,8 +9960,8 @@ build_globals :: proc(checker: ^Checker) {
}
expr := build_expr(checker, global.expr, nil, &dependencies, &calls, expected, global.pkg, global.file)
global_type := checker.global_types[global_index]
if is_runtime_type(checker, declared) {
expr = coerce_expr(checker, expr, declared, global.span)
if is_runtime_type(checker, checker.global_types[global_index]) {
expr = coerce_expr(checker, expr, checker.global_types[global_index], global.span)
global_type = checker.module.exprs[expr].type
} else if is_runtime_type(checker, checker.module.exprs[expr].type) {
global_type = checker.module.exprs[expr].type