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:
parent
9921598c91
commit
e83a8416d5
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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'
|
||||
}
|
Loading…
Reference in New Issue
Block a user