parser, cgen: fix generics fn typeof name (fix #7357) (#9939)

pull/9948/head
yuyi 2021-04-30 18:40:36 +08:00 committed by GitHub
parent 844662e0d6
commit d236d6a473
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 7 deletions

View File

@ -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
}

View File

@ -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)}")')
}

View File

@ -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

View File

@ -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)
}

View File

@ -0,0 +1,15 @@
struct Client {}
fn add_handler<T>(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<string>(on_message)
println(ret)
assert ret == 'fn (mut Client, string)'
}