1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

ast, parser, checker, cgen, fmt: implement generic fn params (fix #14937) (#18126)

This commit is contained in:
yuyi 2023-05-08 01:53:56 +08:00 committed by GitHub
parent 39ec1134fa
commit a0a8b7e47a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 63 additions and 13 deletions

View File

@ -943,6 +943,7 @@ pub mut:
info IdentInfo info IdentInfo
is_mut bool // if mut *token* is before name. Use `is_mut()` to lookup mut variable is_mut bool // if mut *token* is before name. Use `is_mut()` to lookup mut variable
or_expr OrExpr or_expr OrExpr
concrete_types []Type
} }
pub fn (i &Ident) is_mut() bool { pub fn (i &Ident) is_mut() bool {

View File

@ -744,7 +744,7 @@ pub fn (mut t Table) register_anon_struct(name string, sym_idx int) {
} }
pub fn (t &Table) known_type(name string) bool { pub fn (t &Table) known_type(name string) bool {
return t.find_type_idx(name) != 0 || t.parsing_type == name return t.find_type_idx(name) != 0 || t.parsing_type == name || name in ['i32', 'byte']
} }
// start_parsing_type open the scope during the parsing of a type // start_parsing_type open the scope during the parsing of a type

View File

@ -3387,7 +3387,16 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
} }
// Non-anon-function object (not a call), e.g. `onclick(my_click)` // Non-anon-function object (not a call), e.g. `onclick(my_click)`
if func := c.table.find_fn(name) { if func := c.table.find_fn(name) {
fn_type := ast.new_type(c.table.find_or_register_fn_type(func, false, true)) mut fn_type := ast.new_type(c.table.find_or_register_fn_type(func, false,
true))
if func.generic_names.len > 0 {
if typ_ := c.table.resolve_generic_to_concrete(fn_type, func.generic_names,
node.concrete_types)
{
fn_type = typ_
c.table.register_fn_concrete_types(func.fkey(), node.concrete_types)
}
}
node.name = name node.name = name
node.kind = .function node.kind = .function
node.info = ast.IdentFn{ node.info = ast.IdentFn{

View File

@ -2018,6 +2018,17 @@ pub fn (mut f Fmt) ident(node ast.Ident) {
} }
name := f.short_module(node.name) name := f.short_module(node.name)
f.write(name) f.write(name)
if node.concrete_types.len > 0 {
f.write('[')
for i, concrete_type in node.concrete_types {
typ_name := f.table.type_to_str_using_aliases(concrete_type, f.mod2alias)
f.write(typ_name)
if i != node.concrete_types.len - 1 {
f.write(', ')
}
}
f.write(']')
}
if node.or_expr.kind == .propagate_option { if node.or_expr.kind == .propagate_option {
f.write('?') f.write('?')
} else if node.or_expr.kind == .block { } else if node.or_expr.kind == .block {

View File

@ -4215,6 +4215,8 @@ fn (mut g Gen) ident(node ast.Ident) {
if cattr := func.attrs.find_first('c') { if cattr := func.attrs.find_first('c') {
name = cattr.arg name = cattr.arg
} }
} else if node.concrete_types.len > 0 {
name = g.generic_fn_name(node.concrete_types, name)
} }
} }

View File

@ -2116,7 +2116,6 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
} }
pub fn (mut p Parser) parse_ident(language ast.Language) ast.Ident { pub fn (mut p Parser) parse_ident(language ast.Language) ast.Ident {
// p.warn('name ')
is_option := p.tok.kind == .question && p.peek_tok.kind == .lsbr is_option := p.tok.kind == .question && p.peek_tok.kind == .lsbr
if is_option { if is_option {
p.next() p.next()
@ -2169,9 +2168,13 @@ pub fn (mut p Parser) parse_ident(language ast.Language) ast.Ident {
scope: p.scope scope: p.scope
} }
} }
if p.inside_match_body && name == 'it' { mut is_known_generic_fn := false
// p.warn('it') if func := p.table.find_fn(p.prepend_mod(name)) {
if func.generic_names.len > 0 {
is_known_generic_fn = true
} }
}
mut concrete_types := []ast.Type{}
if p.expr_mod.len > 0 { if p.expr_mod.len > 0 {
name = '${p.expr_mod}.${name}' name = '${p.expr_mod}.${name}'
} }
@ -2188,6 +2191,9 @@ pub fn (mut p Parser) parse_ident(language ast.Language) ast.Ident {
} else if allowed_cases && p.tok.kind == .key_orelse { } else if allowed_cases && p.tok.kind == .key_orelse {
or_kind = ast.OrKind.block or_kind = ast.OrKind.block
or_stmts, or_pos = p.or_block(.no_err_var) or_stmts, or_pos = p.or_block(.no_err_var)
} else if is_known_generic_fn && p.tok.kind == .lsbr {
// `generic_fn[int]`
concrete_types = p.parse_concrete_types()
} }
return ast.Ident{ return ast.Ident{
tok_kind: p.tok.kind tok_kind: p.tok.kind
@ -2212,6 +2218,7 @@ pub fn (mut p Parser) parse_ident(language ast.Language) ast.Ident {
stmts: or_stmts stmts: or_stmts
pos: or_pos pos: or_pos
} }
concrete_types: concrete_types
} }
} }

View File

@ -0,0 +1,20 @@
type Fn[T] = fn (x T, i int) T
fn func[T](x T, i int, f_ Fn[T]) T {
return f_(x, i)
}
fn f[T](x T, i int) T {
return x
}
fn test_generic_fn_variable() {
ff := f[int]
ret := ff(1, 11)
println(ret)
assert ret == 1
x := func[f64](2.0, 3, f[f64])
println(x)
assert x == 2.0
}