1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: check generic undefined operation (fix #18162) (#18166)

This commit is contained in:
yuyi 2023-05-13 11:54:08 +08:00 committed by GitHub
parent 1aadd3e59c
commit 814d6823b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 3 deletions

View File

@ -383,6 +383,10 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
} }
} }
.gt, .lt, .ge, .le { .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] { 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) c.error('only `==` and `!=` are defined on arrays', node.pos)
} else if left_sym.kind == .struct_ } 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_ } else if left_sym.kind == .struct_ && right_sym.kind == .struct_
&& node.op in [.eq, .lt] { && node.op in [.eq, .lt] {
if !(left_sym.has_method(node.op.str()) && right_sym.has_method(node.op.str())) { if !(left_sym.has_method(node.op.str()) && right_sym.has_method(node.op.str())) {
left_name := c.table.type_to_str(left_type) left_name := c.table.type_to_str(unwrapped_left_type)
right_name := c.table.type_to_str(right_type) right_name := c.table.type_to_str(unwrapped_right_type)
if left_name == right_name { if left_name == right_name {
if !(node.op == .lt && c.pref.translated) { if !(node.op == .lt && c.pref.translated) {
// Allow `&Foo < &Foo` in translated code. // 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', c.error('only `==`, `!=`, `|` and `&` are defined on `[flag]` tagged `enum`, use an explicit cast to `int` if needed',
node.pos) 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 // Regular enums
c.error('only `==` and `!=` are defined on `enum`, use an explicit cast to `int` if needed', c.error('only `==` and `!=` are defined on `enum`, use an explicit cast to `int` if needed',
node.pos) node.pos)

View File

@ -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")

View File

@ -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)
}