From a6fe88701d3c0ba7b2f7780e436a384ebdd52525 Mon Sep 17 00:00:00 2001 From: shove70 Date: Fri, 17 Nov 2023 18:17:00 +0800 Subject: [PATCH] checker, cgen: make arrays alias can call built-in methods(fix #19896) --- vlib/v/checker/fn.v | 12 ++++---- vlib/v/gen/c/array.v | 18 ++++++------ vlib/v/gen/c/fn.v | 2 +- .../tests/alias_array_built_in_methods_test.v | 28 +++++++++++++++++++ 4 files changed, 45 insertions(+), 15 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..e4fc2de0aa9407 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1674,6 +1674,8 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { // FIXME: Argument count != 1 will break these if left_sym.kind == .array && array_builtin_methods_chk.matches(method_name) { return c.array_builtin_method_call(mut node, left_type, c.table.sym(left_type)) + } else if final_left_sym.kind == .array && array_builtin_methods_chk.matches(method_name) { + return c.array_builtin_method_call(mut node, left_type, final_left_sym) } else if (left_sym.kind == .map || final_left_sym.kind == .map) && method_name in ['clone', 'keys', 'values', 'move', 'delete'] { if left_sym.kind == .map { @@ -1710,8 +1712,6 @@ 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'] { - 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' { info := left_sym.info as ast.Struct @@ -2613,10 +2613,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 +2710,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 +2812,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..486c0ddb8412e6 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') } @@ -801,7 +801,7 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) { // `nums.insert(0, 2)` `nums.insert(0, [2,3,4])` fn (mut g Gen) gen_array_insert(node ast.CallExpr) { - left_sym := g.table.sym(node.left_type) + left_sym := g.table.final_sym(node.left_type) left_info := left_sym.info as ast.Array elem_type_str := g.typ(left_info.elem_type) arg2_sym := g.table.sym(node.args[1].typ) @@ -837,7 +837,7 @@ fn (mut g Gen) gen_array_insert(node ast.CallExpr) { // `nums.prepend(2)` `nums.prepend([2,3,4])` fn (mut g Gen) gen_array_prepend(node ast.CallExpr) { - left_sym := g.table.sym(node.left_type) + left_sym := g.table.final_sym(node.left_type) left_info := left_sym.info as ast.Array elem_type_str := g.typ(left_info.elem_type) arg_sym := g.table.sym(node.args[0].typ) @@ -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..7b9616593d9f76 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1257,7 +1257,7 @@ 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 { 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..85e37129ee4579 --- /dev/null +++ b/vlib/v/tests/alias_array_built_in_methods_test.v @@ -0,0 +1,28 @@ +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) + + arr.insert(3, 3) + assert arr == IntArray([0, 1, 2, 3]) +}