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()) +}