From 34f5f05efa1d1fb16e4069b717559729b5d92298 Mon Sep 17 00:00:00 2001 From: ChAoS_UnItY Date: Sun, 26 Mar 2023 16:29:52 +0800 Subject: [PATCH] ast: fix concrete fn type that returns pair type as generic type (#17780) --- vlib/v/ast/table.v | 47 ++++++++++++++----- .../concrete_type_as_generic_type_test.v | 15 +++++- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index d7a482ee67..f82f623713 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -2105,7 +2105,7 @@ pub fn (mut t Table) generic_insts_to_concrete() { } mut fields := parent_info.fields.clone() if parent_info.generic_types.len == info.concrete_types.len { - generic_names := parent_info.generic_types.map(t.sym(it).name) + generic_names := t.get_generic_names(parent_info.generic_types) for i in 0 .. fields.len { if fields[i].typ.has_flag(.generic) { if fields[i].typ.idx() != info.parent_idx { @@ -2151,7 +2151,7 @@ pub fn (mut t Table) generic_insts_to_concrete() { } if parent_info.generic_types.len == info.concrete_types.len { mut fields := parent_info.fields.clone() - generic_names := parent_info.generic_types.map(t.sym(it).name) + generic_names := t.get_generic_names(parent_info.generic_types) for i in 0 .. fields.len { if t_typ := t.resolve_generic_to_concrete(fields[i].typ, generic_names, info.concrete_types) @@ -2209,7 +2209,7 @@ pub fn (mut t Table) generic_insts_to_concrete() { if parent_info.generic_types.len == info.concrete_types.len { mut fields := parent_info.fields.clone() mut variants := parent_info.variants.clone() - generic_names := parent_info.generic_types.map(t.sym(it).name) + generic_names := t.get_generic_names(parent_info.generic_types) for i in 0 .. fields.len { if t_typ := t.resolve_generic_to_concrete(fields[i].typ, generic_names, info.concrete_types) @@ -2250,11 +2250,12 @@ pub fn (mut t Table) generic_insts_to_concrete() { // 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) + 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_names << t.sym(function.return_type).name + 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, @@ -2264,11 +2265,11 @@ pub fn (mut t Table) generic_insts_to_concrete() { } } } - 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) + if function.return_type.has_flag(.generic) { + if t_typ := t.resolve_generic_to_concrete(function.return_type, + generic_names, info.concrete_types) + { + function.return_type = t_typ } } sym.info = FnType{ @@ -2284,6 +2285,30 @@ pub fn (mut t Table) generic_insts_to_concrete() { } } +// Extracts all type names from given types, notice that MultiReturn will be decompose +// and will not included in returned string +pub fn (t &Table) get_generic_names(generic_types []Type) []string { + mut generic_names := []string{cap: generic_types.len} + for typ in generic_types { + if !typ.has_flag(.generic) { + continue + } + + sym := t.sym(typ) + info := sym.info + + match info { + MultiReturn { + generic_names << t.get_generic_names(info.types) + } + else { + generic_names << sym.name + } + } + } + return generic_names +} + pub fn (t &Table) is_comptime_type(x Type, y ComptimeType) bool { x_kind := t.type_kind(x) match y.kind { diff --git a/vlib/v/tests/concrete_type_as_generic_type_test.v b/vlib/v/tests/concrete_type_as_generic_type_test.v index d7f91a4959..59dd7170b1 100644 --- a/vlib/v/tests/concrete_type_as_generic_type_test.v +++ b/vlib/v/tests/concrete_type_as_generic_type_test.v @@ -2,6 +2,8 @@ type Fn = fn (T) type FnReturn = fn (T) R +type FnMultiReturn = fn (I) (O, R) + fn func_fn_concrete() Fn[string] { return fn (_s string) {} } @@ -23,7 +25,13 @@ fn func_fn_return_dynamic[T, R]() FnReturn[T, R] { } } -// vfmt will erase explicit generic type (bug) +fn func_fn_multi_return_concrete() FnMultiReturn[string, string, string] { + return fn (s string) (string, string) { + return s[..1], s[1..] + } +} + +// vfmt will erase explicit generic type (bug reported in #17773) // vfmt off fn test_concrete_function_type_as_generic_type() { @@ -31,6 +39,11 @@ fn test_concrete_function_type_as_generic_type() { func_fn_dynamic[string]()('V') assert func_fn_return_dynamic[string, int]()('100') == 100 + + s1, s2 := func_fn_multi_return_concrete()('VLang') + + assert s1 == 'V' + assert s2 == 'Lang' } // vfmt on