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

checker: disallow Bar{...foo} when Bar needs more fields, than what foo has (#16609)

This commit is contained in:
Felipe Pena 2022-12-07 11:56:07 -03:00 committed by GitHub
parent 458e68e196
commit 2261606b56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 1 deletions

View File

@ -4003,6 +4003,22 @@ fn (mut c Checker) error(message string, pos token.Pos) {
c.warn_or_error(msg, pos, false)
}
fn (c &Checker) check_struct_signature_init_fields(from ast.Struct, to ast.Struct, node ast.StructInit) bool {
if node.fields.len == 0 {
return from.fields.len == to.fields.len
}
mut count_not_in_from := 0
for field in node.fields {
filtered := from.fields.filter(it.name == field.name)
if filtered.len != 1 {
count_not_in_from++
}
}
return (from.fields.len + count_not_in_from) == to.fields.len
}
// check `to` has all fields of `from`
fn (c &Checker) check_struct_signature(from ast.Struct, to ast.Struct) bool {
// Note: `to` can have extra fields

View File

@ -603,7 +603,8 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
from_info := from_sym.info as ast.Struct
to_info := to_sym.info as ast.Struct
// TODO this check is too strict
if !c.check_struct_signature(from_info, to_info) {
if !c.check_struct_signature(from_info, to_info)
|| !c.check_struct_signature_init_fields(from_info, to_info, node) {
c.error('struct `${from_sym.name}` is not compatible with struct `${to_sym.name}`',
node.update_expr.pos())
}

View File

@ -0,0 +1,14 @@
vlib/v/checker/tests/check_incompatible_struct.vv:17:6: error: struct `Foo` is not compatible with struct `Bar`
15 | }
16 | bar3 := Bar{
17 | ...foo
| ~~~
18 | b: 1
19 | }
vlib/v/checker/tests/check_incompatible_struct.vv:26:6: error: struct `Foo` is not compatible with struct `Bar`
24 | }
25 | bar := Bar{
26 | ...foo
| ~~~
27 | }
28 | print(bar)

View File

@ -0,0 +1,32 @@
struct Foo {
b int
}
struct Bar {
a int
b int
}
fn main() {
foo := Foo{2}
bar2 := Bar{
...foo
a: 1
}
bar3 := Bar{
...foo
b: 1
}
bar4 := Bar{
...foo
b: 1
a: 2
}
bar := Bar{
...foo
}
print(bar)
print(bar2)
print(bar3)
print(bar4)
}