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

ast, parser: fix generic struct init with nested generic struct (#16736)

This commit is contained in:
yuyi 2022-12-22 00:32:54 +08:00 committed by GitHub
parent 1cde55478d
commit ccbb8ab0ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 106 additions and 24 deletions

View File

@ -1712,12 +1712,18 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
for t_typ in sym.generic_types {
if !t_typ.has_flag(.generic) {
t_concrete_types << t_typ
} else {
} else if t.sym(t_typ).kind == .any {
tname := t.sym(t_typ).name
index := generic_names.index(tname)
if index >= 0 && index < concrete_types.len {
t_concrete_types << concrete_types[index]
}
} else {
if tt := t.resolve_generic_to_concrete(t_typ, generic_names,
concrete_types)
{
t_concrete_types << tt
}
}
}
}
@ -1806,7 +1812,7 @@ pub fn (mut t Table) generic_type_names(generic_type Type) []string {
if sym.generic_types.len > 0 {
// Foo[U] (declaration: Foo[T])
for typ in sym.generic_types {
if typ.has_flag(.generic) {
if typ.has_flag(.generic) && t.sym(typ).kind == .any {
names << t.sym(typ).name
}
}
@ -1872,12 +1878,15 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
for t_typ in ts.generic_types {
if !t_typ.has_flag(.generic) {
t_concrete_types << t_typ
} else {
} else if t.sym(t_typ).kind == .any {
tname := t.sym(t_typ).name
index := generic_names.index(tname)
if index >= 0 && index < concrete_types.len {
t_concrete_types << concrete_types[index]
}
} else {
t_concrete_types << t.unwrap_generic_type(t_typ, generic_names,
concrete_types)
}
}
}

View File

@ -720,10 +720,10 @@ pub fn (mut p Parser) parse_generic_inst_type(name string) ast.Type {
if gts.kind == .multi_return {
p.error_with_pos('cannot use multi return as generic concrete type', type_pos)
}
if gt.has_flag(.generic) && gts.name.len > 1 {
p.error_with_pos('the parameter type name of a generic struct, must be a single capital letter placeholder name, like T or X, or a non-generic type name like int, string, etc.',
type_pos)
}
// if gt.has_flag(.generic) && gts.name.len > 1 {
// p.error_with_pos('the parameter type name of a generic struct, must be a single capital letter placeholder name, like T or X, or a non-generic type name like int, string, etc.',
// type_pos)
// }
bs_name += gts.name
bs_cname += gts.cname
concrete_types << gt

View File

@ -1,7 +1,7 @@
vlib/v/parser/tests/generic_struct_parameter_err.vv:10:17: error: the parameter type name of a generic struct, must be a single capital letter placeholder name, like T or X, or a non-generic type name like int, string, etc.
8 | struct MyContainer[T] {
9 | mut:
10 | lst LinkedList[MyNode[T]]
| ~~~~~~~~~
11 | }
12 |
vlib/v/parser/tests/generic_struct_parameter_err.vv:17:16: error: cannot use `MyNode[string]` as `string` in argument 1 to `datatypes.LinkedList[string].push`
15 | data: data
16 | }
17 | c.lst.push[T](node)
| ~~~~
18 | }
19 |

View File

@ -1,5 +0,0 @@
vlib/v/parser/tests/generic_struct_receiver_nested_generic_err.vv:5:11: error: the parameter type name of a generic struct, must be a single capital letter placeholder name, like T or X, or a non-generic type name like int, string, etc.
3 | }
4 |
5 | fn (a Foo[Foo[T]]) baz() {}
| ~~~~~~

View File

@ -1,5 +0,0 @@
struct Foo[T] {
bar T
}
fn (a Foo[Foo[T]]) baz() {}

View File

@ -0,0 +1,83 @@
struct Tuple2[A, B] {
a A
b B
}
// map to array of Tuple2[int, Tuple2[key, value]] tuples
fn map_to_array_int_kv[K, V](m map[K]V) []Tuple2[int, Tuple2[K, V]] {
mut r := []Tuple2[int, Tuple2[K, V]]{cap: m.len}
mut i := 0
for k, v in m {
r << Tuple2[int, Tuple2[K, V]]{i, Tuple2[K, V]{k, v}}
i += 1
}
return r
}
// map to array of Tuple2[int, Tuple2[Tuple2[key, value], Tuple2[value, key]]] tuples
fn map_to_array_int_kv_vk[K, V](m map[K]V) []Tuple2[int, Tuple2[Tuple2[K, V], Tuple2[V, K]]] {
mut r := []Tuple2[int, Tuple2[Tuple2[K, V], Tuple2[V, K]]]{cap: m.len}
mut i := 0
for k, v in m {
r << Tuple2[int, Tuple2[Tuple2[K, V], Tuple2[V, K]]]{i, Tuple2[Tuple2[K, V], Tuple2[V, K]]{Tuple2[K, V]{k, v}, Tuple2[V, K]{v, k}}}
i += 1
}
return r
}
fn test_generics_struct_init_with_inconsistent_generic_types() {
x := {
'one': 1
'two': 2
}
y := {
3: 'three'
4: 'four'
}
println(x)
rx1 := map_to_array_int_kv(x)
println(rx1)
assert rx1[0].a == 0
assert rx1[0].b.a == 'one'
assert rx1[0].b.b == 1
assert rx1[1].a == 1
assert rx1[1].b.a == 'two'
assert rx1[1].b.b == 2
rx2 := map_to_array_int_kv_vk(x)
println(rx2)
assert rx2[0].a == 0
assert rx2[0].b.a.a == 'one'
assert rx2[0].b.a.b == 1
assert rx2[0].b.b.a == 1
assert rx2[0].b.b.b == 'one'
assert rx2[1].a == 1
assert rx2[1].b.a.a == 'two'
assert rx2[1].b.a.b == 2
assert rx2[1].b.b.a == 2
assert rx2[1].b.b.b == 'two'
println(y)
ry1 := map_to_array_int_kv(y)
println(ry1)
assert ry1[0].a == 0
assert ry1[0].b.a == 3
assert ry1[0].b.b == 'three'
assert ry1[1].a == 1
assert ry1[1].b.a == 4
assert ry1[1].b.b == 'four'
ry2 := map_to_array_int_kv_vk(y)
println(ry2)
assert ry2[0].a == 0
assert ry2[0].b.a.a == 3
assert ry2[0].b.a.b == 'three'
assert ry2[0].b.b.a == 'three'
assert ry2[0].b.b.b == 3
assert ry2[1].a == 1
assert ry2[1].b.a.a == 4
assert ry2[1].b.a.b == 'four'
assert ry2[1].b.b.a == 'four'
assert ry2[1].b.b.b == 4
}