From be49e2bf6c9c61b7707e2f1e487b3714c8e1ba89 Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Wed, 21 May 2025 16:30:20 +0530 Subject: [PATCH] checker: disallow invalid expr for `filter`, `count`, `any`, `all` (fix #24508) (#24540) --- vlib/v/checker/fn.v | 15 ++++++++---- vlib/v/checker/tests/array_count_err.out | 7 ++++++ .../tests/array_method_invalid_expr.out | 24 +++++++++++++++++++ .../tests/array_method_invalid_expr.vv | 5 ++++ .../fixed_array_builtin_method_args_err.out | 7 ++++++ vlib/v/pref/pref.v | 2 +- vlib/v/reflection/reflection.v | 2 +- 7 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 vlib/v/checker/tests/array_method_invalid_expr.out create mode 100644 vlib/v/checker/tests/array_method_invalid_expr.vv diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index f6f0f31449..691c6323d3 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -2983,8 +2983,8 @@ fn (mut c Checker) check_predicate_param(is_map bool, elem_typ ast.Type, node as // Finish early so that it doesn't fail later return } - arg_expr := node.args[0].expr - match arg_expr { + mut arg_expr := node.args[0].expr + match mut arg_expr { ast.AnonFn { if arg_expr.decl.return_type.has_flag(.option) { c.error('option needs to be unwrapped before using it in map/filter', @@ -3024,7 +3024,7 @@ fn (mut c Checker) check_predicate_param(is_map bool, elem_typ ast.Type, node as arg_expr.pos) } } else if arg_expr.kind == .variable { - if arg_expr.obj is ast.Var { + if mut arg_expr.obj is ast.Var { expr := arg_expr.obj.expr if expr is ast.AnonFn { // copied from above @@ -3084,13 +3084,18 @@ fn (mut c Checker) check_predicate_param(is_map bool, elem_typ ast.Type, node as } } ast.LambdaExpr { - if arg_expr.expr is ast.CallExpr && is_map + if mut arg_expr.expr is ast.CallExpr && is_map && arg_expr.expr.return_type in [ast.void_type, 0] { c.error('type mismatch, `${arg_expr.expr.name}` does not return anything', arg_expr.expr.pos) } } - else {} + else { + if !is_map && c.expr(mut arg_expr) != ast.bool_type { + c.error('invalid expression, expected infix expr, lambda or function', + arg_expr.pos()) + } + } } } diff --git a/vlib/v/checker/tests/array_count_err.out b/vlib/v/checker/tests/array_count_err.out index e9521a705b..bdd404c093 100644 --- a/vlib/v/checker/tests/array_count_err.out +++ b/vlib/v/checker/tests/array_count_err.out @@ -1,3 +1,10 @@ +vlib/v/checker/tests/array_count_err.vv:3:10: error: invalid expression, expected infix expr, lambda or function + 1 | fn main() { + 2 | a := []int{} + 3 | a.count(1) + | ^ + 4 | a.count(1, 2) + 5 | a.count('') vlib/v/checker/tests/array_count_err.vv:4:4: error: expected 1 argument, but got 2 2 | a := []int{} 3 | a.count(1) diff --git a/vlib/v/checker/tests/array_method_invalid_expr.out b/vlib/v/checker/tests/array_method_invalid_expr.out new file mode 100644 index 0000000000..7d116bf65b --- /dev/null +++ b/vlib/v/checker/tests/array_method_invalid_expr.out @@ -0,0 +1,24 @@ +vlib/v/checker/tests/array_method_invalid_expr.vv:2:16: error: invalid expression, expected infix expr, lambda or function + 1 | runes := [`a`, `b`, `c`, `a`] + 2 | dump(runes.all(`a`)) + | ~~~ + 3 | dump(runes.any(`a`)) + 4 | dump(runes.count(`a`)) +vlib/v/checker/tests/array_method_invalid_expr.vv:3:16: error: invalid expression, expected infix expr, lambda or function + 1 | runes := [`a`, `b`, `c`, `a`] + 2 | dump(runes.all(`a`)) + 3 | dump(runes.any(`a`)) + | ~~~ + 4 | dump(runes.count(`a`)) + 5 | dump(runes.filter(`a`)) +vlib/v/checker/tests/array_method_invalid_expr.vv:4:18: error: invalid expression, expected infix expr, lambda or function + 2 | dump(runes.all(`a`)) + 3 | dump(runes.any(`a`)) + 4 | dump(runes.count(`a`)) + | ~~~ + 5 | dump(runes.filter(`a`)) +vlib/v/checker/tests/array_method_invalid_expr.vv:5:19: error: invalid expression, expected infix expr, lambda or function + 3 | dump(runes.any(`a`)) + 4 | dump(runes.count(`a`)) + 5 | dump(runes.filter(`a`)) + | ~~~ diff --git a/vlib/v/checker/tests/array_method_invalid_expr.vv b/vlib/v/checker/tests/array_method_invalid_expr.vv new file mode 100644 index 0000000000..8be3473723 --- /dev/null +++ b/vlib/v/checker/tests/array_method_invalid_expr.vv @@ -0,0 +1,5 @@ +runes := [`a`, `b`, `c`, `a`] +dump(runes.all(`a`)) +dump(runes.any(`a`)) +dump(runes.count(`a`)) +dump(runes.filter(`a`)) diff --git a/vlib/v/checker/tests/fixed_array_builtin_method_args_err.out b/vlib/v/checker/tests/fixed_array_builtin_method_args_err.out index 0dd5154b9a..13be3227bd 100644 --- a/vlib/v/checker/tests/fixed_array_builtin_method_args_err.out +++ b/vlib/v/checker/tests/fixed_array_builtin_method_args_err.out @@ -33,6 +33,13 @@ vlib/v/checker/tests/fixed_array_builtin_method_args_err.vv:8:11: error: `.any` | ~~~~~ 9 | _ := arr.any(22) 10 | _ := arr.all() +vlib/v/checker/tests/fixed_array_builtin_method_args_err.vv:9:15: error: invalid expression, expected infix expr, lambda or function + 7 | _ := arr.contains('hello') + 8 | _ := arr.any() + 9 | _ := arr.any(22) + | ~~ + 10 | _ := arr.all() + 11 | _ := arr.all('hello') vlib/v/checker/tests/fixed_array_builtin_method_args_err.vv:10:11: error: `.all` expected 1 argument, but got 0 8 | _ := arr.any() 9 | _ := arr.any(22) diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index 400ee1855c..4ea17701f2 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -987,7 +987,7 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin dyld_fallback_paths := os.getenv('DYLD_FALLBACK_LIBRARY_PATH') so_dir := os.dir(so_path) if !dyld_fallback_paths.contains(so_dir) { - env := [dyld_fallback_paths, so_dir].filter(it.len).join(':') + env := [dyld_fallback_paths, so_dir].filter(it.len != 0).join(':') os.setenv('DYLD_FALLBACK_LIBRARY_PATH', env, true) } } diff --git a/vlib/v/reflection/reflection.v b/vlib/v/reflection/reflection.v index 3b3e36190a..3090d16288 100644 --- a/vlib/v/reflection/reflection.v +++ b/vlib/v/reflection/reflection.v @@ -254,7 +254,7 @@ pub fn get_modules() []Module { // get_functions returns the functions built with V source pub fn get_funcs() []Function { mut out := g_reflection.funcs.clone() - out << arrays.flatten[Function](get_types().map(it.sym.methods).filter(it.len)) + out << arrays.flatten[Function](get_types().map(it.sym.methods).filter(it.len != 0)) return out }