checker: fix regression of anon fns that have loops with break/continue
parent
744a753b47
commit
0bcb955258
|
@ -4609,7 +4609,7 @@ fn (mut c Checker) branch_stmt(node ast.BranchStmt) {
|
|||
if c.inside_defer {
|
||||
c.error('`$node.kind.str()` is not allowed in defer statements', node.pos)
|
||||
}
|
||||
if c.in_for_count == 0 || c.inside_anon_fn {
|
||||
if c.in_for_count == 0 {
|
||||
c.error('$node.kind.str() statement not within a loop', node.pos)
|
||||
}
|
||||
if node.label.len > 0 {
|
||||
|
@ -7798,13 +7798,6 @@ fn (mut c Checker) evaluate_once_comptime_if_attribute(mut a ast.Attr) bool {
|
|||
}
|
||||
|
||||
fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
c.fn_level++
|
||||
defer {
|
||||
c.fn_level--
|
||||
}
|
||||
//
|
||||
c.returns = false
|
||||
|
||||
if node.generic_names.len > 0 && c.table.cur_concrete_types.len == 0 {
|
||||
// Just remember the generic function for now.
|
||||
// It will be processed later in c.post_process_generic_fns,
|
||||
|
@ -7815,6 +7808,30 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||
c.file.generic_fns << node
|
||||
return
|
||||
}
|
||||
// save all the state that fn_decl or inner statements/expressions
|
||||
// could potentially modify, since functions can be nested, due to
|
||||
// anonymous function support, and ensure that it is restored, when
|
||||
// fn_decl returns:
|
||||
prev_fn_scope := c.fn_scope
|
||||
prev_in_for_count := c.in_for_count
|
||||
prev_inside_defer := c.inside_defer
|
||||
prev_inside_unsafe := c.inside_unsafe
|
||||
prev_inside_anon_fn := c.inside_anon_fn
|
||||
prev_returns := c.returns
|
||||
c.fn_level++
|
||||
c.in_for_count = 0
|
||||
c.inside_defer = false
|
||||
c.inside_unsafe = false
|
||||
c.returns = false
|
||||
defer {
|
||||
c.fn_level--
|
||||
c.returns = prev_returns
|
||||
c.inside_anon_fn = prev_inside_anon_fn
|
||||
c.inside_unsafe = prev_inside_unsafe
|
||||
c.inside_defer = prev_inside_defer
|
||||
c.in_for_count = prev_in_for_count
|
||||
c.fn_scope = prev_fn_scope
|
||||
}
|
||||
// Check generics fn/method without generic type parameters
|
||||
mut need_generic_names := false
|
||||
if node.generic_names.len == 0 {
|
||||
|
@ -8041,7 +8058,6 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||
}
|
||||
}
|
||||
}
|
||||
c.returns = false
|
||||
node.source_file = c.file
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,20 @@ vlib/v/checker/tests/goto_label.vv:8:8: error: unknown label `f2`
|
|||
| ~~
|
||||
9 | goto a1
|
||||
10 | a1:
|
||||
vlib/v/checker/tests/goto_label.vv:9:8: error: `goto` requires `unsafe` (consider using labelled break/continue)
|
||||
7 | goto f1
|
||||
8 | goto f2
|
||||
9 | goto a1
|
||||
| ~~
|
||||
10 | a1:
|
||||
11 | goto a1
|
||||
vlib/v/checker/tests/goto_label.vv:11:8: error: `goto` requires `unsafe` (consider using labelled break/continue)
|
||||
9 | goto a1
|
||||
10 | a1:
|
||||
11 | goto a1
|
||||
| ~~
|
||||
12 | }
|
||||
13 | f2:
|
||||
vlib/v/checker/tests/goto_label.vv:14:7: error: unknown label `a1`
|
||||
12 | }
|
||||
13 | f2:
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
fn test_anon_functions_can_have_loops_with_breaks() {
|
||||
mut res := 123
|
||||
for true {
|
||||
x := fn () int {
|
||||
for x in 0 .. 10 {
|
||||
println(x)
|
||||
break
|
||||
}
|
||||
return 3
|
||||
}()
|
||||
println('$x')
|
||||
res = x
|
||||
break
|
||||
}
|
||||
assert res == 3
|
||||
}
|
Loading…
Reference in New Issue