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 {
|
if c.inside_defer {
|
||||||
c.error('`$node.kind.str()` is not allowed in defer statements', node.pos)
|
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)
|
c.error('$node.kind.str() statement not within a loop', node.pos)
|
||||||
}
|
}
|
||||||
if node.label.len > 0 {
|
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) {
|
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 {
|
if node.generic_names.len > 0 && c.table.cur_concrete_types.len == 0 {
|
||||||
// Just remember the generic function for now.
|
// Just remember the generic function for now.
|
||||||
// It will be processed later in c.post_process_generic_fns,
|
// 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
|
c.file.generic_fns << node
|
||||||
return
|
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
|
// Check generics fn/method without generic type parameters
|
||||||
mut need_generic_names := false
|
mut need_generic_names := false
|
||||||
if node.generic_names.len == 0 {
|
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
|
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
|
9 | goto a1
|
||||||
10 | 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`
|
vlib/v/checker/tests/goto_label.vv:14:7: error: unknown label `a1`
|
||||||
12 | }
|
12 | }
|
||||||
13 | f2:
|
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