mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
ast, checker: fix generic struct init with inconsistent generic types (#16675)
This commit is contained in:
parent
7f23ae595b
commit
8ab4c7742c
@ -1703,9 +1703,13 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
|||||||
Struct, Interface, SumType {
|
Struct, Interface, SumType {
|
||||||
if sym.info.is_generic {
|
if sym.info.is_generic {
|
||||||
mut nrt := '${sym.name}['
|
mut nrt := '${sym.name}['
|
||||||
|
mut t_generic_names := generic_names.clone()
|
||||||
|
if generic_names.len == sym.info.generic_types.len {
|
||||||
|
t_generic_names = sym.info.generic_types.map(t.sym(it).name)
|
||||||
|
}
|
||||||
for i in 0 .. sym.info.generic_types.len {
|
for i in 0 .. sym.info.generic_types.len {
|
||||||
if ct := t.resolve_generic_to_concrete(sym.info.generic_types[i],
|
if ct := t.resolve_generic_to_concrete(sym.info.generic_types[i],
|
||||||
generic_names, concrete_types)
|
t_generic_names, concrete_types)
|
||||||
{
|
{
|
||||||
gts := t.sym(ct)
|
gts := t.sym(ct)
|
||||||
nrt += gts.name
|
nrt += gts.name
|
||||||
@ -1834,10 +1838,14 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
|
|||||||
if !ts.info.is_generic {
|
if !ts.info.is_generic {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
mut t_generic_names := generic_names.clone()
|
||||||
|
if generic_names.len == ts.info.generic_types.len {
|
||||||
|
t_generic_names = ts.info.generic_types.map(t.sym(it).name)
|
||||||
|
}
|
||||||
nrt = '${ts.name}['
|
nrt = '${ts.name}['
|
||||||
c_nrt = '${ts.cname}_T_'
|
c_nrt = '${ts.cname}_T_'
|
||||||
for i in 0 .. ts.info.generic_types.len {
|
for i in 0 .. ts.info.generic_types.len {
|
||||||
if ct := t.resolve_generic_to_concrete(ts.info.generic_types[i], generic_names,
|
if ct := t.resolve_generic_to_concrete(ts.info.generic_types[i], t_generic_names,
|
||||||
concrete_types)
|
concrete_types)
|
||||||
{
|
{
|
||||||
gts := t.sym(ct)
|
gts := t.sym(ct)
|
||||||
@ -1860,10 +1868,10 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
|
|||||||
if fields[i].typ.has_flag(.generic) {
|
if fields[i].typ.has_flag(.generic) {
|
||||||
sym := t.sym(fields[i].typ)
|
sym := t.sym(fields[i].typ)
|
||||||
if sym.kind == .struct_ && fields[i].typ.idx() != typ.idx() {
|
if sym.kind == .struct_ && fields[i].typ.idx() != typ.idx() {
|
||||||
fields[i].typ = t.unwrap_generic_type(fields[i].typ, generic_names,
|
fields[i].typ = t.unwrap_generic_type(fields[i].typ, t_generic_names,
|
||||||
concrete_types)
|
concrete_types)
|
||||||
} else {
|
} else {
|
||||||
if t_typ := t.resolve_generic_to_concrete(fields[i].typ, generic_names,
|
if t_typ := t.resolve_generic_to_concrete(fields[i].typ, t_generic_names,
|
||||||
concrete_types)
|
concrete_types)
|
||||||
{
|
{
|
||||||
fields[i].typ = t_typ
|
fields[i].typ = t_typ
|
||||||
@ -1874,7 +1882,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
|
|||||||
// update concrete types
|
// update concrete types
|
||||||
for i in 0 .. ts.info.generic_types.len {
|
for i in 0 .. ts.info.generic_types.len {
|
||||||
if t_typ := t.resolve_generic_to_concrete(ts.info.generic_types[i],
|
if t_typ := t.resolve_generic_to_concrete(ts.info.generic_types[i],
|
||||||
generic_names, concrete_types)
|
t_generic_names, concrete_types)
|
||||||
{
|
{
|
||||||
final_concrete_types << t_typ
|
final_concrete_types << t_typ
|
||||||
}
|
}
|
||||||
@ -2005,48 +2013,6 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
|
|||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
// Foo[U]{ bar: U } to Foo[T]{ bar: T }
|
|
||||||
pub fn (mut t Table) replace_generic_type(typ Type, generic_types []Type) {
|
|
||||||
mut ts := t.sym(typ)
|
|
||||||
match mut ts.info {
|
|
||||||
Array {
|
|
||||||
mut elem_type := ts.info.elem_type
|
|
||||||
mut elem_sym := t.sym(elem_type)
|
|
||||||
mut dims := 1
|
|
||||||
for mut elem_sym.info is Array {
|
|
||||||
elem_type = elem_sym.info.elem_type
|
|
||||||
elem_sym = t.sym(elem_type)
|
|
||||||
dims++
|
|
||||||
}
|
|
||||||
t.replace_generic_type(elem_type, generic_types)
|
|
||||||
}
|
|
||||||
ArrayFixed {
|
|
||||||
t.replace_generic_type(ts.info.elem_type, generic_types)
|
|
||||||
}
|
|
||||||
Chan {
|
|
||||||
t.replace_generic_type(ts.info.elem_type, generic_types)
|
|
||||||
}
|
|
||||||
Map {
|
|
||||||
t.replace_generic_type(ts.info.key_type, generic_types)
|
|
||||||
t.replace_generic_type(ts.info.value_type, generic_types)
|
|
||||||
}
|
|
||||||
Struct, Interface, SumType {
|
|
||||||
generic_names := ts.info.generic_types.map(t.sym(it).name)
|
|
||||||
for i in 0 .. ts.info.fields.len {
|
|
||||||
if ts.info.fields[i].typ.has_flag(.generic) {
|
|
||||||
if t_typ := t.resolve_generic_to_concrete(ts.info.fields[i].typ, generic_names,
|
|
||||||
generic_types)
|
|
||||||
{
|
|
||||||
ts.info.fields[i].typ = t_typ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ts.info.generic_types = generic_types
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// generic struct instantiations to concrete types
|
// generic struct instantiations to concrete types
|
||||||
pub fn (mut t Table) generic_insts_to_concrete() {
|
pub fn (mut t Table) generic_insts_to_concrete() {
|
||||||
for mut sym in t.type_symbols {
|
for mut sym in t.type_symbols {
|
||||||
|
@ -131,7 +131,10 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||||||
c.error('fixed array cannot be returned by function', node.return_type_pos)
|
c.error('fixed array cannot be returned by function', node.return_type_pos)
|
||||||
}
|
}
|
||||||
// Ensure each generic type of the parameter was declared in the function's definition
|
// Ensure each generic type of the parameter was declared in the function's definition
|
||||||
if node.return_type.has_flag(.generic) {
|
// TODO: fix inconsistent return_type type case
|
||||||
|
if node.return_type.has_flag(.generic) && (return_sym.kind == .any
|
||||||
|
|| (return_sym.kind == .array
|
||||||
|
&& c.table.sym((return_sym.info as ast.Array).elem_type).kind == .any)) {
|
||||||
generic_names := c.table.generic_type_names(node.return_type)
|
generic_names := c.table.generic_type_names(node.return_type)
|
||||||
for name in generic_names {
|
for name in generic_names {
|
||||||
if name !in node.generic_names {
|
if name !in node.generic_names {
|
||||||
|
@ -286,10 +286,6 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
|||||||
c.error('a non generic struct `${node.typ_str}` used like a generic struct',
|
c.error('a non generic struct `${node.typ_str}` used like a generic struct',
|
||||||
node.name_pos)
|
node.name_pos)
|
||||||
}
|
}
|
||||||
if node.generic_types.len > 0 && struct_sym.info.generic_types.len == node.generic_types.len
|
|
||||||
&& struct_sym.info.generic_types != node.generic_types {
|
|
||||||
c.table.replace_generic_type(node.typ, node.generic_types)
|
|
||||||
}
|
|
||||||
} else if struct_sym.info is ast.Alias {
|
} else if struct_sym.info is ast.Alias {
|
||||||
parent_sym := c.table.sym(struct_sym.info.parent_type)
|
parent_sym := c.table.sym(struct_sym.info.parent_type)
|
||||||
// e.g. ´x := MyMapAlias{}´, should be a cast to alias type ´x := MyMapAlias(map[...]...)´
|
// e.g. ´x := MyMapAlias{}´, should be a cast to alias type ´x := MyMapAlias(map[...]...)´
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
struct Tuple[A, B] {
|
||||||
|
a A
|
||||||
|
b B
|
||||||
|
}
|
||||||
|
|
||||||
|
// map to array of key-value tuples
|
||||||
|
fn map_to_array[K, V](m map[K]V) []Tuple[K, V] {
|
||||||
|
mut r := []Tuple[K, V]{cap: m.len}
|
||||||
|
for k, v in m {
|
||||||
|
r << Tuple[K, V]{k, v}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generics_struct_init_with_inconsistent_generic_types() {
|
||||||
|
x := {
|
||||||
|
'one': 1
|
||||||
|
'two': 2
|
||||||
|
}
|
||||||
|
println(x)
|
||||||
|
arr := map_to_array(x)
|
||||||
|
println(arr)
|
||||||
|
assert arr.len == 2
|
||||||
|
assert arr[0].a == 'one'
|
||||||
|
assert arr[0].b == 1
|
||||||
|
assert arr[1].a == 'two'
|
||||||
|
assert arr[1].b == 2
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user