Skip to content

Commit 604417e

Browse files
authored
ast: get correct generics for generics struct fn with generic param (fix #26191) (#26251)
1 parent 06e3485 commit 604417e

2 files changed

Lines changed: 89 additions & 1 deletion

File tree

‎vlib/v/ast/table.v‎

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,7 @@ pub fn (mut t Table) convert_generic_type(generic_type Type, generic_names []str
19591959
mut cnrt := '${sym.cname}_T_'
19601960
mut t_generic_names := generic_names.clone()
19611961
mut t_to_types := to_types.clone()
1962+
mut has_generic := false
19621963
if sym.generic_types.len > 0 && sym.generic_types.len == sym.info.generic_types.len
19631964
&& sym.generic_types != sym.info.generic_types {
19641965
t_generic_names = sym.info.generic_types.map(t.sym(it).name)
@@ -1995,6 +1996,9 @@ pub fn (mut t Table) convert_generic_type(generic_type Type, generic_names []str
19951996
rnrt += ', '
19961997
cnrt += '_'
19971998
}
1999+
if ct.has_flag(.generic) && ct != sym.info.generic_types[i] {
2000+
has_generic = true
2001+
}
19982002
} else {
19992003
return none
20002004
}
@@ -2008,7 +2012,64 @@ pub fn (mut t Table) convert_generic_type(generic_type Type, generic_names []str
20082012
idx = t.add_placeholder_type(nrt, cnrt, .v)
20092013
}
20102014
}
2011-
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2015+
return if has_generic {
2016+
new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2017+
} else {
2018+
new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2019+
}
2020+
}
2021+
}
2022+
UnknownTypeInfo {
2023+
if sym.name.contains('[') && sym.name.contains(']') {
2024+
base_name := sym.name.all_before('[')
2025+
generic_part := sym.name.all_after('[').trim_right(']')
2026+
mut converted_args := []string{}
2027+
mut has_generic := false
2028+
mut changed := false
2029+
args := generic_part.split(',').map(it.trim_space())
2030+
for arg in args {
2031+
if arg in generic_names {
2032+
idx := generic_names.index(arg)
2033+
if idx < to_types.len {
2034+
converted_type := to_types[idx]
2035+
converted_type_str := t.type_to_str(converted_type)
2036+
if converted_type_str != arg {
2037+
converted_args << converted_type_str
2038+
changed = true
2039+
if converted_type.has_flag(.generic) {
2040+
has_generic = true
2041+
}
2042+
} else {
2043+
converted_args << arg
2044+
}
2045+
} else {
2046+
converted_args << arg
2047+
}
2048+
} else {
2049+
converted_args << arg
2050+
}
2051+
}
2052+
if changed {
2053+
new_name := base_name + '[' + converted_args.join(', ') + ']'
2054+
mut new_idx := t.type_idxs[new_name]
2055+
if new_idx == 0 {
2056+
new_idx = t.add_placeholder_type(new_name, util.no_dots(new_name).replace_each([
2057+
'[',
2058+
'_T_',
2059+
']',
2060+
'',
2061+
', ',
2062+
'_',
2063+
' ',
2064+
'',
2065+
]), sym.language)
2066+
}
2067+
return if has_generic {
2068+
new_type(new_idx).derive_add_muls(generic_type).set_flag(.generic)
2069+
} else {
2070+
new_type(new_idx).derive_add_muls(generic_type).clear_flag(.generic)
2071+
}
2072+
}
20122073
}
20132074
}
20142075
else {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
struct Opt[T] {
2+
val T
3+
pub:
4+
some bool
5+
}
6+
7+
fn some[T](val T) Opt[T] {
8+
return Opt[T]{
9+
val: val
10+
some: true
11+
}
12+
}
13+
14+
fn (f Opt[T]) map[U](op fn (T) U) Opt[U] {
15+
if f.some {
16+
return some[U](op(f.val))
17+
}
18+
return Opt[U]{}
19+
}
20+
21+
fn test_main() {
22+
f := some('hello')
23+
result := f.map(fn (s string) int {
24+
return s.len
25+
})
26+
assert result.some && result.val == 5
27+
}

0 commit comments

Comments
 (0)