From b9352ce834bfc8d6c59bced315228b1948a54b95 Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 30 Mar 2023 19:30:10 +0800 Subject: [PATCH] ast, parser, fmt: fix fmt error of generic fntype (#17814) --- vlib/v/ast/ast.v | 15 ++++++------ vlib/v/fmt/fmt.v | 13 ++++++++-- vlib/v/fmt/tests/generics_fntype_keep.vv | 24 +++++++++++++++++++ vlib/v/parser/parser.v | 1 + vlib/v/tests/call_on_anon_test.v | 16 ++++++------- vlib/v/tests/const_name_equals_fn_name_test.v | 4 ++-- .../fn_call_using_anon_fn_call_args_test.v | 8 +++---- vlib/v/tests/match_return_fn_test.v | 6 ++--- .../sumtype_with_alias_fntype_fn_call_test.v | 2 +- vlib/v/tests/sumtype_with_alias_fntype_test.v | 2 +- 10 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 vlib/v/fmt/tests/generics_fntype_keep.vv diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index b529956a75..601403ca62 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1225,13 +1225,14 @@ pub mut: pub struct FnTypeDecl { pub: - name string - is_pub bool - typ Type - pos token.Pos - type_pos token.Pos - comments []Comment - attrs []Attr // attributes of type declaration + name string + is_pub bool + typ Type + pos token.Pos + type_pos token.Pos + comments []Comment + generic_types []Type + attrs []Attr // attributes of type declaration } // TODO: handle this differently diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index c602b3795d..75975140ee 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -1396,7 +1396,12 @@ pub fn (mut f Fmt) fn_type_decl(node ast.FnTypeDecl) { fn_typ_info := typ_sym.info as ast.FnType fn_info := fn_typ_info.func fn_name := f.no_cur_mod(node.name) - f.write('type ${fn_name} = fn (') + mut generic_types_str := '' + if node.generic_types.len > 0 { + generic_names := node.generic_types.map(f.table.sym(it).name) + generic_types_str = '[${generic_names.join(', ')}]' + } + f.write('type ${fn_name}${generic_types_str} = fn (') for i, arg in fn_info.params { if arg.is_mut { f.write(arg.typ.share().str() + ' ') @@ -1775,7 +1780,11 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) { } } if node.mod == '' && node.name == '' { - f.write(node.left.str()) + if node.left is ast.CallExpr { + f.expr(node.left) + } else { + f.write(node.left.str()) + } } f.write_generic_call_if_require(node) f.write('(') diff --git a/vlib/v/fmt/tests/generics_fntype_keep.vv b/vlib/v/fmt/tests/generics_fntype_keep.vv new file mode 100644 index 0000000000..6c128dbabc --- /dev/null +++ b/vlib/v/fmt/tests/generics_fntype_keep.vv @@ -0,0 +1,24 @@ +type Fn[T] = fn (T) + +type FnReturn[T, R] = fn (T) R + +fn func_fn_concrete() Fn[string] { + return fn (_s string) {} +} + +fn func_fn_dynamic[T]() Fn[T] { + return fn [T](_t T) {} +} + +fn func_fn_return_dynamic[T, R]() FnReturn[T, R] { + return fn [T, R](t T) R { + return t.int() + } +} + +fn main() { + func_fn_concrete()('V') + func_fn_dynamic[string]()('V') + + assert func_fn_return_dynamic[string, int]()('100') == 100 +} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 9acf95cc94..03305ea6fb 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -4016,6 +4016,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl { pos: decl_pos type_pos: type_pos comments: comments + generic_types: generic_types attrs: attrs } } diff --git a/vlib/v/tests/call_on_anon_test.v b/vlib/v/tests/call_on_anon_test.v index 799056d807..b6b6539e81 100644 --- a/vlib/v/tests/call_on_anon_test.v +++ b/vlib/v/tests/call_on_anon_test.v @@ -29,16 +29,16 @@ fn f5(s string) fn (string) !string { } fn test_call_nested_anon() { - println(main.f1('V')('Lang')!) - s1 := main.f1('V')('Lang')! + println(f1('V')('Lang')!) + s1 := f1('V')('Lang')! println(s1) - s2 := main.f1('V')('Lang') or { 'ErrLang' } + s2 := f1('V')('Lang') or { 'ErrLang' } println(s2) - s3 := main.f2('V')('Lang')? + s3 := f2('V')('Lang')? println(s3) - s4 := main.f2('V')('Lang') or { 'NoneLang' } + s4 := f2('V')('Lang') or { 'NoneLang' } println(s4) - s := main.f3('V')('Lang') + s := f3('V')('Lang') println(s) assert s == 'VLang' assert s1 == 'VLang' @@ -46,10 +46,10 @@ fn test_call_nested_anon() { assert s3 == 'VLang' assert s4 == 'VLang' - s5 := main.f4('V')('Lang') or { 'Lang++' } + s5 := f4('V')('Lang') or { 'Lang++' } println(s5) assert s5 == 'Lang++' - s6 := main.f5('V')('Lang') or { '${err}' } + s6 := f5('V')('Lang') or { '${err}' } println(s6) assert s6 == 'test' } diff --git a/vlib/v/tests/const_name_equals_fn_name_test.v b/vlib/v/tests/const_name_equals_fn_name_test.v index 497b18aa20..a6fb22fa87 100644 --- a/vlib/v/tests/const_name_equals_fn_name_test.v +++ b/vlib/v/tests/const_name_equals_fn_name_test.v @@ -39,7 +39,7 @@ fn test_a_const_that_is_alias_to_fn_from_module() { const pg = fn_generator() -const pg2 = main.fn_generator()() +const pg2 = fn_generator()() fn fn_generator() fn () string { return fn () string { @@ -49,7 +49,7 @@ fn fn_generator() fn () string { } fn test_a_const_can_be_assigned_a_fn_produced_by_a_fn_generator_and_the_const_can_be_used() { - assert main.fn_generator()() == 'ok' + assert fn_generator()() == 'ok' x := fn_generator() assert x() == 'ok' diff --git a/vlib/v/tests/fn_call_using_anon_fn_call_args_test.v b/vlib/v/tests/fn_call_using_anon_fn_call_args_test.v index c140b2fe18..def9d4e898 100644 --- a/vlib/v/tests/fn_call_using_anon_fn_call_args_test.v +++ b/vlib/v/tests/fn_call_using_anon_fn_call_args_test.v @@ -11,9 +11,9 @@ fn foofun2(op string) fn () int { } fn test_fn_call_using_anon_fn_call_arg() { - println(main.foofun1('1')()) - assert main.foofun1('1')() == 'x passed' + println(foofun1('1')()) + assert foofun1('1')() == 'x passed' - println(main.foofun2('1')()) - assert main.foofun2('1')() == 22 + println(foofun2('1')()) + assert foofun2('1')() == 22 } diff --git a/vlib/v/tests/match_return_fn_test.v b/vlib/v/tests/match_return_fn_test.v index cba1a6e5ef..2ddf7253e8 100644 --- a/vlib/v/tests/match_return_fn_test.v +++ b/vlib/v/tests/match_return_fn_test.v @@ -77,13 +77,13 @@ fn err5(f fn ()) fn () { } fn test_main() { - var := main.err()() + var := err()() assert var == 'b' - var2 := main.err2()() + var2 := err2()() assert var2 == 'a' - var3 := main.err3()() + var3 := err3()() assert var3 == 'c' var4 := err4() diff --git a/vlib/v/tests/sumtype_with_alias_fntype_fn_call_test.v b/vlib/v/tests/sumtype_with_alias_fntype_fn_call_test.v index a95d8a01f4..3a28655b81 100644 --- a/vlib/v/tests/sumtype_with_alias_fntype_fn_call_test.v +++ b/vlib/v/tests/sumtype_with_alias_fntype_fn_call_test.v @@ -30,7 +30,7 @@ fn run(mmff Maybefnfact) string { } fn test_sumtype_with_alias_fntype_fn_call() { - r1 := main.myfnfact()(1) + r1 := myfnfact()(1) println(r1) assert r1 == 1 diff --git a/vlib/v/tests/sumtype_with_alias_fntype_test.v b/vlib/v/tests/sumtype_with_alias_fntype_test.v index 416b5112b8..9ad2bb27b0 100644 --- a/vlib/v/tests/sumtype_with_alias_fntype_test.v +++ b/vlib/v/tests/sumtype_with_alias_fntype_test.v @@ -23,7 +23,7 @@ fn test_sumtype_with_alias_fntype() { myfnfact := fn () Myfn { return abc } - r1 := main.myfnfact()(1) + r1 := myfnfact()(1) println(r1) assert r1 == 1