diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 355be70ecf..6b9b524812 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1297,26 +1297,12 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { c.fail_if_unreadable(arg.expr, got_arg_typ, 'argument') } } - if left_sym.kind == .array && method_name == 'sort_with_compare' { - array_info := left_sym.info as ast.Array - elem_typ := array_info.elem_type - arg_sym := c.table.sym(arg.typ) - if arg_sym.kind == .function { - func_info := arg_sym.info as ast.FnType - if func_info.func.params.len == 2 { - if func_info.func.params[0].typ.nr_muls() != elem_typ.nr_muls() + 1 { - arg_typ_str := c.table.type_to_str(func_info.func.params[0].typ) - expected_typ_str := c.table.type_to_str(elem_typ.ref()) - c.error('sort_with_compare callback function parameter `${func_info.func.params[0].name}` with type `$arg_typ_str` should be `$expected_typ_str`', - func_info.func.params[0].type_pos) - } - if func_info.func.params[1].typ.nr_muls() != elem_typ.nr_muls() + 1 { - arg_typ_str := c.table.type_to_str(func_info.func.params[1].typ) - expected_typ_str := c.table.type_to_str(elem_typ.ref()) - c.error('sort_with_compare callback function parameter `${func_info.func.params[1].name}` with type `$arg_typ_str` should be `$expected_typ_str`', - func_info.func.params[1].type_pos) - } - } + if left_sym.kind == .array { + if method_name == 'sort_with_compare' { + c.check_sort_cb_args(2, 'sort_with_compare', left_sym, arg) + } + if method_name == 'sort_with_compare_context' { + c.check_sort_cb_args(3, 'sort_with_compare_context', left_sym, arg) } } // Handle expected interface @@ -1844,3 +1830,26 @@ fn scope_register_a_b(mut s ast.Scope, pos token.Pos, typ ast.Type) { is_used: true }) } + +fn (mut c Checker) check_sort_cb_args(howmany int, fname string, left_sym &ast.TypeSymbol, arg &ast.CallArg) { + array_info := left_sym.info as ast.Array + elem_typ := array_info.elem_type + arg_sym := c.table.sym(arg.typ) + if arg_sym.kind != .function { + return + } + func_info := arg_sym.info as ast.FnType + if func_info.func.params.len != howmany { + c.error('$fname callback should have exactly $howmany parameters', arg.expr.pos()) + return + } + desired_et_muls := elem_typ.nr_muls() + 1 + expected_typ_str := c.table.type_to_str(elem_typ.ref()) + for k in 0 .. 2 { + if func_info.func.params[k].typ.nr_muls() != desired_et_muls { + arg_typ_str := c.table.type_to_str(func_info.func.params[k].typ) + c.error('$fname callback function parameter `${func_info.func.params[k].name}` with type `$arg_typ_str` should be `$expected_typ_str`', + func_info.func.params[k].type_pos) + } + } +} diff --git a/vlib/v/checker/tests/array_sort_with_compare_err.out b/vlib/v/checker/tests/array_sort_with_compare_err.out index 47b67389cb..ab7913431c 100644 --- a/vlib/v/checker/tests/array_sort_with_compare_err.out +++ b/vlib/v/checker/tests/array_sort_with_compare_err.out @@ -1,13 +1,13 @@ vlib/v/checker/tests/array_sort_with_compare_err.vv:11:24: error: sort_with_compare callback function parameter `a` with type `string` should be `&string` 9 | } - 10 | + 10 | 11 | fn sort_by_file_base(a string, b string) int { | ~~~~~~ 12 | return int(a > b) 13 | } vlib/v/checker/tests/array_sort_with_compare_err.vv:4:26: error: cannot use `fn (string, string) int` as `fn (voidptr, voidptr) int` in argument 1 to `[]string.sort_with_compare` 2 | mut names := ['aaa', 'bbb', 'ccc'] - 3 | + 3 | 4 | names.sort_with_compare(sort_by_file_base) | ~~~~~~~~~~~~~~~~~ 5 | println(names) @@ -15,7 +15,7 @@ vlib/v/checker/tests/array_sort_with_compare_err.vv:4:26: error: cannot use `fn Details: ``'s expected fn argument: `` is a pointer, but the passed fn argument: `a` is NOT a pointer vlib/v/checker/tests/array_sort_with_compare_err.vv:7:26: error: cannot use `int literal` as `fn (voidptr, voidptr) int` in argument 1 to `[]string.sort_with_compare` 5 | println(names) - 6 | + 6 | 7 | names.sort_with_compare(22) | ~~ 8 | println(names) diff --git a/vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.out b/vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.out index 32915e9ba3..16d5d96e81 100644 --- a/vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.out +++ b/vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.out @@ -1,6 +1,6 @@ vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.vv:21:23: error: sort_with_compare callback function parameter `a` with type `&Cell` should be `&&Cell` 19 | } - 20 | + 20 | 21 | fn sort_cells_by_yx(a &Cell, b &Cell) int { | ^ 22 | if a.pos.y == b.pos.y { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 15ddbc5b97..a3414564c6 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -952,7 +952,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { receiver_type_name = 'map' } if final_left_sym.kind == .array - && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'pop', 'clone', 'reverse', 'slice', 'pointers'] { + && node.name in ['repeat', 'sort_with_compare', 'sort_with_compare_context', 'free', 'push_many', 'trim', 'first', 'last', 'pop', 'clone', 'reverse', 'slice', 'pointers'] { if !(left_sym.info is ast.Alias && typ_sym.has_method(node.name)) { // `array_Xyz_clone` => `array_clone` receiver_type_name = 'array' diff --git a/vlib/v/gen/js/fn.v b/vlib/v/gen/js/fn.v index d583111314..80660d4584 100644 --- a/vlib/v/gen/js/fn.v +++ b/vlib/v/gen/js/fn.v @@ -318,7 +318,7 @@ fn (mut g JsGen) method_call(node ast.CallExpr) { } } if final_left_sym.kind == .array - && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'pop', 'clone', 'reverse', 'slice', 'pointers'] { + && node.name in ['repeat', 'sort_with_compare', 'sort_with_compare_context', 'free', 'push_many', 'trim', 'first', 'last', 'pop', 'clone', 'reverse', 'slice', 'pointers'] { if !(left_sym.info is ast.Alias && typ_sym.has_method(node.name)) { // `array_Xyz_clone` => `array_clone` receiver_type_name = 'array'