checker: fix map assign array of interface values (#10532)

pull/10540/head
yuyi 2021-06-22 00:24:42 +08:00 committed by GitHub
parent e259f7ac58
commit da4b6b934d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 13 deletions

View File

@ -6872,30 +6872,43 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
return node.typ
}
if node.keys.len > 0 && node.vals.len > 0 {
// `{'age': 20}`
mut key0_type := c.table.mktyp(c.expr(node.keys[0]))
if node.keys[0].is_auto_deref_var() {
key0_type = key0_type.deref()
}
mut val0_type := c.table.mktyp(c.expr(node.vals[0]))
if node.vals[0].is_auto_deref_var() {
val0_type = val0_type.deref()
mut key0_type := ast.void_type
mut val0_type := ast.void_type
use_expected_type := c.expected_type != ast.void_type && !c.inside_const
&& c.table.get_type_symbol(c.expected_type).kind == .map
if use_expected_type {
sym := c.table.get_type_symbol(c.expected_type)
info := sym.map_info()
key0_type = c.unwrap_generic(info.key_type)
val0_type = c.unwrap_generic(info.value_type)
} else {
// `{'age': 20}`
key0_type = c.table.mktyp(c.expr(node.keys[0]))
if node.keys[0].is_auto_deref_var() {
key0_type = key0_type.deref()
}
val0_type = c.table.mktyp(c.expr(node.vals[0]))
if node.vals[0].is_auto_deref_var() {
val0_type = val0_type.deref()
}
}
mut same_key_type := true
for i, key in node.keys {
if i == 0 {
if i == 0 && !use_expected_type {
continue
}
val := node.vals[i]
key_type := c.expr(key)
c.expected_type = val0_type
val_type := c.expr(val)
if !c.check_types(key_type, key0_type) {
if !c.check_types(key_type, key0_type) || (i == 0 && key_type.is_number()
&& key0_type.is_number() && key0_type != c.table.mktyp(key_type)) {
msg := c.expected_msg(key_type, key0_type)
c.error('invalid map key: $msg', key.position())
same_key_type = false
}
if !c.check_types(val_type, val0_type) {
if !c.check_types(val_type, val0_type) || (i == 0 && val_type.is_number()
&& val0_type.is_number() && val0_type != c.table.mktyp(val_type)) {
msg := c.expected_msg(val_type, val0_type)
c.error('invalid map value: $msg', val.position())
}

View File

@ -1,8 +1,8 @@
vlib/v/checker/tests/map_init_wrong_type.vv:3:8: error: cannot assign to `a`: expected `map[string]f32`, not `map[string]f64`
vlib/v/checker/tests/map_init_wrong_type.vv:3:15: error: invalid map value: expected `f32`, not `float literal`
1 | fn main() {
2 | mut a := map[string]f32{}
3 | a = { 'x': 12.3 }
| ~~~~~~~~~~~~~
| ~~~~
4 | _ = {2:0 3:0 "hi":0}
5 | _ = {2:0 3:`@` 4:0}
vlib/v/checker/tests/map_init_wrong_type.vv:4:17: error: invalid map key: expected `int`, not `string`

View File

@ -0,0 +1,40 @@
interface Animal {
say(message string) ?
}
struct Cat {
name string
}
struct Dog {
name string
}
pub fn (cat Cat) say(message string) ? {
println('$message, meow')
}
pub fn (dog Dog) say(message string) ? {
println('$message, wooff')
}
fn test_map_assign_array_of_interface() {
mut owner_and_animals := map[string][]Animal{}
owner_and_animals = map{
'John Doe': [
Cat{
name: 'Bobby'
},
Dog{
name: 'Hulk'
},
]
}
println(owner_and_animals)
assert owner_and_animals['John Doe'].len == 2
println(owner_and_animals['John Doe'][0])
assert '${owner_and_animals['John Doe'][0]}'.contains("name: 'Bobby'")
println(owner_and_animals['John Doe'][1])
assert '${owner_and_animals['John Doe'][1]}'.contains("name: 'Hulk'")
}