parser, checker: fix var scope in lambda(fix #19860) (#19871)

This commit is contained in:
shove 2023-11-15 04:34:16 +08:00 committed by GitHub
parent 50c3e4001b
commit f5bf18c79a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 2 deletions

View File

@ -79,6 +79,7 @@ pub mut:
inside_unsafe bool // true inside `unsafe {}` blocks
inside_const bool // true inside `const ( ... )` blocks
inside_anon_fn bool // true inside `fn() { ... }()`
inside_lambda bool // true inside `|...| ...`
inside_ref_lit bool // true inside `a := &something`
inside_defer bool // true inside `defer {}` blocks
inside_fn_arg bool // `a`, `b` in `a.f(b)`
@ -2799,6 +2800,10 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {
return c.int_lit(mut node)
}
ast.LambdaExpr {
c.inside_lambda = true
defer {
c.inside_lambda = false
}
return c.lambda_expr(mut node, c.expected_type)
}
ast.LockExpr {
@ -3732,8 +3737,13 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
found_var := c.fn_scope.find_var(node.name)
if found_var != none {
c.error('`${node.name}` must be added to the capture list for the closure to be used inside',
node.pos)
if c.inside_lambda {
// Lambdas don't support capturing variables yet, so that's the only hint.
c.error('undefined variable `${node.name}`', node.pos)
} else {
c.error('`${node.name}` must be added to the capture list for the closure to be used inside',
node.pos)
}
return ast.void_type
}
}

View File

@ -0,0 +1,33 @@
vlib/v/checker/tests/lambda_undefined_variables_err.vv:7:2: warning: unused variable: `s2`
5 | f(|x| s1)
6 |
7 | s2 := 'abc'
| ~~
8 | f(|x| s2)
9 | }
vlib/v/checker/tests/lambda_undefined_variables_err.vv:5:8: error: undefined ident: `s1`
3 |
4 | fn main() {
5 | f(|x| s1)
| ~~
6 |
7 | s2 := 'abc'
vlib/v/checker/tests/lambda_undefined_variables_err.vv:5:4: error: `s1` used as value
3 |
4 | fn main() {
5 | f(|x| s1)
| ^
6 |
7 | s2 := 'abc'
vlib/v/checker/tests/lambda_undefined_variables_err.vv:8:8: error: undefined variable `s2`
6 |
7 | s2 := 'abc'
8 | f(|x| s2)
| ~~
9 | }
vlib/v/checker/tests/lambda_undefined_variables_err.vv:8:4: error: `s2` used as value
6 |
7 | s2 := 'abc'
8 | f(|x| s2)
| ^
9 | }

View File

@ -0,0 +1,9 @@
fn f(g fn (int) string) {
}
fn main() {
f(|x| s1)
s2 := 'abc'
f(|x| s2)
}

View File

@ -852,6 +852,7 @@ fn (mut p Parser) lambda_expr() ?ast.LambdaExpr {
defer {
p.close_scope()
}
p.scope.detached_from_parent = true
mut pos := p.tok.pos()
mut params := []ast.Ident{}