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 inconsistent generic types (#16697)

This commit is contained in:
yuyi 2022-12-18 00:17:43 +08:00 committed by GitHub
parent 9921598c91
commit e83a8416d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 20 deletions

View File

@ -1704,18 +1704,30 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
if sym.info.is_generic {
mut nrt := '${sym.name}['
mut t_generic_names := generic_names.clone()
if generic_names.len == sym.info.generic_types.len {
mut t_concrete_types := concrete_types.clone()
if sym.generic_types.len > 0 && sym.generic_types.len == sym.info.generic_types.len
&& sym.generic_types != sym.info.generic_types {
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]
}
}
}
for i in 0 .. sym.info.generic_types.len {
if ct := t.resolve_generic_to_concrete(sym.info.generic_types[i],
t_generic_names, concrete_types)
t_generic_names, t_concrete_types)
{
gts := t.sym(ct)
nrt += gts.name
if i != sym.info.generic_types.len - 1 {
nrt += ', '
}
} else {
return none
}
}
nrt += ']'
@ -1839,14 +1851,24 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
return typ
}
mut t_generic_names := generic_names.clone()
if generic_names.len == ts.info.generic_types.len {
mut t_concrete_types := concrete_types.clone()
if ts.generic_types.len > 0 && ts.generic_types.len == ts.info.generic_types.len
&& ts.generic_types != ts.info.generic_types {
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]
}
}
}
nrt = '${ts.name}['
c_nrt = '${ts.cname}_T_'
for i in 0 .. ts.info.generic_types.len {
if ct := t.resolve_generic_to_concrete(ts.info.generic_types[i], t_generic_names,
concrete_types)
t_concrete_types)
{
gts := t.sym(ct)
nrt += gts.name
@ -1855,6 +1877,8 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
nrt += ', '
c_nrt += '_'
}
} else {
return typ
}
}
nrt += ']'
@ -1869,10 +1893,10 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
sym := t.sym(fields[i].typ)
if sym.kind == .struct_ && fields[i].typ.idx() != typ.idx() {
fields[i].typ = t.unwrap_generic_type(fields[i].typ, t_generic_names,
concrete_types)
t_concrete_types)
} else {
if t_typ := t.resolve_generic_to_concrete(fields[i].typ, t_generic_names,
concrete_types)
t_concrete_types)
{
fields[i].typ = t_typ
}
@ -1882,7 +1906,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
// update concrete types
for i in 0 .. ts.info.generic_types.len {
if t_typ := t.resolve_generic_to_concrete(ts.info.generic_types[i],
t_generic_names, concrete_types)
t_generic_names, t_concrete_types)
{
final_concrete_types << t_typ
}
@ -1903,7 +1927,9 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
}
}
}
t.register_fn_concrete_types(method.fkey(), final_concrete_types)
if final_concrete_types.len == method.generic_names.len {
t.register_fn_concrete_types(method.fkey(), final_concrete_types)
}
}
}
}

View File

@ -89,17 +89,18 @@ pub struct TypeSymbol {
pub:
parent_idx int
pub mut:
info TypeInfo
kind Kind
name string // the internal & source name of the type, i.e. `[5]int`.
cname string // the name with no dots for use in the generated C code
methods []Fn
mod string
is_pub bool
language Language
idx int
size int = -1
align int = -1
info TypeInfo
kind Kind
name string // the internal & source name of the type, i.e. `[5]int`.
cname string // the name with no dots for use in the generated C code
methods []Fn
generic_types []Type
mod string
is_pub bool
language Language
idx int
size int = -1
align int = -1
}
// max of 8

View File

@ -647,7 +647,37 @@ pub fn (mut p Parser) find_type_or_add_placeholder(name string, language ast.Lan
// struct / enum / placeholder
mut idx := p.table.find_type_idx(name)
if idx > 0 {
return ast.new_type(idx)
mut typ := ast.new_type(idx)
sym := p.table.sym(typ)
match sym.info {
ast.Struct, ast.Interface, ast.SumType {
if p.struct_init_generic_types.len > 0 && sym.info.generic_types.len > 0
&& p.struct_init_generic_types != sym.info.generic_types {
generic_names := p.struct_init_generic_types.map(p.table.sym(it).name)
mut sym_name := sym.name + '['
for i, gt in generic_names {
sym_name += gt
if i != generic_names.len - 1 {
sym_name += ','
}
}
sym_name += ']'
existing_idx := p.table.type_idxs[sym_name]
if existing_idx > 0 {
idx = existing_idx
} else {
idx = p.table.register_sym(ast.TypeSymbol{
...sym
name: sym_name
generic_types: p.struct_init_generic_types.clone()
})
}
typ = ast.new_type(idx)
}
}
else {}
}
return typ
}
// not found - add placeholder
idx = p.table.add_placeholder_type(name, language)

View File

@ -0,0 +1,34 @@
module main
pub struct Maybe[T] {
present bool
val T
}
pub fn some[T](t T) Maybe[T] {
return Maybe[T]{true, t}
}
pub fn (me Maybe[T]) map[T, U](f fn (T) U) Maybe[U] {
if me.present {
return Maybe[U]{true, f(me.val)}
}
return Maybe[U]{}
}
pub fn (o Maybe[T]) get() ?T {
if o.present {
return o.val
} else {
return none
}
}
fn test_generics_struct_init_with_inconsistent_generic_types() {
m := some[int](12)
ret := m.map[int, string](fn (i int) string {
return i.str()
})
println(ret)
assert ret.val == '12'
}