From 73260c6fc02ffeac4a55bbb94a14b48a9b220639 Mon Sep 17 00:00:00 2001 From: ChAoS_UnItY <43753315+ChAoSUnItY@users.noreply.github.com> Date: Thu, 21 Apr 2022 15:32:29 +0800 Subject: [PATCH] checker, cgen: allow static (fixed) arrays in `in` operator (#14121) --- vlib/v/checker/checker.v | 9 +++++ vlib/v/gen/c/infix.v | 48 +++++++++++++++++++++++++++ vlib/v/gen/js/infix.v | 2 +- vlib/v/tests/fixed_array_in_op_test.v | 8 +++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/fixed_array_in_op_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 865c5e4ed9..227d826147 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -662,6 +662,15 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } node.left_type = map_info.key_type } + .array_fixed { + if left_sym.kind !in [.sum_type, .interface_] { + elem_type := right_final.array_fixed_info().elem_type + c.check_expected(left_type, elem_type) or { + c.error('left operand to `$node.op` does not match the fixed array element type: $err.msg()', + left_right_pos) + } + } + } else { c.error('`$node.op.str()` can only be used with arrays and maps', node.pos) diff --git a/vlib/v/gen/c/infix.v b/vlib/v/gen/c/infix.v index d080855f1e..d76eb3c56d 100644 --- a/vlib/v/gen/c/infix.v +++ b/vlib/v/gen/c/infix.v @@ -441,6 +441,54 @@ fn (mut g Gen) infix_expr_in_op(node ast.InfixExpr) { g.expr(node.right) } g.write(')') + } else if right.unaliased_sym.kind == .array_fixed { + if left.sym.kind in [.sum_type, .interface_] { + if node.right is ast.ArrayInit { + if node.right.exprs.len > 0 { + mut infix_exprs := []ast.InfixExpr{} + for i in 0 .. node.right.exprs.len { + infix_exprs << ast.InfixExpr{ + op: .key_is + left: node.left + left_type: node.left_type + right: node.right.exprs[i] + right_type: node.right.expr_types[i] + } + } + g.write('(') + g.infix_expr_in_sumtype_interface_array(infix_exprs) + g.write(')') + return + } + } + } + if node.right is ast.ArrayInit { + if node.right.exprs.len > 0 { + // `a in [1,2,3]!` optimization => `a == 1 || a == 2 || a == 3` + // avoids an allocation + g.write('(') + g.infix_expr_in_optimization(node.left, node.right) + g.write(')') + return + } + } + if right.sym.info is ast.Array { + elem_type := right.sym.info.elem_type + elem_type_ := g.unwrap(elem_type) + if elem_type_.sym.kind == .sum_type { + if node.left_type in elem_type_.sym.sumtype_info().variants { + new_node_left := ast.CastExpr{ + arg: ast.EmptyExpr{} + typ: elem_type + expr: node.left + expr_type: node.left_type + } + g.gen_array_contains(node.right_type, node.right, new_node_left) + return + } + } + } + g.gen_array_contains(node.right_type, node.right, node.left) } else if right.unaliased_sym.kind == .string { g.write('string_contains(') g.expr(node.right) diff --git a/vlib/v/gen/js/infix.v b/vlib/v/gen/js/infix.v index f936070be9..df8af67d78 100644 --- a/vlib/v/gen/js/infix.v +++ b/vlib/v/gen/js/infix.v @@ -282,7 +282,7 @@ fn (mut g JsGen) infix_in_not_in_op(node ast.InfixExpr) { if node.op == .not_in { g.write('!') } - if r_sym.unaliased_sym.kind == .array { + if r_sym.unaliased_sym.kind in [.array, .array_fixed] { fn_name := g.gen_array_contains_method(node.right_type) g.write('(${fn_name}(') g.expr(node.right) diff --git a/vlib/v/tests/fixed_array_in_op_test.v b/vlib/v/tests/fixed_array_in_op_test.v new file mode 100644 index 0000000000..767df764a8 --- /dev/null +++ b/vlib/v/tests/fixed_array_in_op_test.v @@ -0,0 +1,8 @@ +fn test_fixed_array_in_op() { + assert 1 in [1, 2]! + assert `a` in [`a`, `b`]! + assert 'a' in ['a', 'b']! + + ch := `"` + assert ch in [`"`, `'`]! +}