1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: allow for all.children := { "abc": rect, "def": rectangle()}, where children is map[string]Widget, without needing explicit casts for all the map values

This commit is contained in:
Delyan Angelov 2022-11-10 13:04:24 +02:00
parent 46921480fc
commit 7543b769ad
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
2 changed files with 64 additions and 6 deletions

View File

@ -322,6 +322,7 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
node.value_type = info.value_type
return node.typ
}
if node.keys.len > 0 && node.vals.len > 0 {
mut key0_type := ast.void_type
mut val0_type := ast.void_type
@ -344,6 +345,15 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
}
node.val_types << val0_type
}
key0_type = c.unwrap_generic(key0_type)
val0_type = c.unwrap_generic(val0_type)
map_type := ast.new_type(c.table.find_or_register_map(key0_type, val0_type))
node.typ = map_type
node.key_type = key0_type
node.value_type = val0_type
map_value_sym := c.table.sym(node.value_type)
expecting_interface_map := map_value_sym.kind == .interface_
//
mut same_key_type := true
for i, key in node.keys {
if i == 0 && !use_expected_type {
@ -355,12 +365,32 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
c.expected_type = val0_type
val_type := c.expr(val)
node.val_types << val_type
val_type_sym := c.table.sym(val_type)
if !c.check_types(key_type, key0_type) || (i == 0 && key_type.is_number()
&& key0_type.is_number() && key0_type != ast.mktyp(key_type)) {
msg := c.expected_msg(key_type, key0_type)
c.error('invalid map key: $msg', key.pos())
same_key_type = false
}
if expecting_interface_map {
if val_type == node.value_type {
continue
}
if val_type_sym.kind == .struct_
&& c.type_implements(val_type, node.value_type, val.pos()) {
node.vals[i] = ast.CastExpr{
expr: val
typname: c.table.get_type_name(node.value_type)
typ: node.value_type
expr_type: val_type
pos: val.pos()
}
continue
} else {
msg := c.expected_msg(val_type, node.value_type)
c.error('invalid map value: $msg', val.pos())
}
}
if !c.check_types(val_type, val0_type) || (i == 0 && val_type.is_number()
&& val0_type.is_number() && val0_type != ast.mktyp(val_type)) {
msg := c.expected_msg(val_type, val0_type)
@ -372,12 +402,6 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
c.check_dup_keys(node, i)
}
}
key0_type = c.unwrap_generic(key0_type)
val0_type = c.unwrap_generic(val0_type)
mut map_type := ast.new_type(c.table.find_or_register_map(key0_type, val0_type))
node.typ = map_type
node.key_type = key0_type
node.value_type = val0_type
return map_type
}
return node.typ

View File

@ -0,0 +1,34 @@
interface Widget {}
struct Rectangle {}
struct Children {
mut:
children map[string]Widget
}
fn rectangle() &Rectangle {
return &Rectangle{}
}
fn test_map_of_interfaces_infers_interface_casts_of_the_map_values() {
rect := rectangle()
mut m := map[string]Widget{}
m = {
'abc': rect
'def': rectangle()
}
res := m.str()
assert res == "{'abc': Widget(Rectangle{}), 'def': Widget(Rectangle{})}"
}
fn test_map_of_interfaces_infers_casts_of_the_map_values_when_assigned_to_a_struct_field_too() {
mut all := &Children{}
rect := rectangle()
all.children = {
'abc': rect
'def': rectangle()
}
res := all.children.str()
assert res == "{'abc': Widget(Rectangle{}), 'def': Widget(Rectangle{})}"
}