From d7817863c6b69ab4e062696660f6f58076416ab6 Mon Sep 17 00:00:00 2001
From: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
Date: Fri, 1 Apr 2022 18:31:27 +0200
Subject: [PATCH] checker: type inference over a generic type should compile
 (#13824)

---
 vlib/rand/rand.v                              |  4 +++-
 vlib/v/checker/check_types.v                  |  2 +-
 vlib/v/checker/checker.v                      |  6 ++++--
 .../checker/tests/generic_type_inference.out  |  0
 .../v/checker/tests/generic_type_inference.vv | 20 +++++++++++++++++++
 5 files changed, 28 insertions(+), 4 deletions(-)
 create mode 100644 vlib/v/checker/tests/generic_type_inference.out
 create mode 100644 vlib/v/checker/tests/generic_type_inference.vv

diff --git a/vlib/rand/rand.v b/vlib/rand/rand.v
index 15ac15c013..183fdbeb47 100644
--- a/vlib/rand/rand.v
+++ b/vlib/rand/rand.v
@@ -327,7 +327,9 @@ pub fn (mut rng PRNG) choose<T>(array []T, k int) ?[]T {
 	}
 	mut results := []T{len: k}
 	mut indices := []int{len: n, init: it}
-	rng.shuffle(mut indices) ?
+	// TODO: see why exactly it is necessary to enfoce the type here in Checker.infer_fn_generic_types
+	// (v errors with: `inferred generic type T is ambiguous: got int, expected string`, when <int> is missing)
+	rng.shuffle<int>(mut indices) ?
 	for i in 0 .. k {
 		results[i] = array[indices[i]]
 	}
diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v
index 12435e8096..5e9da090e9 100644
--- a/vlib/v/checker/check_types.v
+++ b/vlib/v/checker/check_types.v
@@ -535,7 +535,7 @@ pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr
 		for i, param in func.params {
 			mut to_set := ast.void_type
 			// resolve generic struct receiver
-			if i == 0 && node.is_method && param.typ.has_flag(.generic) {
+			if node.is_method && param.typ.has_flag(.generic) {
 				sym := c.table.sym(node.receiver_type)
 				match sym.info {
 					ast.Struct, ast.Interface, ast.SumType {
diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v
index f7a3c6d734..2f82ed82a4 100644
--- a/vlib/v/checker/checker.v
+++ b/vlib/v/checker/checker.v
@@ -823,10 +823,12 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
 				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] {
+				if need_overload && !gen_sym.has_method_with_generic_parent('<')
+					&& 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 {
+				} else if need_overload && !gen_sym.has_method_with_generic_parent('<')
+					&& node.op == .gt {
 					c.error('cannot use `>` as `<=` operator method is not defined', left_right_pos)
 				}
 			} else if left_type in ast.integer_type_idxs && right_type in ast.integer_type_idxs {
diff --git a/vlib/v/checker/tests/generic_type_inference.out b/vlib/v/checker/tests/generic_type_inference.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/vlib/v/checker/tests/generic_type_inference.vv b/vlib/v/checker/tests/generic_type_inference.vv
new file mode 100644
index 0000000000..200df78e99
--- /dev/null
+++ b/vlib/v/checker/tests/generic_type_inference.vv
@@ -0,0 +1,20 @@
+import datatypes
+
+struct KeyVal<T> {
+	key string
+	val T
+}
+
+fn (a KeyVal<T>) == (b KeyVal<T>) bool {
+	return a.key == b.key
+}
+
+fn (a KeyVal<T>) < (b KeyVal<T>) bool {
+	return a.key < b.key
+}
+
+fn main() {
+	mut bst := datatypes.BSTree<KeyVal<int>>{}
+	bst.insert(KeyVal<int>{key: "alibaba", val: 12})
+	println(bst.in_order_traversal())
+}