From aa502c26e952c35337a2cfa05b2a4941eba2190a Mon Sep 17 00:00:00 2001 From: shove Date: Sat, 18 Nov 2023 17:55:51 +0800 Subject: [PATCH] checker, cgen: fix arrays alias built-in methods call(fix #19896) (#19910) --- vlib/v/checker/fn.v | 11 +++++--- vlib/v/gen/c/array.v | 14 +++++------ vlib/v/gen/c/fn.v | 3 ++- .../tests/alias_array_built_in_methods_test.v | 25 +++++++++++++++++++ 4 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 vlib/v/tests/alias_array_built_in_methods_test.v diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 574e6e70e8aa63..e0bd5eafe5ede2 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1710,7 +1710,8 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { if !c.check_types(arg_type, info.elem_type) && !c.check_types(left_type, arg_type) { c.error('cannot ${method_name} `${arg_sym.name}` to `${left_sym.name}`', arg_expr.pos()) } - } else if final_left_sym.kind == .array && method_name in ['first', 'last', 'pop'] { + } else if final_left_sym.kind == .array + && method_name in ['filter', 'map', 'sort', 'sorted', 'contains', 'any', 'all', 'first', 'last', 'pop'] { return c.array_builtin_method_call(mut node, left_type, final_left_sym) } else if c.pref.backend.is_js() && left_sym.name.starts_with('Promise[') && method_name == 'wait' { @@ -2613,10 +2614,12 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as c.error('.slice() is a private method, use `x[start..end]` instead', node.pos) return ast.void_type } + unwrapped_left_type := c.unwrap_generic(left_type) + unaliased_left_type := c.table.unaliased_type(unwrapped_left_type) array_info := if left_sym.info is ast.Array { left_sym.info as ast.Array } else { - c.table.sym(c.unwrap_generic(left_type)).info as ast.Array + c.table.sym(unaliased_left_type).info as ast.Array } elem_typ = array_info.elem_type if method_name in ['filter', 'map', 'any', 'all'] { @@ -2708,7 +2711,7 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as } } // map/filter are supposed to have 1 arg only - mut arg_type := left_type + mut arg_type := unaliased_left_type for mut arg in node.args { arg_type = c.check_expr_opt_call(arg.expr, c.expr(mut arg.expr)) } @@ -2810,7 +2813,7 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as } } else if method_name == 'delete' { c.fail_if_immutable(mut node.left) - unwrapped_left_sym := c.table.sym(c.unwrap_generic(left_type)) + unwrapped_left_sym := c.table.sym(unwrapped_left_type) if method := c.table.find_method(unwrapped_left_sym, method_name) { node.receiver_type = method.receiver_type } diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index ab67411a83fa66..89195427985b91 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -468,8 +468,8 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) { } ret_typ := g.typ(node.return_type) - ret_sym := g.table.sym(node.return_type) - inp_sym := g.table.sym(node.receiver_type) + ret_sym := g.table.final_sym(node.return_type) + inp_sym := g.table.final_sym(node.receiver_type) ret_info := ret_sym.info as ast.Array mut ret_elem_type := g.typ(ret_info.elem_type) inp_info := inp_sym.info as ast.Array @@ -581,7 +581,7 @@ fn (mut g Gen) gen_array_sorted(node ast.CallExpr) { g.past_tmp_var_done(past) } atype := g.typ(node.return_type) - sym := g.table.sym(node.return_type) + sym := g.table.final_sym(node.return_type) info := sym.info as ast.Array depth := g.get_array_depth(info.elem_type) @@ -601,7 +601,7 @@ fn (mut g Gen) gen_array_sorted(node ast.CallExpr) { // `users.sort(a.age < b.age)` fn (mut g Gen) gen_array_sort(node ast.CallExpr) { // println('filter s="$s"') - rec_sym := g.table.sym(node.receiver_type) + rec_sym := g.table.final_sym(node.receiver_type) if rec_sym.kind != .array { println(node.name) println(g.typ(node.receiver_type)) @@ -724,7 +724,7 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) { g.past_tmp_var_done(past) } - sym := g.table.sym(node.return_type) + sym := g.table.final_sym(node.return_type) if sym.kind != .array { verror('filter() requires an array') } @@ -1121,7 +1121,7 @@ fn (mut g Gen) gen_array_any(node ast.CallExpr) { g.past_tmp_var_done(past) } - sym := g.table.sym(node.left_type) + sym := g.table.final_sym(node.left_type) info := sym.info as ast.Array // styp := g.typ(node.return_type) elem_type_str := g.typ(info.elem_type) @@ -1200,7 +1200,7 @@ fn (mut g Gen) gen_array_all(node ast.CallExpr) { g.past_tmp_var_done(past) } - sym := g.table.sym(node.left_type) + sym := g.table.final_sym(node.left_type) info := sym.info as ast.Array // styp := g.typ(node.return_type) elem_type_str := g.typ(info.elem_type) diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 98ae43f8d96bfe..c607a944cb502c 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1257,7 +1257,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) { } left_sym := g.table.sym(left_type) final_left_sym := g.table.final_sym(left_type) - if left_sym.kind == .array { + if left_sym.kind == .array || (final_left_sym.kind == .array + && node.name in ['filter', 'map', 'sort', 'sorted', 'contains', 'any', 'all']) { if g.gen_array_method_call(node, left_type) { return } diff --git a/vlib/v/tests/alias_array_built_in_methods_test.v b/vlib/v/tests/alias_array_built_in_methods_test.v new file mode 100644 index 00000000000000..dfb796aa205e6a --- /dev/null +++ b/vlib/v/tests/alias_array_built_in_methods_test.v @@ -0,0 +1,25 @@ +type IntArray = []int + +fn test_alias_array_method() { + mut arr := IntArray([0, 1, 2, 3]) + res := arr.filter(it > 0) + assert res == IntArray([1, 2, 3]) + + assert arr.first() == 0 + assert arr.last() == 3 + arr.pop() + assert arr == IntArray([0, 1, 2]) + + arr2 := arr.map(it) + assert arr2 == [0, 1, 2] + + assert arr.any(it > 0) + assert !arr.all(it > 0) + + arr.sort(a > b) + assert arr == IntArray([2, 1, 0]) + arr.sort() + assert arr == IntArray([0, 1, 2]) + + assert arr.contains(1) +}