From d236d6a47350eb602e6360adeb01aa4c4e013fb3 Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 30 Apr 2021 18:40:36 +0800 Subject: [PATCH] parser, cgen: fix generics fn typeof name (fix #7357) (#9939) --- vlib/v/gen/c/auto_str_methods.v | 7 +++++-- vlib/v/gen/c/cgen.v | 16 +++++++++++----- vlib/v/parser/fn.v | 2 ++ vlib/v/parser/parse_type.v | 13 +++++++++++++ vlib/v/tests/generic_fn_typeof_name_test.v | 15 +++++++++++++++ 5 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 vlib/v/tests/generic_fn_typeof_name_test.v diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 3e8f71c3ec..c3d76fd5dd 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -724,14 +724,17 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_ fn (mut g Gen) fn_decl_str(info ast.FnType) string { mut fn_str := 'fn (' for i, arg in info.func.params { + if arg.is_mut { + fn_str += 'mut ' + } if i > 0 { fn_str += ', ' } - fn_str += util.strip_main_name(g.table.get_type_name(arg.typ)) + fn_str += util.strip_main_name(g.table.get_type_name(g.unwrap_generic(arg.typ))) } fn_str += ')' if info.func.return_type != ast.void_type { - fn_str += ' ${util.strip_main_name(g.table.get_type_name(info.func.return_type))}' + fn_str += ' ${util.strip_main_name(g.table.get_type_name(g.unwrap_generic(info.func.return_type)))}' } return fn_str } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index d6a10155ea..fcb9374f65 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3229,12 +3229,18 @@ fn (mut g Gen) expr(node ast.Expr) { } // T.name, typeof(expr).name -fn (mut g Gen) type_name(type_ ast.Type) { - mut typ := type_ - if typ.has_flag(.generic) { - typ = g.cur_concrete_types[0] +fn (mut g Gen) type_name(typ ast.Type) { + sym := g.table.get_type_symbol(typ) + mut s := '' + if sym.kind == .function { + if typ.is_ptr() { + s = '&' + g.fn_decl_str(sym.info as ast.FnType) + } else { + s = g.fn_decl_str(sym.info as ast.FnType) + } + } else { + s = g.table.type_to_str(g.unwrap_generic(typ)) } - s := g.table.type_to_str(typ) g.write('_SLIT("${util.strip_main_name(s)}")') } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 21ab9cdd2d..77c318a771 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -703,6 +703,8 @@ fn (mut p Parser) fn_args() ([]ast.Param, bool, bool) { types_only := p.tok.kind in [.amp, .ellipsis, .key_fn, .lsbr] || (p.peek_tok.kind == .comma && p.table.known_type(argname)) || p.peek_tok.kind == .dot || p.peek_tok.kind == .rpar + || (p.tok.kind == .key_mut && (p.peek_token(2).kind == .comma + || p.peek_token(2).kind == .rpar)) // TODO copy pasta, merge 2 branches if types_only { mut arg_no := 1 diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 42fe40889d..30c70003fe 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -193,11 +193,21 @@ pub fn (mut p Parser) parse_multi_return_type() ast.Type { pub fn (mut p Parser) parse_fn_type(name string) ast.Type { // p.warn('parse fn') p.check(.key_fn) + mut has_generic := false line_nr := p.tok.line_nr args, _, is_variadic := p.fn_args() + for arg in args { + if arg.typ.has_flag(.generic) { + has_generic = true + break + } + } mut return_type := ast.void_type if p.tok.line_nr == line_nr && p.tok.kind.is_start_of_type() { return_type = p.parse_type() + if return_type.has_flag(.generic) { + has_generic = true + } } func := ast.Fn{ name: name @@ -209,6 +219,9 @@ pub fn (mut p Parser) parse_fn_type(name string) ast.Type { // because typedefs get generated after the map struct is generated has_decl := p.builtin_mod && name.starts_with('Map') && name.ends_with('Fn') idx := p.table.find_or_register_fn_type(p.mod, func, false, has_decl) + if has_generic { + return ast.new_type(idx).set_flag(.generic) + } return ast.new_type(idx) } diff --git a/vlib/v/tests/generic_fn_typeof_name_test.v b/vlib/v/tests/generic_fn_typeof_name_test.v new file mode 100644 index 0000000000..413553bb25 --- /dev/null +++ b/vlib/v/tests/generic_fn_typeof_name_test.v @@ -0,0 +1,15 @@ +struct Client {} + +fn add_handler(handler fn (mut Client, T)) string { + return typeof(handler).name +} + +fn on_message(mut client Client, event string) { + println(event) +} + +fn test_generics_fn_typeof_name() { + ret := add_handler(on_message) + println(ret) + assert ret == 'fn (mut Client, string)' +}