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

ast: fix concrete function type used as generic type (#17769)

This commit is contained in:
ChAoS_UnItY 2023-03-26 03:45:19 +08:00 committed by GitHub
parent 3d2d330478
commit f5f45d846e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 68 additions and 0 deletions

View File

@ -2246,6 +2246,38 @@ pub fn (mut t Table) generic_insts_to_concrete() {
util.verror('generic error', 'the number of generic types of sumtype `${parent.name}` is inconsistent with the concrete types')
}
}
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_names := []string{cap: function.params.len + 1}
generic_names << function.params.filter(it.typ.has_flag(.generic)).map(t.sym(it.typ).name)
if function.return_type.has_flag(.generic) {
generic_names << t.sym(function.return_type).name
}
for mut param in function.params {
if param.typ.has_flag(.generic) {
if t_typ := t.resolve_generic_to_concrete(param.typ, generic_names,
info.concrete_types)
{
param.typ = t_typ
}
}
}
mut return_type := function.return_type
if return_type.has_flag(.generic) {
if return_type.idx() != info.parent_idx {
return_type = t.unwrap_generic_type(return_type, generic_names,
info.concrete_types)
}
}
sym.info = FnType{
...parent_info
func: function
}
sym.is_pub = true
sym.kind = parent.kind
}
else {}
}
}

View File

@ -0,0 +1,36 @@
type Fn = fn (T)
type FnReturn = fn (T) R
fn func_fn_concrete() Fn[string] {
return fn (_s string) {}
}
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_dynamic[T, R]() FnReturn[T, R] {
return fn [T, R](t T) R {
return t.int()
}
}
// vfmt will erase explicit generic type (bug)
// vfmt off
fn test_concrete_function_type_as_generic_type() {
func_fn_concrete()('V')
func_fn_dynamic[string]()('V')
assert func_fn_return_dynamic[string, int]()('100') == 100
}
// vfmt on