From 0208e9672d0a044a326f8e1ad6f7710fbd91b31d Mon Sep 17 00:00:00 2001 From: yuyi Date: Sat, 19 Feb 2022 16:06:36 +0800 Subject: [PATCH] checker: check array sort_with_compare callback function parameters (#13511) --- vlib/v/checker/fn.v | 22 ++++++++ .../tests/array_sort_with_compare_err.out | 7 +++ .../array_sort_with_compare_ref_elem_err.out | 7 +++ .../array_sort_with_compare_ref_elem_err.vv | 54 +++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.out create mode 100644 vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.vv diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 14272734a8..352b4e3725 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1313,6 +1313,28 @@ 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) + } + } + } + } // Handle expected interface if final_arg_sym.kind == .interface_ { if c.type_implements(got_arg_typ, final_arg_typ, arg.expr.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 6670e5bf4e..47b67389cb 100644 --- a/vlib/v/checker/tests/array_sort_with_compare_err.out +++ b/vlib/v/checker/tests/array_sort_with_compare_err.out @@ -1,3 +1,10 @@ +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 | + 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 | 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 new file mode 100644 index 0000000000..32915e9ba3 --- /dev/null +++ b/vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.out @@ -0,0 +1,7 @@ +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 | + 21 | fn sort_cells_by_yx(a &Cell, b &Cell) int { + | ^ + 22 | if a.pos.y == b.pos.y { + 23 | if a.pos.x < b.pos.x { diff --git a/vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.vv b/vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.vv new file mode 100644 index 0000000000..8d64744fe7 --- /dev/null +++ b/vlib/v/checker/tests/array_sort_with_compare_ref_elem_err.vv @@ -0,0 +1,54 @@ +struct Vec2 { + x f32 + y f32 +} + +interface Cell { +mut: + pos Vec2 +} + +struct GridCell { +mut: + pos Vec2 +} + +pub struct Grid2D { +mut: + cells []&Cell +} + +fn sort_cells_by_yx(a &Cell, b &Cell) int { + if a.pos.y == b.pos.y { + if a.pos.x < b.pos.x { + return -1 + } else { + return 1 + } + } else { + if a.pos.y < b.pos.y { + return -1 + } else { + return 1 + } + } +} + +fn (mut g Grid2D) sort_cells() { + g.cells.sort_with_compare(sort_cells_by_yx) +} + +fn main() { + mut grid := Grid2D{} + grid.cells << GridCell{ + pos: Vec2{0, 0} + } + grid.cells << GridCell{ + pos: Vec2{1, 0} + } + grid.cells << GridCell{ + pos: Vec2{1, 2} + } + grid.sort_cells() + println(grid) +}