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:
parent
458e68e196
commit
2261606b56
@ -4003,6 +4003,22 @@ fn (mut c Checker) error(message string, pos token.Pos) {
|
|||||||
c.warn_or_error(msg, pos, false)
|
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`
|
// check `to` has all fields of `from`
|
||||||
fn (c &Checker) check_struct_signature(from ast.Struct, to ast.Struct) bool {
|
fn (c &Checker) check_struct_signature(from ast.Struct, to ast.Struct) bool {
|
||||||
// Note: `to` can have extra fields
|
// Note: `to` can have extra fields
|
||||||
|
@ -603,7 +603,8 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
|||||||
from_info := from_sym.info as ast.Struct
|
from_info := from_sym.info as ast.Struct
|
||||||
to_info := to_sym.info as ast.Struct
|
to_info := to_sym.info as ast.Struct
|
||||||
// TODO this check is too strict
|
// 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}`',
|
c.error('struct `${from_sym.name}` is not compatible with struct `${to_sym.name}`',
|
||||||
node.update_expr.pos())
|
node.update_expr.pos())
|
||||||
}
|
}
|
||||||
|
14
vlib/v/checker/tests/check_incompatible_struct.out
Normal file
14
vlib/v/checker/tests/check_incompatible_struct.out
Normal 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)
|
32
vlib/v/checker/tests/check_incompatible_struct.vv
Normal file
32
vlib/v/checker/tests/check_incompatible_struct.vv
Normal 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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user