diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 07edfec0f5..d7a482ee67 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -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 {} } } diff --git a/vlib/v/tests/concrete_type_as_generic_type_test.v b/vlib/v/tests/concrete_type_as_generic_type_test.v new file mode 100644 index 0000000000..d7f91a4959 --- /dev/null +++ b/vlib/v/tests/concrete_type_as_generic_type_test.v @@ -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