mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
This commit is contained in:
@ -1570,6 +1570,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||
}
|
||||
}
|
||||
func.name = ''
|
||||
func.generic_names = []
|
||||
idx := t.find_or_register_fn_type(func, true, false)
|
||||
if has_generic {
|
||||
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
|
||||
@ -2163,18 +2164,11 @@ pub fn (mut t Table) generic_insts_to_concrete() {
|
||||
}
|
||||
}
|
||||
FnType {
|
||||
// TODO: Cache function's generic types (parameters and return type) like Struct and Interface etc. do?
|
||||
mut parent_info := parent.info as FnType
|
||||
mut function := parent_info.func
|
||||
mut generic_types := []Type{cap: function.params.len + 1}
|
||||
generic_types << function.params.filter(it.typ.has_flag(.generic)).map(it.typ)
|
||||
if function.return_type.has_flag(.generic) {
|
||||
generic_types << function.return_type
|
||||
}
|
||||
generic_names := t.get_generic_names(generic_types)
|
||||
for mut param in function.params {
|
||||
if param.typ.has_flag(.generic) {
|
||||
if t_typ := t.resolve_generic_to_concrete(param.typ, generic_names,
|
||||
if t_typ := t.resolve_generic_to_concrete(param.typ, function.generic_names,
|
||||
info.concrete_types)
|
||||
{
|
||||
param.typ = t_typ
|
||||
@ -2183,11 +2177,12 @@ pub fn (mut t Table) generic_insts_to_concrete() {
|
||||
}
|
||||
if function.return_type.has_flag(.generic) {
|
||||
if t_typ := t.resolve_generic_to_concrete(function.return_type,
|
||||
generic_names, info.concrete_types)
|
||||
function.generic_names, info.concrete_types)
|
||||
{
|
||||
function.return_type = t_typ
|
||||
}
|
||||
}
|
||||
function.generic_names = []
|
||||
sym.info = FnType{
|
||||
...parent_info
|
||||
func: function
|
||||
|
@ -229,7 +229,7 @@ pub fn (mut p Parser) parse_multi_return_type() ast.Type {
|
||||
}
|
||||
|
||||
// given anon name based off signature when `name` is blank
|
||||
pub fn (mut p Parser) parse_fn_type(name string) ast.Type {
|
||||
pub fn (mut p Parser) parse_fn_type(name string, generic_types []ast.Type) ast.Type {
|
||||
p.check(.key_fn)
|
||||
|
||||
for attr in p.attrs {
|
||||
@ -273,6 +273,7 @@ pub fn (mut p Parser) parse_fn_type(name string) ast.Type {
|
||||
is_variadic: is_variadic
|
||||
return_type: return_type
|
||||
return_type_pos: return_type_pos
|
||||
generic_names: generic_types.map(p.table.sym(it).name)
|
||||
is_method: false
|
||||
attrs: p.attrs
|
||||
}
|
||||
@ -543,7 +544,7 @@ pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_d
|
||||
match p.tok.kind {
|
||||
.key_fn {
|
||||
// func
|
||||
return p.parse_fn_type('')
|
||||
return p.parse_fn_type('', []ast.Type{})
|
||||
}
|
||||
.lsbr, .nilsbr {
|
||||
// array
|
||||
|
@ -4013,7 +4013,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||
if p.tok.kind == .key_fn && p.is_fn_type_decl() {
|
||||
// function type: `type mycallback = fn(string, int)`
|
||||
fn_name := p.prepend_mod(name)
|
||||
fn_type := p.parse_fn_type(fn_name)
|
||||
fn_type := p.parse_fn_type(fn_name, generic_types)
|
||||
p.table.sym(fn_type).is_pub = is_pub
|
||||
type_pos = type_pos.extend(p.tok.pos())
|
||||
comments = p.eat_comments(same_line: true)
|
||||
|
@ -1,8 +1,8 @@
|
||||
type Fn = fn (T)
|
||||
type Fn[T] = fn (T)
|
||||
|
||||
type FnReturn = fn (T) R
|
||||
type FnReturn[T, R] = fn (T) R
|
||||
|
||||
type FnMultiReturn = fn (I) (O, R)
|
||||
type FnMultiReturn[I, O, R] = fn (I) (O, R)
|
||||
|
||||
fn func_fn_concrete() Fn[string] {
|
||||
return fn (_s string) {}
|
||||
@ -12,12 +12,11 @@ fn func_fn_dynamic[T]() Fn[T] {
|
||||
return fn [T](_t T) {}
|
||||
}
|
||||
|
||||
// FIXME: FnReturn[string, string] fails to stencil
|
||||
// fn func_fn_return_concrete() FnReturn[string, string] {
|
||||
// return fn (s string) string {
|
||||
// return s
|
||||
// }
|
||||
// }
|
||||
fn func_fn_return_concrete() FnReturn[string, string] {
|
||||
return fn (s string) string {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
fn func_fn_return_dynamic[T, R]() FnReturn[T, R] {
|
||||
return fn [T, R](t T) R {
|
||||
@ -35,6 +34,7 @@ fn test_concrete_function_type_as_generic_type() {
|
||||
func_fn_concrete()('V')
|
||||
func_fn_dynamic[string]()('V')
|
||||
|
||||
func_fn_return_concrete()('V')
|
||||
assert func_fn_return_dynamic[string, int]()('100') == 100
|
||||
|
||||
s1, s2 := func_fn_multi_return_concrete()('VLang')
|
33
vlib/v/tests/concrete_type_as_generic_fn_type_2_test.v
Normal file
33
vlib/v/tests/concrete_type_as_generic_fn_type_2_test.v
Normal file
@ -0,0 +1,33 @@
|
||||
struct ParseResult[T] {
|
||||
result T
|
||||
rest string
|
||||
}
|
||||
|
||||
type ParseFunction[T] = fn (string) !ParseResult[T]
|
||||
|
||||
fn literal(l string) ParseFunction[string] {
|
||||
return fn [l] (input string) !ParseResult[string] {
|
||||
if !input.starts_with(l) {
|
||||
return error(input)
|
||||
}
|
||||
|
||||
return ParseResult[string]{
|
||||
result: l
|
||||
rest: input.all_after_first(l)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_concrete_function_type_as_generic_type() {
|
||||
l_func := literal('start')
|
||||
val1 := l_func('start test') or { ParseResult[string]{} }
|
||||
val2 := l_func('test') or { ParseResult[string]{} }
|
||||
|
||||
println(val1)
|
||||
assert val1.result == 'start'
|
||||
assert val1.rest == ' test'
|
||||
|
||||
println(val2)
|
||||
assert val2.result == ''
|
||||
assert val2.rest == ''
|
||||
}
|
Reference in New Issue
Block a user