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:
parent
46921480fc
commit
7543b769ad
@ -322,6 +322,7 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
|
|||||||
node.value_type = info.value_type
|
node.value_type = info.value_type
|
||||||
return node.typ
|
return node.typ
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.keys.len > 0 && node.vals.len > 0 {
|
if node.keys.len > 0 && node.vals.len > 0 {
|
||||||
mut key0_type := ast.void_type
|
mut key0_type := ast.void_type
|
||||||
mut val0_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
|
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
|
mut same_key_type := true
|
||||||
for i, key in node.keys {
|
for i, key in node.keys {
|
||||||
if i == 0 && !use_expected_type {
|
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
|
c.expected_type = val0_type
|
||||||
val_type := c.expr(val)
|
val_type := c.expr(val)
|
||||||
node.val_types << val_type
|
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()
|
if !c.check_types(key_type, key0_type) || (i == 0 && key_type.is_number()
|
||||||
&& key0_type.is_number() && key0_type != ast.mktyp(key_type)) {
|
&& key0_type.is_number() && key0_type != ast.mktyp(key_type)) {
|
||||||
msg := c.expected_msg(key_type, key0_type)
|
msg := c.expected_msg(key_type, key0_type)
|
||||||
c.error('invalid map key: $msg', key.pos())
|
c.error('invalid map key: $msg', key.pos())
|
||||||
same_key_type = false
|
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()
|
if !c.check_types(val_type, val0_type) || (i == 0 && val_type.is_number()
|
||||||
&& val0_type.is_number() && val0_type != ast.mktyp(val_type)) {
|
&& val0_type.is_number() && val0_type != ast.mktyp(val_type)) {
|
||||||
msg := c.expected_msg(val_type, val0_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)
|
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 map_type
|
||||||
}
|
}
|
||||||
return node.typ
|
return node.typ
|
||||||
|
@ -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{})}"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user