From b9fce4ef09f3f9444cd50fd8ce2644bee55935a5 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Fri, 4 Feb 2022 23:11:24 +0100 Subject: [PATCH] checker: make sure that the operator check is made on the concrete type (#13360) --- vlib/v/checker/checker.v | 16 +++++++++-- vlib/v/checker/tests/cmp_between_struct.out | 21 ++++++++++++++ vlib/v/checker/tests/cmp_between_struct.vv | 31 +++++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 vlib/v/checker/tests/cmp_between_struct.out create mode 100644 vlib/v/checker/tests/cmp_between_struct.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index eefacfedd3..b36bf617c5 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -541,10 +541,10 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { defer { c.expected_type = former_expected_type } - left_type := c.expr(node.left) + mut left_type := c.expr(node.left) node.left_type = left_type c.expected_type = left_type - right_type := c.expr(node.right) + mut right_type := c.expr(node.right) node.right_type = right_type if left_type.is_number() && !left_type.is_ptr() && right_type in [ast.int_literal_type, ast.float_literal_type] { @@ -796,6 +796,18 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } else if !left_sym.has_method('<') && node.op == .gt { c.error('cannot use `>` as `<=` operator method is not defined', left_right_pos) } + } else if left_type.has_flag(.generic) && right_type.has_flag(.generic) { + // Try to unwrap the generic type to make sure that + // the below check works as expected + left_gen_type := c.unwrap_generic(left_type) + gen_sym := c.table.sym(left_gen_type) + need_overload := gen_sym.kind in [.struct_, .interface_] + if need_overload && !gen_sym.has_method('<') && node.op in [.ge, .le] { + c.error('cannot use `$node.op` as `<` operator method is not defined', + left_right_pos) + } else if need_overload && !gen_sym.has_method('<') && node.op == .gt { + c.error('cannot use `>` as `<=` operator method is not defined', left_right_pos) + } } } .left_shift { diff --git a/vlib/v/checker/tests/cmp_between_struct.out b/vlib/v/checker/tests/cmp_between_struct.out new file mode 100644 index 0000000000..20fd38d169 --- /dev/null +++ b/vlib/v/checker/tests/cmp_between_struct.out @@ -0,0 +1,21 @@ +vlib/datatypes/heap.v:16:15: error: cannot use `>` as `<=` operator method is not defined + 14 | mut child := heap.data.len - 1 + 15 | mut parent := heap.parent(child) + 16 | for heap.data[parent] > heap.data[child] { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 17 | heap.data[parent], heap.data[child] = heap.data[child], heap.data[parent] + 18 | child = parent +vlib/datatypes/heap.v:37:15: error: cannot use `>` as `<=` operator method is not defined + 35 | mut left := heap.left_child(parent) or { return item } + 36 | mut right := heap.right_child(parent) or { left } + 37 | for heap.data[parent] > heap.data[left] || heap.data[parent] > heap.data[right] { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + 38 | // choose min for min heap + 39 | swap := if heap.data[left] <= heap.data[right] { left } else { right } +vlib/datatypes/heap.v:39:23: error: cannot use `<=` as `<` operator method is not defined + 37 | for heap.data[parent] > heap.data[left] || heap.data[parent] > heap.data[right] { + 38 | // choose min for min heap + 39 | swap := if heap.data[left] <= heap.data[right] { left } else { right } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + 40 | heap.data[parent], heap.data[swap] = heap.data[swap], heap.data[parent] + 41 | parent = swap diff --git a/vlib/v/checker/tests/cmp_between_struct.vv b/vlib/v/checker/tests/cmp_between_struct.vv new file mode 100644 index 0000000000..ea36b1ff4b --- /dev/null +++ b/vlib/v/checker/tests/cmp_between_struct.vv @@ -0,0 +1,31 @@ +module main + +import datatypes + +struct Item { + priority int +} + +// Issue https://github.com/vlang/v/issues/13318 + +/* +fn (a Item) < (b Item) bool { + return a.priority < b.priority +} + +fn (a Item) == (b Item) bool { + return a.priority == b.priority +} +*/ + +fn main() { + min_heap() +} + +fn min_heap() { + mut heap := datatypes.MinHeap{} + + heap.insert(Item{10}) + + println(heap) +}