Skip to content

Commit

Permalink
ast: fix concrete of generic structs when used as array or maps eleme…
Browse files Browse the repository at this point in the history
…nts(fix #18852)
  • Loading branch information
shove70 committed Aug 17, 2023
1 parent d0e6057 commit e82142d
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 7 deletions.
73 changes: 66 additions & 7 deletions vlib/v/ast/table.v
Original file line number Diff line number Diff line change
Expand Up @@ -1692,7 +1692,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
{
gts := t.sym(ct)
if ct.is_ptr() {
nrt += '&'
nrt += '&'.repeat(ct.nr_muls())
}
nrt += gts.name
rnrt += gts.name
Expand Down Expand Up @@ -1794,6 +1794,62 @@ pub fn (mut t Table) generic_type_names(generic_type Type) []string {
return names
}

// check if there are fields whose array or map elements are generic structs
fn (mut t Table) check_elements_is_exists_generic_structs(typ Type) bool {
sym := t.sym(typ)
if sym.kind !in [.struct_, .array, .array_fixed, .map] {
return false
}

mut typs := []Type{}
if sym.kind in [.array, .array_fixed, .map] {
match sym.info {
Array {
typs << (sym.info as Array).elem_type
}
ArrayFixed {
typs << (sym.info as ArrayFixed).elem_type
}
Map {
typs << (sym.info as Map).key_type
typs << (sym.info as Map).value_type
}
else {}
}
for typ_ in typs {
t_sym := t.sym(typ_)
match t_sym.info {
Struct, Interface, SumType {
if t_sym.info.is_generic {
return true
}
}
else {}
}
if t.check_elements_is_exists_generic_structs(typ_) {
return true
}
}
return false
}

if sym.language != .v {
return false
}
fields := t.struct_fields(sym)
if fields.len == 0 {
return false
}
for field in fields {
if t.sym(field.typ).kind in [.array, .array_fixed, .map] {
if t.check_elements_is_exists_generic_structs(field.typ) {
return true
}
}
}
return false
}

pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concrete_types []Type) Type {
mut final_concrete_types := []Type{}
mut fields := []StructField{}
Expand Down Expand Up @@ -1871,7 +1927,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
{
gts := t.sym(ct)
if ct.is_ptr() {
nrt += '&'
nrt += '&'.repeat(ct.nr_muls())
}
nrt += gts.name
c_nrt += gts.cname
Expand All @@ -1891,13 +1947,16 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
// fields type translate to concrete type
fields = ts.info.fields.clone()
for i in 0 .. fields.len {
if fields[i].typ.has_flag(.generic) {
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,
field_typ := fields[i].typ
field_sym := t.sym(field_typ)
if field_typ.has_flag(.generic) {
if field_typ.idx() != typ.idx() && (field_sym.kind == .struct_
|| (field_sym.kind in [.array, .array_fixed, .map]
&& t.check_elements_is_exists_generic_structs(field_typ))) {
fields[i].typ = t.unwrap_generic_type(field_typ, t_generic_names,
t_concrete_types)
} else {
if t_typ := t.resolve_generic_to_concrete(fields[i].typ, t_generic_names,
if t_typ := t.resolve_generic_to_concrete(field_typ, t_generic_names,
t_concrete_types)
{
fields[i].typ = t_typ
Expand Down
24 changes: 24 additions & 0 deletions vlib/v/tests/generics_struct_as_elements_concrete_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
struct Root[T] {
edges1 map[int]Edge[T]
edges2 map[int][]Edge[T]
edges3 []Edge[T]
edges4 [][]Edge[T]
edges5 []T
edges6 [][]T
}

struct Edge[T] {
}

fn new[T]() Root[T] {
return Root[T]{}
}

// for issue 18852
fn test_generics_struct_as_elements_concrete() {
t1 := new[int]()
dump(t1)
t2 := new[&int]()
dump(t2)
assert true
}

0 comments on commit e82142d

Please sign in to comment.