From 69a3e1ee787000ed971da81f7da634147bca0756 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sun, 12 Oct 2025 13:11:41 -0300 Subject: [PATCH] v: add a fixed array `filter()` method (fix #25469) (#25479) --- vlib/v/checker/checker.v | 3 ++- vlib/v/checker/fn.v | 10 ++++++++++ vlib/v/gen/c/array.v | 5 +++-- vlib/v/gen/c/fn.v | 3 +++ vlib/v/tests/array_fixed_filter_test.v | 20 ++++++++++++++++++++ 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 vlib/v/tests/array_fixed_filter_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 3b7377fd6..7aff4d171 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -33,7 +33,8 @@ pub const array_builtin_methods = ['filter', 'clone', 'repeat', 'reverse', 'map' 'first', 'last', 'pop_left', 'pop', 'delete', 'insert', 'prepend', 'count'] pub const array_builtin_methods_chk = token.new_keywords_matcher_from_array_trie(array_builtin_methods) pub const fixed_array_builtin_methods = ['contains', 'index', 'any', 'all', 'wait', 'map', 'sort', - 'sorted', 'sort_with_compare', 'sorted_with_compare', 'reverse', 'reverse_in_place', 'count'] + 'sorted', 'sort_with_compare', 'sorted_with_compare', 'reverse', 'reverse_in_place', 'count', + 'filter'] pub const fixed_array_builtin_methods_chk = token.new_keywords_matcher_from_array_trie(fixed_array_builtin_methods) // TODO: remove `byte` from this list when it is no longer supported pub const reserved_type_names = ['bool', 'char', 'i8', 'i16', 'i32', 'int', 'i64', 'u8', 'u16', diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index d0632dea0..aca23e3ab 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -3665,6 +3665,16 @@ fn (mut c Checker) fixed_array_builtin_method_call(mut node ast.CallExpr, left_t c.expr(mut arg0.expr) c.check_predicate_param(false, elem_typ, node) node.return_type = ast.int_type + } else if method_name == 'filter' { + if node_args_len != 1 { + c.error('`.${method_name}` expected 1 argument, but got ${node_args_len}', + node.pos) + } + // position of `it` doesn't matter + scope_register_it(mut node.scope, node.pos, elem_typ) + c.expr(mut arg0.expr) + c.check_predicate_param(false, elem_typ, node) + node.return_type = c.table.find_or_register_array(elem_typ) } else if method_name == 'wait' { elem_sym := c.table.sym(elem_typ) if elem_sym.kind == .thread { diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index 90c5dc7eb..74afc0c97 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -973,11 +973,12 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) { } sym := g.table.final_sym(node.return_type) - if sym.kind != .array { + if sym.kind !in [.array_fixed, .array] { verror('filter() requires an array') } info := sym.info as ast.Array styp := g.styp(node.return_type) + left_sym := g.table.final_sym(node.left_type) elem_type_str := g.styp(info.elem_type) noscan := g.check_noscan(info.elem_type) has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, styp, '{0}') @@ -997,7 +998,7 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) { i := g.new_tmp_var() g.writeln('for (${ast.int_type_name} ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {') g.indent++ - g.write_prepared_var(var_name, info.elem_type, elem_type_str, past.tmp_var, i, true, + g.write_prepared_var(var_name, info.elem_type, elem_type_str, past.tmp_var, i, left_sym.kind == .array, false) g.set_current_pos_as_last_stmt_pos() mut is_embed_map_filter := false diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index ed3834134..b029d3688 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1305,6 +1305,9 @@ fn (mut g Gen) gen_array_method_call(node ast.CallExpr, left_type ast.Type, left fn (mut g Gen) gen_fixed_array_method_call(node ast.CallExpr, left_type ast.Type) bool { match node.name { + 'filter' { + g.gen_array_filter(node) + } 'index' { g.gen_array_index(node) } diff --git a/vlib/v/tests/array_fixed_filter_test.v b/vlib/v/tests/array_fixed_filter_test.v new file mode 100644 index 000000000..452251cf9 --- /dev/null +++ b/vlib/v/tests/array_fixed_filter_test.v @@ -0,0 +1,20 @@ +fn test_filtered_fixed_arrays() { + a := [1, 2, 3]! + assert a.filter(it > 2).len == 1 + assert typeof(a.filter(it > 2)).name == '[]int' + + sfa := ['abc', 'def', 'xyz']! + sfaf := sfa.filter(it[0] == `d`) + assert sfaf == ['def'] + assert typeof(sfaf).name == '[]string' + + ufa := [u8(99), 77, 61, 120]! + ufaf := ufa.filter(it > 80) + assert ufaf == [u8(99), 120] + assert typeof(ufaf).name == '[]u8' + + fafa := [[1, 2, 3]!, [4, 5, 6]!, [6, 7, 8]!]! + fafaf := fafa.filter(it[2] > 5) + assert fafaf == [[4, 5, 6]!, [6, 7, 8]!] + assert typeof(fafaf).name == '[][3]int' +} -- 2.39.5