conditional optional unwrapping

This commit is contained in:
2026-06-21 20:38:12 +02:00
parent c90ada608e
commit f4194492cc
10 changed files with 391 additions and 12 deletions
+36 -1
View File
@@ -633,7 +633,22 @@ lower_statements :: proc(state: ^State, statements: []hir.Stmt_Id) {
diagnostic=statement.diagnostic,
})
case .If:
cond := lower_expr(state, statement.expr)
// A conditional unwrap (`if opt |v| { ... }`) carries the binding local id in
// `statement.local`; `expr` is then the optional, not a bool condition. Test it
// for presence, and inside the then-block bind the unwrapped value to the local.
is_unwrap := statement.local != hir.INVALID_LOCAL
opt := ir.INVALID_INSTRUCTION
cond: ir.Instruction_Id
if is_unwrap {
opt = lower_expr(state, statement.expr)
cond = append_instruction(state, ir.Instruction{
op=.Optional_Is_Some, span=statement.span, type=types.BOOL,
target=ir.INVALID_REF, a=opt, b=ir.INVALID_INSTRUCTION,
diagnostic=source.INVALID_DIAGNOSTIC,
})
} else {
cond = lower_expr(state, statement.expr)
}
has_else := statement.else_body != nil
then_lbl := fresh_label(state)
else_lbl := fresh_label(state) if has_else else then_lbl
@@ -649,6 +664,26 @@ lower_statements :: proc(state: ^State, statements: []hir.Stmt_Id) {
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
diagnostic=source.INVALID_DIAGNOSTIC,
})
if is_unwrap && int(statement.local) < len(state.func_locals) {
local := state.func_locals[statement.local]
slot := append_instruction(state, ir.Instruction{
op=.Alloca, span=statement.span, type=local.type,
target=ir.local_ref(ir.Local_Id(statement.local)),
a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
diagnostic=source.INVALID_DIAGNOSTIC,
})
state.local_slots[statement.local] = slot
inner := append_instruction(state, ir.Instruction{
op=.Optional_Value, span=statement.span, type=local.type,
target=ir.INVALID_REF, a=opt, b=ir.INVALID_INSTRUCTION,
diagnostic=source.INVALID_DIAGNOSTIC,
})
append_instruction(state, ir.Instruction{
op=.Store, span=statement.span, type=local.type,
target=ir.INVALID_REF, a=slot, b=inner,
diagnostic=source.INVALID_DIAGNOSTIC,
})
}
lower_statements(state, statement.then_body)
append_instruction(state, ir.Instruction{
op=.Br, span=statement.span, type=types.VOID, integer=merge_lbl,