mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
This commit is contained in:
parent
04936b00c5
commit
aad95ac818
@ -1710,10 +1710,14 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||
t_generic_names = sym.info.generic_types.map(t.sym(it).name)
|
||||
t_concrete_types = []
|
||||
for t_typ in sym.generic_types {
|
||||
tname := t.sym(t_typ).name
|
||||
index := generic_names.index(tname)
|
||||
if index >= 0 && index < concrete_types.len {
|
||||
t_concrete_types << concrete_types[index]
|
||||
if !t_typ.has_flag(.generic) {
|
||||
t_concrete_types << t_typ
|
||||
} else {
|
||||
tname := t.sym(t_typ).name
|
||||
index := generic_names.index(tname)
|
||||
if index >= 0 && index < concrete_types.len {
|
||||
t_concrete_types << concrete_types[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1801,7 +1805,7 @@ pub fn (mut t Table) generic_type_names(generic_type Type) []string {
|
||||
if sym.info.is_generic {
|
||||
if sym.generic_types.len > 0 {
|
||||
// Foo[U] (declaration: Foo[T])
|
||||
names << sym.generic_types.map(t.sym(it).name)
|
||||
names << sym.generic_types.filter(it.has_flag(.generic)).map(t.sym(it).name)
|
||||
} else {
|
||||
names << sym.info.generic_types.map(t.sym(it).name)
|
||||
}
|
||||
@ -1862,10 +1866,14 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
|
||||
t_generic_names = ts.info.generic_types.map(t.sym(it).name)
|
||||
t_concrete_types = []
|
||||
for t_typ in ts.generic_types {
|
||||
tname := t.sym(t_typ).name
|
||||
index := generic_names.index(tname)
|
||||
if index >= 0 && index < concrete_types.len {
|
||||
t_concrete_types << concrete_types[index]
|
||||
if !t_typ.has_flag(.generic) {
|
||||
t_concrete_types << t_typ
|
||||
} else {
|
||||
tname := t.sym(t_typ).name
|
||||
index := generic_names.index(tname)
|
||||
if index >= 0 && index < concrete_types.len {
|
||||
t_concrete_types << concrete_types[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -277,6 +277,9 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
||||
node.pos)
|
||||
} else if node.generic_types.len > 0 && c.table.cur_fn != unsafe { nil } {
|
||||
for gtyp in node.generic_types {
|
||||
if !gtyp.has_flag(.generic) {
|
||||
continue
|
||||
}
|
||||
gtyp_name := c.table.sym(gtyp).name
|
||||
if gtyp_name !in c.table.cur_fn.generic_names {
|
||||
cur_generic_names := '(' + c.table.cur_fn.generic_names.join(',') + ')'
|
||||
|
@ -109,6 +109,10 @@ fn (mut g Gen) final_gen_str(typ StrType) {
|
||||
}
|
||||
styp := typ.styp
|
||||
str_fn_name := styp_to_str_fn_name(styp)
|
||||
if str_fn_name in g.str_fn_names {
|
||||
return
|
||||
}
|
||||
g.str_fn_names << str_fn_name
|
||||
if typ.typ.has_flag(.optional) {
|
||||
g.gen_str_for_option(typ.typ, styp, str_fn_name)
|
||||
return
|
||||
|
@ -157,6 +157,7 @@ mut:
|
||||
defer_vars []string
|
||||
str_types []StrType // types that need automatic str() generation
|
||||
generated_str_fns []StrType // types that already have a str() function
|
||||
str_fn_names []string // remove duplicate function names
|
||||
threaded_fns shared []string // for generating unique wrapper types and fns for `go xxx()`
|
||||
waiter_fns shared []string // functions that wait for `go xxx()` to finish
|
||||
needed_equality_fns []ast.Type
|
||||
@ -5363,6 +5364,7 @@ fn (mut g Gen) write_sorted_types() {
|
||||
}
|
||||
|
||||
fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
|
||||
mut struct_names := []string{cap: 16}
|
||||
for sym in symbols {
|
||||
if sym.name.starts_with('C.') {
|
||||
continue
|
||||
@ -5377,7 +5379,10 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
|
||||
mut name := sym.cname
|
||||
match sym.info {
|
||||
ast.Struct {
|
||||
g.struct_decl(sym.info, name, false)
|
||||
if name !in struct_names {
|
||||
g.struct_decl(sym.info, name, false)
|
||||
struct_names << name
|
||||
}
|
||||
}
|
||||
ast.Alias {
|
||||
// ast.Alias { TODO
|
||||
@ -5401,9 +5406,10 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
|
||||
}
|
||||
}
|
||||
ast.SumType {
|
||||
if sym.info.is_generic {
|
||||
if sym.info.is_generic || name in struct_names {
|
||||
continue
|
||||
}
|
||||
struct_names << name
|
||||
g.typedefs.writeln('typedef struct ${name} ${name};')
|
||||
g.type_definitions.writeln('')
|
||||
g.type_definitions.writeln('// Union sum type ${name} = ')
|
||||
|
@ -708,19 +708,19 @@ pub fn (mut p Parser) parse_generic_inst_type(name string) ast.Type {
|
||||
bs_name += '['
|
||||
bs_cname += '_T_'
|
||||
mut concrete_types := []ast.Type{}
|
||||
mut is_instance := false
|
||||
mut is_instance := true
|
||||
for p.tok.kind != .eof {
|
||||
mut type_pos := p.tok.pos()
|
||||
gt := p.parse_type()
|
||||
type_pos = type_pos.extend(p.prev_tok.pos())
|
||||
if !gt.has_flag(.generic) {
|
||||
is_instance = true
|
||||
if gt.has_flag(.generic) {
|
||||
is_instance = false
|
||||
}
|
||||
gts := p.table.sym(gt)
|
||||
if gts.kind == .multi_return {
|
||||
p.error_with_pos('cannot use multi return as generic concrete type', type_pos)
|
||||
}
|
||||
if !is_instance && gts.name.len > 1 {
|
||||
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)
|
||||
}
|
||||
|
@ -0,0 +1,165 @@
|
||||
struct Tuple1[A] {
|
||||
a A
|
||||
}
|
||||
|
||||
struct Tuple2[A, B] {
|
||||
a A
|
||||
b B
|
||||
}
|
||||
|
||||
struct Tuple3[A, B, X] { // note: "C" is reserved for C language...
|
||||
a A
|
||||
b B
|
||||
c X
|
||||
}
|
||||
|
||||
// map to array of key tuples
|
||||
fn map_to_array1_k[K, V](m map[K]V) []Tuple1[K] {
|
||||
mut r := []Tuple1[K]{cap: m.len}
|
||||
for k, _ in m {
|
||||
r << Tuple1[K]{k}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// map to array of value tuples
|
||||
fn map_to_array1_v[K, V](m map[K]V) []Tuple1[V] {
|
||||
mut r := []Tuple1[V]{cap: m.len}
|
||||
for _, v in m {
|
||||
r << Tuple1[V]{v}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// map to array of key-value tuples
|
||||
fn map_to_array2_k_v[K, V](m map[K]V) []Tuple2[K, V] {
|
||||
mut r := []Tuple2[K, V]{cap: m.len}
|
||||
for k, v in m {
|
||||
r << Tuple2[K, V]{k, v}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// map to array of value-key tuples
|
||||
fn map_to_array2_v_k[K, V](m map[K]V) []Tuple2[V, K] {
|
||||
mut r := []Tuple2[V, K]{cap: m.len}
|
||||
for k, v in m {
|
||||
r << Tuple2[V, K]{v, k}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// map to array of key-int tuples
|
||||
fn map_to_array2_k_int[K, V](m map[K]V) []Tuple2[K, int] {
|
||||
mut r := []Tuple2[K, int]{cap: m.len}
|
||||
mut i := 0
|
||||
for k, _ in m {
|
||||
r << Tuple2[K, int]{k, i}
|
||||
i += 1
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// map to array of value-int-key tuples
|
||||
fn map_to_array3_v_int_k[K, V](m map[K]V) []Tuple3[V, int, K] {
|
||||
mut r := []Tuple3[V, int, K]{cap: m.len}
|
||||
mut i := 0
|
||||
for k, v in m {
|
||||
r << Tuple3[V, int, K]{v, i, 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_array1_k(x)
|
||||
println(rx1)
|
||||
assert rx1[0].a == 'one'
|
||||
assert rx1[1].a == 'two'
|
||||
|
||||
rx2 := map_to_array1_v(x)
|
||||
println(rx2)
|
||||
assert rx2[0].a == 1
|
||||
assert rx2[1].a == 2
|
||||
|
||||
rx3 := map_to_array2_k_v(x)
|
||||
println(rx3)
|
||||
assert rx3[0].a == 'one'
|
||||
assert rx3[0].b == 1
|
||||
assert rx3[1].a == 'two'
|
||||
assert rx3[1].b == 2
|
||||
|
||||
rx4 := map_to_array2_v_k(x)
|
||||
println(rx4)
|
||||
assert rx4[0].a == 1
|
||||
assert rx4[0].b == 'one'
|
||||
assert rx4[1].a == 2
|
||||
assert rx4[1].b == 'two'
|
||||
|
||||
rx5 := map_to_array2_k_int(x)
|
||||
println(rx5)
|
||||
assert rx5[0].a == 'one'
|
||||
assert rx5[0].b == 0
|
||||
assert rx5[1].a == 'two'
|
||||
assert rx5[1].b == 1
|
||||
|
||||
rx6 := map_to_array3_v_int_k(x)
|
||||
println(rx6)
|
||||
assert rx6[0].a == 1
|
||||
assert rx6[0].b == 0
|
||||
assert rx6[0].c == 'one'
|
||||
assert rx6[1].a == 2
|
||||
assert rx6[1].b == 1
|
||||
assert rx6[1].c == 'two'
|
||||
|
||||
println(y)
|
||||
ry1 := map_to_array1_k(y)
|
||||
println(ry1)
|
||||
assert ry1[0].a == 3
|
||||
assert ry1[1].a == 4
|
||||
|
||||
ry2 := map_to_array1_v(y)
|
||||
println(ry2)
|
||||
assert ry2[0].a == 'three'
|
||||
assert ry2[1].a == 'four'
|
||||
|
||||
ry3 := map_to_array2_k_v(y)
|
||||
println(ry3)
|
||||
assert ry3[0].a == 3
|
||||
assert ry3[0].b == 'three'
|
||||
assert ry3[1].a == 4
|
||||
assert ry3[1].b == 'four'
|
||||
|
||||
ry4 := map_to_array2_v_k(y)
|
||||
println(ry4)
|
||||
assert ry4[0].a == 'three'
|
||||
assert ry4[0].b == 3
|
||||
assert ry4[1].a == 'four'
|
||||
assert ry4[1].b == 4
|
||||
|
||||
ry5 := map_to_array2_k_int(y)
|
||||
println(ry5)
|
||||
assert ry5[0].a == 3
|
||||
assert ry5[0].b == 0
|
||||
assert ry5[1].a == 4
|
||||
assert ry5[1].b == 1
|
||||
|
||||
ry6 := map_to_array3_v_int_k(y)
|
||||
println(ry6)
|
||||
assert ry6[0].a == 'three'
|
||||
assert ry6[0].b == 0
|
||||
assert ry6[0].c == 3
|
||||
assert ry6[1].a == 'four'
|
||||
assert ry6[1].b == 1
|
||||
assert ry6[1].c == 4
|
||||
}
|
Loading…
Reference in New Issue
Block a user