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:
parent
1cde55478d
commit
ccbb8ab0ca
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
|
@ -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() {}
|
||||
| ~~~~~~
|
@ -1,5 +0,0 @@
|
||||
struct Foo[T] {
|
||||
bar T
|
||||
}
|
||||
|
||||
fn (a Foo[Foo[T]]) baz() {}
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user