mirror of
https://github.com/vlang/v.git
synced 2025-09-14 01:47:30 -04:00
checker, cgen: implement .index/1 method for fixed arrays (#22593)
This commit is contained in:
parent
14ca0f533f
commit
39c69c5fc8
51
vlib/builtin/fixed_array_index_test.v
Normal file
51
vlib/builtin/fixed_array_index_test.v
Normal file
@ -0,0 +1,51 @@
|
||||
fn test_index_of_ints() {
|
||||
ia := [1, 2, 3]!
|
||||
mut ii := ia.index(2)
|
||||
dump(ii)
|
||||
assert ii == 1
|
||||
|
||||
ii = ia.index(5)
|
||||
dump(ii)
|
||||
assert ii == -1
|
||||
}
|
||||
|
||||
fn test_index_of_strings() {
|
||||
sa := ['a', 'b', 'c']!
|
||||
mut si := sa.index('b')
|
||||
dump(si)
|
||||
assert si == 1
|
||||
|
||||
si = sa.index('v')
|
||||
dump(si)
|
||||
assert si == -1
|
||||
}
|
||||
|
||||
fn test_index_of_voidptrs() {
|
||||
pa := [voidptr(123), voidptr(45), voidptr(99)]!
|
||||
mut pi := pa.index(voidptr(45))
|
||||
dump(pi)
|
||||
assert pi == 1
|
||||
|
||||
pi = pa.index(unsafe { nil })
|
||||
dump(pi)
|
||||
assert pi == -1
|
||||
}
|
||||
|
||||
fn a() {}
|
||||
|
||||
fn b() {}
|
||||
|
||||
fn c() {}
|
||||
|
||||
fn v() {}
|
||||
|
||||
fn test_index_of_fns() {
|
||||
fa := [a, b, c]!
|
||||
mut fi := fa.index(b)
|
||||
dump(fi)
|
||||
assert fi == 1
|
||||
|
||||
fi = fa.index(v)
|
||||
dump(fi)
|
||||
assert fi == -1
|
||||
}
|
@ -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() {
|
||||
|
@ -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)) {')
|
||||
} else {
|
||||
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'
|
||||
}
|
||||
} 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('\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}_sumtype_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'
|
||||
}
|
||||
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 (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] {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user