Skip to content

Commit 34f5f05

Browse files
authored
ast: fix concrete fn type that returns pair type as generic type (#17780)
1 parent 8759409 commit 34f5f05

2 files changed

Lines changed: 50 additions & 12 deletions

File tree

vlib/v/ast/table.v

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,7 +2105,7 @@ pub fn (mut t Table) generic_insts_to_concrete() {
21052105
}
21062106
mut fields := parent_info.fields.clone()
21072107
if parent_info.generic_types.len == info.concrete_types.len {
2108-
generic_names := parent_info.generic_types.map(t.sym(it).name)
2108+
generic_names := t.get_generic_names(parent_info.generic_types)
21092109
for i in 0 .. fields.len {
21102110
if fields[i].typ.has_flag(.generic) {
21112111
if fields[i].typ.idx() != info.parent_idx {
@@ -2151,7 +2151,7 @@ pub fn (mut t Table) generic_insts_to_concrete() {
21512151
}
21522152
if parent_info.generic_types.len == info.concrete_types.len {
21532153
mut fields := parent_info.fields.clone()
2154-
generic_names := parent_info.generic_types.map(t.sym(it).name)
2154+
generic_names := t.get_generic_names(parent_info.generic_types)
21552155
for i in 0 .. fields.len {
21562156
if t_typ := t.resolve_generic_to_concrete(fields[i].typ, generic_names,
21572157
info.concrete_types)
@@ -2209,7 +2209,7 @@ pub fn (mut t Table) generic_insts_to_concrete() {
22092209
if parent_info.generic_types.len == info.concrete_types.len {
22102210
mut fields := parent_info.fields.clone()
22112211
mut variants := parent_info.variants.clone()
2212-
generic_names := parent_info.generic_types.map(t.sym(it).name)
2212+
generic_names := t.get_generic_names(parent_info.generic_types)
22132213
for i in 0 .. fields.len {
22142214
if t_typ := t.resolve_generic_to_concrete(fields[i].typ, generic_names,
22152215
info.concrete_types)
@@ -2250,11 +2250,12 @@ pub fn (mut t Table) generic_insts_to_concrete() {
22502250
// TODO: Cache function's generic types (parameters and return type) like Struct and Interface etc. do?
22512251
mut parent_info := parent.info as FnType
22522252
mut function := parent_info.func
2253-
mut generic_names := []string{cap: function.params.len + 1}
2254-
generic_names << function.params.filter(it.typ.has_flag(.generic)).map(t.sym(it.typ).name)
2253+
mut generic_types := []Type{cap: function.params.len + 1}
2254+
generic_types << function.params.filter(it.typ.has_flag(.generic)).map(it.typ)
22552255
if function.return_type.has_flag(.generic) {
2256-
generic_names << t.sym(function.return_type).name
2256+
generic_types << function.return_type
22572257
}
2258+
generic_names := t.get_generic_names(generic_types)
22582259
for mut param in function.params {
22592260
if param.typ.has_flag(.generic) {
22602261
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() {
22642265
}
22652266
}
22662267
}
2267-
mut return_type := function.return_type
2268-
if return_type.has_flag(.generic) {
2269-
if return_type.idx() != info.parent_idx {
2270-
return_type = t.unwrap_generic_type(return_type, generic_names,
2271-
info.concrete_types)
2268+
if function.return_type.has_flag(.generic) {
2269+
if t_typ := t.resolve_generic_to_concrete(function.return_type,
2270+
generic_names, info.concrete_types)
2271+
{
2272+
function.return_type = t_typ
22722273
}
22732274
}
22742275
sym.info = FnType{
@@ -2284,6 +2285,30 @@ pub fn (mut t Table) generic_insts_to_concrete() {
22842285
}
22852286
}
22862287

2288+
// Extracts all type names from given types, notice that MultiReturn will be decompose
2289+
// and will not included in returned string
2290+
pub fn (t &Table) get_generic_names(generic_types []Type) []string {
2291+
mut generic_names := []string{cap: generic_types.len}
2292+
for typ in generic_types {
2293+
if !typ.has_flag(.generic) {
2294+
continue
2295+
}
2296+
2297+
sym := t.sym(typ)
2298+
info := sym.info
2299+
2300+
match info {
2301+
MultiReturn {
2302+
generic_names << t.get_generic_names(info.types)
2303+
}
2304+
else {
2305+
generic_names << sym.name
2306+
}
2307+
}
2308+
}
2309+
return generic_names
2310+
}
2311+
22872312
pub fn (t &Table) is_comptime_type(x Type, y ComptimeType) bool {
22882313
x_kind := t.type_kind(x)
22892314
match y.kind {

vlib/v/tests/concrete_type_as_generic_type_test.v

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ type Fn = fn (T)
22

33
type FnReturn = fn (T) R
44

5+
type FnMultiReturn = fn (I) (O, R)
6+
57
fn func_fn_concrete() Fn[string] {
68
return fn (_s string) {}
79
}
@@ -23,14 +25,25 @@ fn func_fn_return_dynamic[T, R]() FnReturn[T, R] {
2325
}
2426
}
2527

26-
// vfmt will erase explicit generic type (bug)
28+
fn func_fn_multi_return_concrete() FnMultiReturn[string, string, string] {
29+
return fn (s string) (string, string) {
30+
return s[..1], s[1..]
31+
}
32+
}
33+
34+
// vfmt will erase explicit generic type (bug reported in #17773)
2735
// vfmt off
2836

2937
fn test_concrete_function_type_as_generic_type() {
3038
func_fn_concrete()('V')
3139
func_fn_dynamic[string]()('V')
3240

3341
assert func_fn_return_dynamic[string, int]()('100') == 100
42+
43+
s1, s2 := func_fn_multi_return_concrete()('VLang')
44+
45+
assert s1 == 'V'
46+
assert s2 == 'Lang'
3447
}
3548

3649
// vfmt on

0 commit comments

Comments
 (0)