From 814d6823b45845fe729bc16594c3b29369ddba3a Mon Sep 17 00:00:00 2001 From: yuyi Date: Sat, 13 May 2023 11:54:08 +0800 Subject: [PATCH] checker: check generic undefined operation (fix #18162) (#18166) --- vlib/v/checker/infix.v | 11 +++++-- .../tests/generics_undefined_operation_2.out | 7 ++++ .../tests/generics_undefined_operation_2.vv | 33 +++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 vlib/v/checker/tests/generics_undefined_operation_2.out create mode 100644 vlib/v/checker/tests/generics_undefined_operation_2.vv diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index b6fc902fce..ce395ade0c 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -383,6 +383,10 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } } .gt, .lt, .ge, .le { + unwrapped_left_type := c.unwrap_generic(left_type) + left_sym = c.table.sym(unwrapped_left_type) + unwrapped_right_type := c.unwrap_generic(right_type) + right_sym = c.table.sym(unwrapped_right_type) if left_sym.kind in [.array, .array_fixed] && right_sym.kind in [.array, .array_fixed] { c.error('only `==` and `!=` are defined on arrays', node.pos) } else if left_sym.kind == .struct_ @@ -392,8 +396,8 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } else if left_sym.kind == .struct_ && right_sym.kind == .struct_ && node.op in [.eq, .lt] { if !(left_sym.has_method(node.op.str()) && right_sym.has_method(node.op.str())) { - left_name := c.table.type_to_str(left_type) - right_name := c.table.type_to_str(right_type) + left_name := c.table.type_to_str(unwrapped_left_type) + right_name := c.table.type_to_str(unwrapped_right_type) if left_name == right_name { if !(node.op == .lt && c.pref.translated) { // Allow `&Foo < &Foo` in translated code. @@ -670,7 +674,8 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { c.error('only `==`, `!=`, `|` and `&` are defined on `[flag]` tagged `enum`, use an explicit cast to `int` if needed', node.pos) } - } else if !c.pref.translated && !c.file.is_translated { + } else if !c.pref.translated && !c.file.is_translated && !left_type.has_flag(.generic) + && !right_type.has_flag(.generic) { // Regular enums c.error('only `==` and `!=` are defined on `enum`, use an explicit cast to `int` if needed', node.pos) diff --git a/vlib/v/checker/tests/generics_undefined_operation_2.out b/vlib/v/checker/tests/generics_undefined_operation_2.out new file mode 100644 index 0000000000..1a7ea045c8 --- /dev/null +++ b/vlib/v/checker/tests/generics_undefined_operation_2.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/generics_undefined_operation_2.vv:23:18: error: undefined operation `&INode` < `&INode` + 21 | fn (mut h IHeap[T]) percolateup(hl u64, mut element T) { + 22 | mut hole := hl + 23 | for hole > 1 && element < h.array[hole / 2] { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 24 | // ^ Notice that '<' was not defined + 25 | println("didnt define '<' for the INode") diff --git a/vlib/v/checker/tests/generics_undefined_operation_2.vv b/vlib/v/checker/tests/generics_undefined_operation_2.vv new file mode 100644 index 0000000000..41a0bbde85 --- /dev/null +++ b/vlib/v/checker/tests/generics_undefined_operation_2.vv @@ -0,0 +1,33 @@ +pub struct INode { +mut: + heapindex u64 +} + +pub struct IHeap[T] { +mut: + array []&T + size u64 +} + +pub fn create_iheap[T](capacity int) &IHeap[T] { + mut h := &IHeap[T]{ + array: []&T{cap: capacity} + size: 0 + } + h.array << &T(unsafe { nil }) + return h +} + +fn (mut h IHeap[T]) percolateup(hl u64, mut element T) { + mut hole := hl + for hole > 1 && element < h.array[hole / 2] { + // ^ Notice that '<' was not defined + println("didnt define '<' for the INode") + hole /= 2 + } +} + +fn main() { + heap := create_iheap[INode](3000000) + println(heap) +}