From ddcbc4440b67c9c4b369a53230b61aeb95096a5f Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 29 Jan 2021 18:20:28 +0800 Subject: [PATCH] cgen: fix array_sort_by_references (fix #8390) (#8403) --- vlib/v/gen/array.v | 15 ++++++++++----- vlib/v/tests/sorting_by_references_test.v | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 vlib/v/tests/sorting_by_references_test.v diff --git a/vlib/v/gen/array.v b/vlib/v/gen/array.v index e3a4da3759..ee379ee9d0 100644 --- a/vlib/v/gen/array.v +++ b/vlib/v/gen/array.v @@ -253,17 +253,18 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) { // `users.sort(a.age > b.age)` // Generate a comparison function for a custom type tmp_name := g.new_tmp_var() - compare_fn = 'compare_${tmp_name}_' + g.typ(typ) + styp := g.typ(typ).trim('*') + compare_fn = 'compare_${tmp_name}_$styp' if is_reverse { compare_fn += '_reverse' } // Register a new custom `compare_xxx` function for qsort() g.table.register_fn(name: compare_fn, return_type: table.int_type) infix_expr := node.args[0].expr as ast.InfixExpr - styp := g.typ(typ) // Variables `a` and `b` are used in the `.sort(a < b)` syntax, so we can reuse them // when generating the function as long as the args are named the same. - g.definitions.writeln('int $compare_fn ($styp* a, $styp* b) {') + styp_arg := g.typ(typ) + g.definitions.writeln('int $compare_fn ($styp_arg* a, $styp_arg* b) {') sym := g.table.get_type_symbol(typ) if !is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 { g.definitions.writeln('\tif (${styp}__lt(*a, *b)) { return -1; } else { return 1; }}') @@ -271,8 +272,12 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) { g.definitions.writeln('\tif (${styp}__gt(*a, *b)) { return -1; } else { return 1; }}') } else { field_type := g.typ(infix_expr.left_type) - left_expr_str := g.write_expr_to_string(infix_expr.left) - right_expr_str := g.write_expr_to_string(infix_expr.right) + mut left_expr_str := g.write_expr_to_string(infix_expr.left) + mut right_expr_str := g.write_expr_to_string(infix_expr.right) + if typ.is_ptr() { + left_expr_str = left_expr_str.replace_once('a', '(*a)') + right_expr_str = right_expr_str.replace_once('b', '(*b)') + } g.definitions.writeln('$field_type a_ = $left_expr_str;') g.definitions.writeln('$field_type b_ = $right_expr_str;') mut op1, mut op2 := '', '' diff --git a/vlib/v/tests/sorting_by_references_test.v b/vlib/v/tests/sorting_by_references_test.v new file mode 100644 index 0000000000..d2e5434a43 --- /dev/null +++ b/vlib/v/tests/sorting_by_references_test.v @@ -0,0 +1,22 @@ +struct Container { +mut: + name string +} + +fn test_array_sort_by_references() { + mut a := []&Container{} + + a << &Container{ name: 'a' } + a << &Container{ name: 'b' } + a << &Container{ name: 'c' } + a << &Container{ name: 'd' } + a << &Container{ name: 'e' } + + a.sort(a.name > b.name) + println(a) + assert a[0].name == 'e' + assert a[1].name == 'd' + assert a[2].name == 'c' + assert a[3].name == 'b' + assert a[4].name == 'a' +}