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

@ -935,14 +935,15 @@ pub:
mut_pos token.Pos
comptime bool
pub mut:
scope &Scope = unsafe { nil }
obj ScopeObject
mod string
name string
kind IdentKind
info IdentInfo
is_mut bool // if mut *token* is before name. Use `is_mut()` to lookup mut variable
or_expr OrExpr
scope &Scope = unsafe { nil }
obj ScopeObject
mod string
name string
kind IdentKind
info IdentInfo
is_mut bool // if mut *token* is before name. Use `is_mut()` to lookup mut variable
or_expr OrExpr
concrete_types []Type
}
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 {
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

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)`
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.kind = .function
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)
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 {
f.write('?')
} 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') {
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 {
// p.warn('name ')
is_option := p.tok.kind == .question && p.peek_tok.kind == .lsbr
if is_option {
p.next()
@ -2169,9 +2168,13 @@ pub fn (mut p Parser) parse_ident(language ast.Language) ast.Ident {
scope: p.scope
}
}
if p.inside_match_body && name == 'it' {
// p.warn('it')
mut is_known_generic_fn := false
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 {
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 {
or_kind = ast.OrKind.block
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{
tok_kind: p.tok.kind
@ -2212,6 +2218,7 @@ pub fn (mut p Parser) parse_ident(language ast.Language) ast.Ident {
stmts: or_stmts
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
}