From 6698fe4f60797b4dd406f8efed8653cda8b2facf Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 23 May 2023 20:46:14 +0800 Subject: [PATCH] checker, cgen: fix contains() with array of interfaces (#18241) --- vlib/v/checker/fn.v | 3 +++ vlib/v/gen/c/array.v | 22 ++++++++++++++----- vlib/v/gen/c/fn.v | 2 +- vlib/v/gen/c/infix.v | 17 ++++++++++---- ...array_of_interfaces_builtin_method_test.v} | 6 ++++- 5 files changed, 38 insertions(+), 12 deletions(-) rename vlib/v/tests/{array_of_interfaces_index_test.v => array_of_interfaces_builtin_method_test.v} (82%) diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index cfb70ae181..b7e4ed3672 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -2509,6 +2509,9 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as c.error('${err.msg()} in argument 1 to `.contains()`', node.args[0].pos) } } + for i, arg in node.args { + node.args[i].typ = c.expr(arg.expr) + } node.return_type = ast.bool_type } else if method_name == 'index' { if node.args.len != 1 { diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index 38b76e731c..2c757feeb5 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -885,22 +885,32 @@ fn (mut g Gen) gen_array_contains_methods() { } // `nums.contains(2)` -fn (mut g Gen) gen_array_contains(typ ast.Type, left ast.Expr, right ast.Expr) { - fn_name := g.get_array_contains_method(typ) +fn (mut g Gen) gen_array_contains(left_type ast.Type, left ast.Expr, right_type ast.Type, right ast.Expr) { + fn_name := g.get_array_contains_method(left_type) g.write('${fn_name}(') - g.write(strings.repeat(`*`, typ.nr_muls())) - if typ.share() == .shared_t { + g.write(strings.repeat(`*`, left_type.nr_muls())) + if left_type.share() == .shared_t { g.go_back(1) } g.expr(left) - if typ.share() == .shared_t { + if left_type.share() == .shared_t { g.write('->val') } g.write(', ') if right.is_auto_deref_var() { g.write('*') } - g.expr(right) + left_sym := g.table.final_sym(left_type) + elem_typ := if left_sym.kind == .array { + left_sym.array_info().elem_type + } else { + left_sym.array_fixed_info().elem_type + } + if g.table.sym(elem_typ).kind in [.interface_, .sum_type] { + g.expr_with_cast(right, right_type, elem_typ) + } else { + g.expr(right) + } g.write(')') } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index fd7b9171bf..5f7cc915c8 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -891,7 +891,7 @@ fn (mut g Gen) gen_array_method_call(node ast.CallExpr, left_type ast.Type) bool return true } 'contains' { - g.gen_array_contains(left_type, node.left, node.args[0].expr) + g.gen_array_contains(left_type, node.left, node.args[0].typ, node.args[0].expr) return true } 'index' { diff --git a/vlib/v/gen/c/infix.v b/vlib/v/gen/c/infix.v index 12c816588b..8d8a156c0e 100644 --- a/vlib/v/gen/c/infix.v +++ b/vlib/v/gen/c/infix.v @@ -488,12 +488,21 @@ fn (mut g Gen) infix_expr_in_op(node ast.InfixExpr) { expr: node.left expr_type: ast.mktyp(node.left_type) } - g.gen_array_contains(node.right_type, node.right, new_node_left) + g.gen_array_contains(node.right_type, node.right, elem_type, new_node_left) return } + } else if elem_type_.sym.kind == .interface_ { + new_node_left := ast.CastExpr{ + arg: ast.empty_expr + typ: elem_type + expr: node.left + expr_type: ast.mktyp(node.left_type) + } + g.gen_array_contains(node.right_type, node.right, elem_type, new_node_left) + return } } - g.gen_array_contains(node.right_type, node.right, node.left) + g.gen_array_contains(node.right_type, node.right, node.left_type, node.left) } else if right.unaliased_sym.kind == .map { g.write('_IN_MAP(') if !left.typ.is_ptr() { @@ -558,12 +567,12 @@ fn (mut g Gen) infix_expr_in_op(node ast.InfixExpr) { expr: node.left expr_type: ast.mktyp(node.left_type) } - g.gen_array_contains(node.right_type, node.right, new_node_left) + g.gen_array_contains(node.right_type, node.right, elem_type, new_node_left) return } } } - g.gen_array_contains(node.right_type, node.right, node.left) + g.gen_array_contains(node.right_type, node.right, node.left_type, node.left) } else if right.unaliased_sym.kind == .string { g.write('string_contains(') g.expr(node.right) diff --git a/vlib/v/tests/array_of_interfaces_index_test.v b/vlib/v/tests/array_of_interfaces_builtin_method_test.v similarity index 82% rename from vlib/v/tests/array_of_interfaces_index_test.v rename to vlib/v/tests/array_of_interfaces_builtin_method_test.v index 0c2324d53e..847dc192c8 100644 --- a/vlib/v/tests/array_of_interfaces_index_test.v +++ b/vlib/v/tests/array_of_interfaces_builtin_method_test.v @@ -24,8 +24,12 @@ fn get_component[T](entity Entity) !&T { fn test_array_of_interfaces_index() { entity := Entity{1, [IsControlledByPlayerTag{}]} - id := entity.components.index(*get_component[IsControlledByPlayerTag](entity)!) + id := entity.components.index(*get_component[IsControlledByPlayerTag](entity)!) println('id = ${id}') assert id == 0 + + ret := entity.components.contains(*get_component[IsControlledByPlayerTag](entity)!) + println(ret) + assert ret }