From 715a0a656ebef4a8a6dd285a55149402d2a6c2be Mon Sep 17 00:00:00 2001 From: shove Date: Fri, 15 Dec 2023 21:18:26 +0800 Subject: [PATCH] ast: fix dimension mismatch check for fn/method mut array args (fix #20172) (#20173) --- vlib/v/ast/table.v | 39 +++++++------------ vlib/v/ast/types.v | 24 +++++++++--- .../tests/fn_call_arg_array_mismatch_err.out | 19 ++++++--- .../tests/fn_call_arg_array_mismatch_err.vv | 20 ++++++++-- 4 files changed, 63 insertions(+), 39 deletions(-) diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index e18c251579d8bd..5ebf540e4d2320 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1569,14 +1569,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name } match mut sym.info { Array { - mut elem_type := sym.info.elem_type - mut elem_sym := t.sym(elem_type) - mut dims := 1 - for mut elem_sym.info is Array { - elem_type = elem_sym.info.elem_type - elem_sym = t.sym(elem_type) - dims++ - } + dims, elem_type := t.get_array_dims(sym.info) if typ := t.resolve_generic_to_concrete(elem_type, generic_names, concrete_types) { idx := t.find_or_register_array_with_dims(typ, dims) if typ.has_flag(.generic) { @@ -1782,14 +1775,7 @@ pub fn (mut t Table) generic_type_names(generic_type Type) []string { } match mut sym.info { Array { - mut elem_type := sym.info.elem_type - mut elem_sym := t.sym(elem_type) - mut dims := 1 - for mut elem_sym.info is Array { - elem_type = elem_sym.info.elem_type - elem_sym = t.sym(elem_type) - dims++ - } + _, elem_type := t.get_array_dims(sym.info) names << t.generic_type_names(elem_type) } ArrayFixed { @@ -1847,14 +1833,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr ts := t.sym(typ) match ts.info { Array { - mut elem_type := ts.info.elem_type - mut elem_sym := t.sym(elem_type) - mut dims := 1 - for mut elem_sym.info is Array { - elem_type = elem_sym.info.elem_type - elem_sym = t.sym(elem_type) - dims++ - } + dims, elem_type := t.get_array_dims(ts.info) unwrap_typ := t.unwrap_generic_type(elem_type, generic_names, concrete_types) idx := t.find_or_register_array_with_dims(unwrap_typ, dims) return new_type(idx).derive_add_muls(typ).clear_flag(.generic) @@ -2549,3 +2528,15 @@ pub fn (t &Table) dependent_names_in_stmt(stmt Stmt) []string { } return names } + +pub fn (t &Table) get_array_dims(arr Array) (int, Type) { + mut dims := 1 + mut elem_type := arr.elem_type + mut elem_sym := t.sym(elem_type) + for mut elem_sym.info is Array { + dims++ + elem_type = elem_sym.info.elem_type + elem_sym = t.sym(elem_type) + } + return dims, elem_type +} diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 1641130ef27ccb..19b1690f6ac7a7 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -1535,18 +1535,32 @@ pub fn (t &Table) fn_signature_using_aliases(func &Fn, import_aliases map[string } // symbol_name_except_generic return the name of the complete qualified name of the type, -// but without the generic parts. For example: +// but without the generic parts. The potential `[]`, `&[][]` etc prefixes are kept. For example: // `main.Abc[int]` -> `main.Abc` // `main.Abc[int]` -> `main.Abc` +// `[]main.Abc[int]` -> `[]main.Abc` +// `&[][]main.Abc[int]` -> `&[][]main.Abc` pub fn (t &TypeSymbol) symbol_name_except_generic() string { + // &[]main.Abc[int], [][]main.Abc[int]... + mut prefix := '' + mut name := t.name + for i, ch in t.name { + if ch in [`&`, `[`, `]`] { + continue + } + if i > 0 { + prefix = t.name[..i] + name = t.name[i..] + } + break + } // main.Abc[int] - mut embed_name := t.name // remove generic part from name // main.Abc[int] => main.Abc - if embed_name.contains('[') { - embed_name = embed_name.all_before('[') + if name.contains('[') { + name = name.all_before('[') } - return embed_name + return prefix + name } // embed_name return the pure name of the complete qualified name of the type, diff --git a/vlib/v/checker/tests/fn_call_arg_array_mismatch_err.out b/vlib/v/checker/tests/fn_call_arg_array_mismatch_err.out index 789d65e8e59d6e..40cc375568ce60 100644 --- a/vlib/v/checker/tests/fn_call_arg_array_mismatch_err.out +++ b/vlib/v/checker/tests/fn_call_arg_array_mismatch_err.out @@ -1,7 +1,14 @@ -vlib/v/checker/tests/fn_call_arg_array_mismatch_err.vv:9:36: error: cannot use `string` as `array` in argument 2 to `os.write_file_array` - 7 | - 8 | fn main() { - 9 | os.write_file_array(service_path, service_file) or { +vlib/v/checker/tests/fn_call_arg_array_mismatch_err.vv:7:36: error: cannot use `string` as `array` in argument 2 to `os.write_file_array` + 5 | + 6 | fn main() { + 7 | os.write_file_array(service_path, service_file) or { | ~~~~~~~~~~~~ - 10 | eprintln('Error: write file service') - 11 | exit(1) + 8 | eprintln('Error: write file service') + 9 | exit(1) +vlib/v/checker/tests/fn_call_arg_array_mismatch_err.vv:16:10: error: cannot use `&[]int` as `&[][]int` in argument 1 to `bar` + 14 | // dimension checking error when mut array is passed multiple times as args + 15 | fn foo(mut arr []int) { + 16 | bar(mut arr) + | ~~~ + 17 | } + 18 | diff --git a/vlib/v/checker/tests/fn_call_arg_array_mismatch_err.vv b/vlib/v/checker/tests/fn_call_arg_array_mismatch_err.vv index 9f3dc8be4b55ce..f2d9baa3cf9f6d 100644 --- a/vlib/v/checker/tests/fn_call_arg_array_mismatch_err.vv +++ b/vlib/v/checker/tests/fn_call_arg_array_mismatch_err.vv @@ -1,9 +1,7 @@ import os -const ( - service_file = '[Unit]' - service_path = 'dockerman.service' -) +const service_file = '[Unit]' +const service_path = 'dockerman.service' fn main() { os.write_file_array(service_path, service_file) or { @@ -11,3 +9,17 @@ fn main() { exit(1) } } + +// for issue 20172 +// dimension checking error when mut array is passed multiple times as args +fn foo(mut arr []int) { + bar(mut arr) +} + +fn bar(mut arr [][]int) { +} + +fn baz() { + mut arr := [1, 2, 3] + foo(mut arr) +}