From 25c1b174ca6bdf7874ea82a6cd55e3d6abc080e2 Mon Sep 17 00:00:00 2001 From: yuyi Date: Mon, 2 May 2022 21:17:27 +0800 Subject: [PATCH] checker: fix generic fn infering fn type argument (fix #14243) (#14256) --- vlib/v/checker/check_types.v | 23 ++++++++++++-- .../generic_fn_infer_fn_type_argument_test.v | 31 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/generic_fn_infer_fn_type_argument_test.v diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 9d2bb65a50..de418af4dc 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -627,7 +627,9 @@ pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr param_elem_info = param_elem_sym.info as ast.Array param_elem_sym = c.table.sym(param_elem_info.elem_type) } else { - to_set = arg_elem_info.elem_type + if param_elem_sym.name == gt_name { + typ = arg_elem_info.elem_type + } break } } @@ -644,7 +646,9 @@ pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr param_elem_info = param_elem_sym.info as ast.ArrayFixed param_elem_sym = c.table.sym(param_elem_info.elem_type) } else { - to_set = arg_elem_info.elem_type + if param_elem_sym.name == gt_name { + typ = arg_elem_info.elem_type + } break } } @@ -659,6 +663,21 @@ pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr && c.table.sym(param_map_info.value_type).name == gt_name { typ = arg_map_info.value_type } + } else if arg_sym.kind == .function && param_type_sym.kind == .function { + arg_type_func := (arg_sym.info as ast.FnType).func + param_type_func := (param_type_sym.info as ast.FnType).func + if param_type_func.params.len == arg_type_func.params.len { + for n, fn_param in param_type_func.params { + if fn_param.typ.has_flag(.generic) + && c.table.sym(fn_param.typ).name == gt_name { + typ = arg_type_func.params[n].typ + } + } + if param_type_func.return_type.has_flag(.generic) + && c.table.sym(param_type_func.return_type).name == gt_name { + typ = arg_type_func.return_type + } + } } else if arg_sym.kind in [.struct_, .interface_, .sum_type] { mut generic_types := []ast.Type{} mut concrete_types := []ast.Type{} diff --git a/vlib/v/tests/generic_fn_infer_fn_type_argument_test.v b/vlib/v/tests/generic_fn_infer_fn_type_argument_test.v new file mode 100644 index 0000000000..2b121f7b71 --- /dev/null +++ b/vlib/v/tests/generic_fn_infer_fn_type_argument_test.v @@ -0,0 +1,31 @@ +fn test_generic_fn_infer_fn_type_argument() { + to_r := fn (x int) rune { + return [`😺`, `😸`, `😹`, `😻`, `😾`][x - 1] + } + to_f64 := fn (x int) f64 { + return f64(x) + 0.123 + } + to_s := fn (x int) string { + return ['One', 'Two', 'Three', 'Four', 'Five'][x - 1] + } + + items := [1, 2, 3, 4, 5] + + ret_r := fmap(to_r, items) + println('${ret_r.map(rune(it))}') + assert '${ret_r.map(rune(it))}' == '[`😺`, `😸`, `😹`, `😻`, `😾`]' + + // returns random same number for every item in array + ret_f64 := fmap(to_f64, items) + println(ret_f64) + assert ret_f64 == [1.123, 2.123, 3.123, 4.123, 5.123] + + ret_s := fmap(to_s, items) + println(ret_s) + assert ret_s == ['One', 'Two', 'Three', 'Four', 'Five'] +} + +// [noah04 #14214] code +fn fmap(func fn (I) O, list []I) []O { + return []O{len: list.len, init: func(list[it])} +}