errdefer and try/defer fix
This commit is contained in:
@@ -290,7 +290,8 @@ Ct_State :: struct {
|
||||
places: [dynamic]Ct_Place,
|
||||
paths: [dynamic]Ct_Path_Elem,
|
||||
bindings: [dynamic]Ct_Binding,
|
||||
defers: [dynamic]ast.Stmt_Id,
|
||||
defers: [dynamic]Ct_Defer,
|
||||
defer_depth: int,
|
||||
steps: int,
|
||||
error: Ct_Error_Kind,
|
||||
diagnostic: source.Diagnostic_Id,
|
||||
@@ -298,6 +299,12 @@ Ct_State :: struct {
|
||||
demanded: ^[dynamic]Spec_Id,
|
||||
}
|
||||
|
||||
Ct_Defer :: struct {
|
||||
statement: ast.Stmt_Id,
|
||||
error_only: bool,
|
||||
capture: symbol.Id,
|
||||
}
|
||||
|
||||
ct_state_make :: proc(
|
||||
checker: ^Checker,
|
||||
pkg: ast.Package_Id,
|
||||
@@ -2217,6 +2224,9 @@ ct_clone_value :: proc(dst, src: ^Ct_State, id: Ct_Value_Id) -> Ct_Value_Id {
|
||||
}
|
||||
|
||||
ct_eval_try_expr :: proc(state: ^Ct_State, expr: ast.Expr, depth: int) -> (Ct_Value_Id, Ct_Flow, bool) {
|
||||
if state.defer_depth > 0 {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "cannot 'try' inside a 'defer'")
|
||||
}
|
||||
checker := state.checker
|
||||
channel, flow, ok := ct_eval_expr(state, expr.left, types.INVALID, depth+1)
|
||||
if !ok || flow.kind != .Normal {
|
||||
@@ -2465,7 +2475,17 @@ ct_exec_statements :: proc(
|
||||
case .Block:
|
||||
flow, ok = ct_exec_statements(state, statement.body, yield_returns, depth+1)
|
||||
case .Defer:
|
||||
append(&state.defers, statement.update)
|
||||
if statement.error_only && types.kind(state.result, &checker.module.types) != .Fallible {
|
||||
ok = ct_fail(state, .Not_Comptime, statement.span, "'errdefer' requires an enclosing fallible function")
|
||||
} else {
|
||||
capture := symbol.INVALID
|
||||
if len(statement.captures) > 0 {
|
||||
capture = statement.captures[0]
|
||||
}
|
||||
append(&state.defers, Ct_Defer{
|
||||
statement=statement.update, error_only=statement.error_only, capture=capture,
|
||||
})
|
||||
}
|
||||
case .Match:
|
||||
flow, ok = ct_exec_match(state, statement, yield_returns, depth+1)
|
||||
case .Match_Arm:
|
||||
@@ -2477,22 +2497,50 @@ ct_exec_statements :: proc(
|
||||
return flow, false
|
||||
}
|
||||
if flow.kind != .Normal {
|
||||
if !ct_flush_defers(state, defer_start, depth+1) {
|
||||
if !ct_flush_defers(state, defer_start, flow, depth+1) {
|
||||
return flow, false
|
||||
}
|
||||
return flow, true
|
||||
}
|
||||
}
|
||||
if !ct_flush_defers(state, defer_start, depth+1) {
|
||||
if !ct_flush_defers(state, defer_start, ct_flow(.Normal), depth+1) {
|
||||
return ct_flow(.Normal), false
|
||||
}
|
||||
return ct_flow(.Normal), true
|
||||
}
|
||||
|
||||
ct_flush_defers :: proc(state: ^Ct_State, start: int, depth: int) -> bool {
|
||||
ct_flush_defers :: proc(state: ^Ct_State, start: int, exit: Ct_Flow, depth: int) -> bool {
|
||||
error_exit := false
|
||||
error_value := INVALID_CT_VALUE
|
||||
if exit.kind == .Return && exit.value != INVALID_CT_VALUE && int(exit.value) < len(state.values) {
|
||||
returned := state.values[exit.value]
|
||||
if returned.kind == .Fallible && returned.active != 0 {
|
||||
error_exit = true
|
||||
children := ct_child_slice(state, returned)
|
||||
if len(children) > 0 {
|
||||
error_value = children[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
for index := len(state.defers) - 1; index >= start; index -= 1 {
|
||||
stmt := [1]ast.Stmt_Id{state.defers[index]}
|
||||
entry := state.defers[index]
|
||||
if entry.error_only && !error_exit {
|
||||
continue
|
||||
}
|
||||
binding_start := len(state.bindings)
|
||||
bound_capture := false
|
||||
if entry.error_only && symbol.is_valid(entry.capture) &&
|
||||
entry.capture != state.checker.sink_symbol && error_value != INVALID_CT_VALUE {
|
||||
ct_bind_value(state, entry.capture, state.values[error_value].type, error_value, false)
|
||||
bound_capture = true
|
||||
}
|
||||
stmt := [1]ast.Stmt_Id{entry.statement}
|
||||
state.defer_depth += 1
|
||||
flow, ok := ct_exec_statements(state, stmt[:], false, depth+1)
|
||||
state.defer_depth -= 1
|
||||
if bound_capture {
|
||||
ct_pop_bindings(state, binding_start)
|
||||
}
|
||||
if !ok || flow.kind != .Normal {
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user