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 {
|
||||
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 {
|
||||
t_generic_names = sym.info.generic_types.map(t.sym(it).name)
|
||||
}
|
||||
for i in 0 .. sym.info.generic_types.len {
|
||||
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)
|
||||
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 {
|
||||
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}['
|
||||
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], generic_names,
|
||||
if ct := t.resolve_generic_to_concrete(ts.info.generic_types[i], t_generic_names,
|
||||
concrete_types)
|
||||
{
|
||||
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) {
|
||||
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, generic_names,
|
||||
fields[i].typ = t.unwrap_generic_type(fields[i].typ, t_generic_names,
|
||||
concrete_types)
|
||||
} 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)
|
||||
{
|
||||
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
|
||||
for i in 0 .. ts.info.generic_types.len {
|
||||
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
|
||||
}
|
||||
@ -2005,48 +2013,6 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
|
||||
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
|
||||
pub fn (mut t Table) generic_insts_to_concrete() {
|
||||
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)
|
||||
}
|
||||
// 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)
|
||||
for name in 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',
|
||||
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 {
|
||||
parent_sym := c.table.sym(struct_sym.info.parent_type)
|
||||
// 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…
Reference in New Issue
Block a user