From ea0ac092976b8d654460f18fc286226a6d20a665 Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 29 Apr 2021 22:37:54 +0800 Subject: [PATCH] checker: fix generics with nested external generics fn (#9933) --- vlib/v/checker/checker.v | 46 +++++++++---------- ...cs_with_nested_external_generics_fn_test.v | 21 +++++++++ 2 files changed, 44 insertions(+), 23 deletions(-) create mode 100644 vlib/v/tests/generics_with_nested_external_generics_fn_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 4e3661bf48..67cd5d6740 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -197,11 +197,14 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) { // post process generic functions. must be done after all files have been // checked, to eunsure all generic calls are processed as this information // is needed when the generic type is auto inferred from the call argument - for i in 0 .. ast_files.len { - file := unsafe { &ast_files[i] } - if file.generic_fns.len > 0 { - c.change_current_file(file) - c.post_process_generic_fns() + // Check 2 times (in order to check nested generics fn) + for _ in 0 .. 2 { + for i in 0 .. ast_files.len { + file := unsafe { &ast_files[i] } + if file.generic_fns.len > 0 { + c.change_current_file(file) + c.post_process_generic_fns() + } } } // restore the original c.file && c.mod after post processing @@ -1990,7 +1993,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type { } } if has_generic { - if c.mod != '' && !fn_name.starts_with('${c.mod}.') { + if c.mod != '' && !fn_name.contains('.') { // Need to prepend the module when adding a generic type to a function c.table.register_fn_concrete_types(c.mod + '.' + fn_name, concrete_types) } else { @@ -6573,24 +6576,21 @@ fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Positi fn (mut c Checker) post_process_generic_fns() { // Loop thru each generic function concrete type. // Check each specific fn instantiation. - // Check 2 times (in order to check nested generics fn) - for _ in 0 .. 2 { - for i in 0 .. c.file.generic_fns.len { - if c.table.fn_generic_types.len == 0 { - // no concrete types, so just skip: - continue - } - mut node := c.file.generic_fns[i] - c.mod = node.mod - for generic_types in c.table.fn_generic_types[node.name] { - node.cur_generic_types = generic_types - c.fn_decl(mut node) - if node.name in ['vweb.run_app', 'vweb.run'] { - c.vweb_gen_types << generic_types - } - } - node.cur_generic_types = [] + for i in 0 .. c.file.generic_fns.len { + if c.table.fn_generic_types.len == 0 { + // no concrete types, so just skip: + continue } + mut node := c.file.generic_fns[i] + c.mod = node.mod + for generic_types in c.table.fn_generic_types[node.name] { + node.cur_generic_types = generic_types + c.fn_decl(mut node) + if node.name in ['vweb.run_app', 'vweb.run'] { + c.vweb_gen_types << generic_types + } + } + node.cur_generic_types = [] } } diff --git a/vlib/v/tests/generics_with_nested_external_generics_fn_test.v b/vlib/v/tests/generics_with_nested_external_generics_fn_test.v new file mode 100644 index 0000000000..410e863e60 --- /dev/null +++ b/vlib/v/tests/generics_with_nested_external_generics_fn_test.v @@ -0,0 +1,21 @@ +import rand.util +import rand + +pub fn sample(arr []T, k int) []T { + mut result := arr.clone() + + rand.seed([u32(1), 2]) // set seed to produce same results in order + util.shuffle(mut result, k) + + return result[0..k] +} + +fn test_generics_with_nested_external_generics_fn() { + mut arr := [11, 32, 24, 45, 57, 32, 37, 52, 37, 24] + println(arr) + + ret := sample(arr, 5) + println(ret) + + assert ret == [32, 45, 57, 11, 37] +}