diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 8b88571872..bd2f7f5e49 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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 } } diff --git a/vlib/v/checker/tests/lambda_undefined_variables_err.out b/vlib/v/checker/tests/lambda_undefined_variables_err.out new file mode 100644 index 0000000000..ba91e8931c --- /dev/null +++ b/vlib/v/checker/tests/lambda_undefined_variables_err.out @@ -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 | } diff --git a/vlib/v/checker/tests/lambda_undefined_variables_err.vv b/vlib/v/checker/tests/lambda_undefined_variables_err.vv new file mode 100644 index 0000000000..aee19868d0 --- /dev/null +++ b/vlib/v/checker/tests/lambda_undefined_variables_err.vv @@ -0,0 +1,9 @@ +fn f(g fn (int) string) { +} + +fn main() { + f(|x| s1) + + s2 := 'abc' + f(|x| s2) +} diff --git a/vlib/v/parser/expr.v b/vlib/v/parser/expr.v index 7d772b9d79..cdff14ddf4 100644 --- a/vlib/v/parser/expr.v +++ b/vlib/v/parser/expr.v @@ -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{}