diff --git a/vlib/builtin/fixed_array_index_test.v b/vlib/builtin/fixed_array_index_test.v new file mode 100644 index 00000000000000..6cd2c8a21a6b58 --- /dev/null +++ b/vlib/builtin/fixed_array_index_test.v @@ -0,0 +1,35 @@ +fn test_index_of_ints() { + ia := [1, 2, 3]! + ii := ia.index(2) + dump(ii) + assert ii == 1 +} + +fn test_index_of_strings() { + sa := ['a', 'b', 'c']! + si := sa.index('b') + dump(si) + assert si == 1 +} + +fn test_index_of_voidptrs() { + pa := [voidptr(123), voidptr(45), voidptr(99)]! + pi := pa.index(voidptr(45)) + dump(pi) + assert pi == 1 +} + +////////// + +fn a() {} + +fn b() {} + +fn c() {} + +fn test_index_of_fns() { + fa := [a, b, c]! + fi := fa.index(b) + dump(fi) + assert fi == 1 +} diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index b41cbf0f6f247b..ed75454a523408 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -2064,6 +2064,9 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { if final_left_sym.kind == .array && array_builtin_methods_chk.matches(method_name) && !(left_sym.kind == .alias && left_sym.has_method(method_name)) { return c.array_builtin_method_call(mut node, left_type) + } else if final_left_sym.kind == .array_fixed && method_name in ['index', 'all', 'any', 'map'] + && !(left_sym.kind == .alias && left_sym.has_method(method_name)) { + return c.fixed_array_builtin_method_call(mut node, left_type) } else if final_left_sym.kind == .map && method_name in ['clone', 'keys', 'values', 'move', 'delete'] && !(left_sym.kind == .alias && left_sym.has_method(method_name)) { @@ -3466,6 +3469,34 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as return node.return_type } +fn (mut c Checker) fixed_array_builtin_method_call(mut node ast.CallExpr, left_type ast.Type) ast.Type { + left_sym := c.table.final_sym(left_type) + method_name := node.name + 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.ArrayFixed { + left_sym.info as ast.ArrayFixed + } else { + c.table.sym(unaliased_left_type).info as ast.ArrayFixed + } + elem_typ := array_info.elem_type + if method_name == 'index' { + if node.args.len != 1 { + c.error('`.index()` expected 1 argument, but got ${node.args.len}', node.pos) + } else if !left_sym.has_method('index') { + arg_typ := c.expr(mut node.args[0].expr) + c.check_expected_call_arg(arg_typ, elem_typ, node.language, node.args[0]) or { + c.error('${err.msg()} in argument 1 to `.index()`', node.args[0].pos) + } + } + for i, mut arg in node.args { + node.args[i].typ = c.expr(mut arg.expr) + } + node.return_type = ast.int_type + } + return node.return_type +} + fn (mut c Checker) check_for_mut_receiver(mut expr ast.Expr) (string, token.Pos) { to_lock, pos := c.fail_if_immutable(mut expr) if !expr.is_lvalue() { diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index 51c3a47f2bd6ae..f6d3e478292f60 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -1096,50 +1096,96 @@ fn (mut g Gen) gen_array_index_methods() { final_left_sym := g.table.final_sym(t) mut left_type_str := g.typ(t) fn_name := '${left_type_str}_index' - info := final_left_sym.info as ast.Array - mut elem_type_str := g.typ(info.elem_type) - elem_sym := g.table.sym(info.elem_type) - if elem_sym.kind == .function { - left_type_str = 'Array_voidptr' - elem_type_str = 'voidptr' - } - g.type_definitions.writeln('static int ${fn_name}(${left_type_str} a, ${elem_type_str} v); // auto') mut fn_builder := strings.new_builder(512) - fn_builder.writeln('static int ${fn_name}(${left_type_str} a, ${elem_type_str} v) {') - fn_builder.writeln('\t${elem_type_str}* pelem = a.data;') - fn_builder.writeln('\tfor (int i = 0; i < a.len; ++i, ++pelem) {') - if elem_sym.kind == .string { - fn_builder.writeln('\t\tif (fast_string_eq(*pelem, v)) {') - } else if elem_sym.kind in [.array, .array_fixed] && !info.elem_type.is_ptr() { - ptr_typ := g.equality_fn(info.elem_type) - fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(*pelem, v)) {') - } else if elem_sym.kind == .function && !info.elem_type.is_ptr() { - fn_builder.writeln('\t\tif ( *pelem == v) {') - } else if elem_sym.kind == .map && !info.elem_type.is_ptr() { - ptr_typ := g.equality_fn(info.elem_type) - fn_builder.writeln('\t\tif (${ptr_typ}_map_eq((*pelem, v))) {') - } else if elem_sym.kind == .struct && !info.elem_type.is_ptr() { - ptr_typ := g.equality_fn(info.elem_type) - fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(*pelem, v)) {') - } else if elem_sym.kind == .interface { - ptr_typ := g.equality_fn(info.elem_type) - if info.elem_type.is_ptr() { - fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(**pelem, *v)) {') + + if final_left_sym.kind == .array { + info := final_left_sym.info as ast.Array + mut elem_type_str := g.typ(info.elem_type) + elem_sym := g.table.sym(info.elem_type) + if elem_sym.kind == .function { + left_type_str = 'Array_voidptr' + elem_type_str = 'voidptr' + } + g.type_definitions.writeln('static int ${fn_name}(${left_type_str} a, ${elem_type_str} v); // auto') + fn_builder.writeln('static int ${fn_name}(${left_type_str} a, ${elem_type_str} v) {') + fn_builder.writeln('\t${elem_type_str}* pelem = a.data;') + fn_builder.writeln('\tfor (int i = 0; i < a.len; ++i, ++pelem) {') + if elem_sym.kind == .string { + fn_builder.writeln('\t\tif (fast_string_eq(*pelem, v)) {') + } else if elem_sym.kind in [.array, .array_fixed] && !info.elem_type.is_ptr() { + ptr_typ := g.equality_fn(info.elem_type) + fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(*pelem, v)) {') + } else if elem_sym.kind == .function && !info.elem_type.is_ptr() { + fn_builder.writeln('\t\tif ( *pelem == v) {') + } else if elem_sym.kind == .map && !info.elem_type.is_ptr() { + ptr_typ := g.equality_fn(info.elem_type) + fn_builder.writeln('\t\tif (${ptr_typ}_map_eq((*pelem, v))) {') + } else if elem_sym.kind == .struct && !info.elem_type.is_ptr() { + ptr_typ := g.equality_fn(info.elem_type) + fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(*pelem, v)) {') + } else if elem_sym.kind == .interface { + ptr_typ := g.equality_fn(info.elem_type) + if info.elem_type.is_ptr() { + fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(**pelem, *v)) {') + } else { + fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(*pelem, v)) {') + } + } else if elem_sym.kind == .sum_type { + ptr_typ := g.equality_fn(info.elem_type) + if info.elem_type.is_ptr() { + fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(**pelem, *v)) {') + } else { + fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(*pelem, v)) {') + } + } else if elem_sym.kind == .alias { + ptr_typ := g.equality_fn(info.elem_type) + fn_builder.writeln('\t\tif (${ptr_typ}_alias_eq(*pelem, v)) {') } else { - fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(*pelem, v)) {') + fn_builder.writeln('\t\tif (*pelem == v) {') + } + } else if final_left_sym.kind == .array_fixed { + info := final_left_sym.info as ast.ArrayFixed + mut elem_type_str := g.typ(info.elem_type) + elem_sym := g.table.sym(info.elem_type) + if elem_sym.kind == .function { + elem_type_str = 'voidptr' } - } else if elem_sym.kind == .sum_type { - ptr_typ := g.equality_fn(info.elem_type) - if info.elem_type.is_ptr() { - fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(**pelem, *v)) {') + g.type_definitions.writeln('static int ${fn_name}(${left_type_str} a, ${elem_type_str} v); // auto') + fn_builder.writeln('static int ${fn_name}(${left_type_str} a, ${elem_type_str} v) {') + fn_builder.writeln('\tfor (int i = 0; i < ${info.size}; ++i) {') + if elem_sym.kind == .string { + fn_builder.writeln('\t\tif (fast_string_eq(a[i], v)) {') + } else if elem_sym.kind in [.array, .array_fixed] && !info.elem_type.is_ptr() { + ptr_typ := g.equality_fn(info.elem_type) + fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(a[i], v)) {') + } else if elem_sym.kind == .function && !info.elem_type.is_ptr() { + fn_builder.writeln('\t\tif (a[i] == v) {') + } else if elem_sym.kind == .map && !info.elem_type.is_ptr() { + ptr_typ := g.equality_fn(info.elem_type) + fn_builder.writeln('\t\tif (${ptr_typ}_map_eq((a[i], v))) {') + } else if elem_sym.kind == .struct && !info.elem_type.is_ptr() { + ptr_typ := g.equality_fn(info.elem_type) + fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(a[i], v)) {') + } else if elem_sym.kind == .interface { + ptr_typ := g.equality_fn(info.elem_type) + if info.elem_type.is_ptr() { + fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(*a[i], *v)) {') + } else { + fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(a[i], v)) {') + } + } else if elem_sym.kind == .sum_type { + ptr_typ := g.equality_fn(info.elem_type) + if info.elem_type.is_ptr() { + fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(*a[i], *v)) {') + } else { + fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(a[i], v)) {') + } + } else if elem_sym.kind == .alias { + ptr_typ := g.equality_fn(info.elem_type) + fn_builder.writeln('\t\tif (${ptr_typ}_alias_eq(a[i], v)) {') } else { - fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(*pelem, v)) {') + fn_builder.writeln('\t\tif (a[i] == v) {') } - } else if elem_sym.kind == .alias { - ptr_typ := g.equality_fn(info.elem_type) - fn_builder.writeln('\t\tif (${ptr_typ}_alias_eq(*pelem, v)) {') - } else { - fn_builder.writeln('\t\tif (*pelem == v) {') } fn_builder.writeln('\t\t\treturn i;') fn_builder.writeln('\t\t}') @@ -1160,7 +1206,12 @@ fn (mut g Gen) gen_array_index(node ast.CallExpr) { g.expr(node.left) g.write(', ') - elem_typ := g.table.sym(node.left_type).array_info().elem_type + left_sym := g.table.final_sym(node.left_type) + elem_typ := if left_sym.kind == .array { + left_sym.array_info().elem_type + } else { + left_sym.array_fixed_info().elem_type + } // auto deref var is redundant for interfaces and sum types. if node.args[0].expr.is_auto_deref_var() && g.table.sym(elem_typ).kind !in [.interface, .sum_type] { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 4e3eed6dd28832..fcdbf737f92bc1 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1189,6 +1189,18 @@ fn (mut g Gen) gen_array_method_call(node ast.CallExpr, left_type ast.Type, left return true } +fn (mut g Gen) gen_fixed_array_method_call(node ast.CallExpr, left_type ast.Type, left_sym ast.TypeSymbol) bool { + match node.name { + 'index' { + g.gen_array_index(node) + } + else { + return false + } + } + return true +} + fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool { mut rec_type := node.receiver_type if rec_type.has_flag(.shared_f) { @@ -1680,6 +1692,12 @@ fn (mut g Gen) method_call(node ast.CallExpr) { return } } + if final_left_sym.kind == .array_fixed && !(left_sym.kind == .alias + && left_sym.has_method(node.name)) { + if g.gen_fixed_array_method_call(node, left_type, final_left_sym) { + return + } + } if final_left_sym.kind == .map && !(left_sym.kind == .alias && left_sym.has_method(node.name)) { if g.gen_map_method_call(node, left_type, final_left_sym) { return diff --git a/vlib/v/tests/builtin_arrays/fixed_array_literal_infix_test.v b/vlib/v/tests/builtin_arrays/fixed_array_literal_infix_test.v index b81d430b3afbf1..7fb81345a38d18 100644 --- a/vlib/v/tests/builtin_arrays/fixed_array_literal_infix_test.v +++ b/vlib/v/tests/builtin_arrays/fixed_array_literal_infix_test.v @@ -24,3 +24,12 @@ fn test_array_of_fixed_array_index() { println(ret) assert ret == 0 } + +fn test_fixed_array_of_fixed_array_index() { + mut a := [2][2]int{} + a[0] = [1, 2]! + println(a.index([1, 2]!)) + ret := a.index([1, 2]!) + println(ret) + assert ret == 0 +}