mirror of
https://github.com/vlang/v.git
synced 2025-09-14 15:02:33 +03:00
checker, cgen: implement .index/1 method for fixed arrays (#22593)
This commit is contained in:
parent
14ca0f533f
commit
39c69c5fc8
5 changed files with 201 additions and 41 deletions
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)
|
if final_left_sym.kind == .array && array_builtin_methods_chk.matches(method_name)
|
||||||
&& !(left_sym.kind == .alias && left_sym.has_method(method_name)) {
|
&& !(left_sym.kind == .alias && left_sym.has_method(method_name)) {
|
||||||
return c.array_builtin_method_call(mut node, left_type)
|
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
|
} else if final_left_sym.kind == .map
|
||||||
&& method_name in ['clone', 'keys', 'values', 'move', 'delete'] && !(left_sym.kind == .alias
|
&& method_name in ['clone', 'keys', 'values', 'move', 'delete'] && !(left_sym.kind == .alias
|
||||||
&& left_sym.has_method(method_name)) {
|
&& 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
|
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) {
|
fn (mut c Checker) check_for_mut_receiver(mut expr ast.Expr) (string, token.Pos) {
|
||||||
to_lock, pos := c.fail_if_immutable(mut expr)
|
to_lock, pos := c.fail_if_immutable(mut expr)
|
||||||
if !expr.is_lvalue() {
|
if !expr.is_lvalue() {
|
||||||
|
|
|
@ -1096,50 +1096,96 @@ fn (mut g Gen) gen_array_index_methods() {
|
||||||
final_left_sym := g.table.final_sym(t)
|
final_left_sym := g.table.final_sym(t)
|
||||||
mut left_type_str := g.typ(t)
|
mut left_type_str := g.typ(t)
|
||||||
fn_name := '${left_type_str}_index'
|
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)
|
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;')
|
if final_left_sym.kind == .array {
|
||||||
fn_builder.writeln('\tfor (int i = 0; i < a.len; ++i, ++pelem) {')
|
info := final_left_sym.info as ast.Array
|
||||||
if elem_sym.kind == .string {
|
mut elem_type_str := g.typ(info.elem_type)
|
||||||
fn_builder.writeln('\t\tif (fast_string_eq(*pelem, v)) {')
|
elem_sym := g.table.sym(info.elem_type)
|
||||||
} else if elem_sym.kind in [.array, .array_fixed] && !info.elem_type.is_ptr() {
|
if elem_sym.kind == .function {
|
||||||
ptr_typ := g.equality_fn(info.elem_type)
|
left_type_str = 'Array_voidptr'
|
||||||
fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(*pelem, v)) {')
|
elem_type_str = 'voidptr'
|
||||||
} 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 {
|
g.type_definitions.writeln('static int ${fn_name}(${left_type_str} a, ${elem_type_str} v); // auto')
|
||||||
ptr_typ := g.equality_fn(info.elem_type)
|
fn_builder.writeln('static int ${fn_name}(${left_type_str} a, ${elem_type_str} v) {')
|
||||||
if info.elem_type.is_ptr() {
|
fn_builder.writeln('\t${elem_type_str}* pelem = a.data;')
|
||||||
fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(**pelem, *v)) {')
|
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 {
|
} 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\treturn i;')
|
||||||
fn_builder.writeln('\t\t}')
|
fn_builder.writeln('\t\t}')
|
||||||
|
@ -1160,7 +1206,12 @@ fn (mut g Gen) gen_array_index(node ast.CallExpr) {
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write(', ')
|
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.
|
// auto deref var is redundant for interfaces and sum types.
|
||||||
if node.args[0].expr.is_auto_deref_var()
|
if node.args[0].expr.is_auto_deref_var()
|
||||||
&& g.table.sym(elem_typ).kind !in [.interface, .sum_type] {
|
&& 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
|
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 {
|
fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool {
|
||||||
mut rec_type := node.receiver_type
|
mut rec_type := node.receiver_type
|
||||||
if rec_type.has_flag(.shared_f) {
|
if rec_type.has_flag(.shared_f) {
|
||||||
|
@ -1680,6 +1692,12 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
return
|
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 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) {
|
if g.gen_map_method_call(node, left_type, final_left_sym) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -24,3 +24,12 @@ fn test_array_of_fixed_array_index() {
|
||||||
println(ret)
|
println(ret)
|
||||||
assert ret == 0
|
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…
Add table
Add a link
Reference in a new issue