checker: ensure `expr` is an lvalue with `Struct{...expr` (#8489)
parent
d660f2cc6f
commit
c537578481
|
@ -680,12 +680,17 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
|
||||||
if struct_init.has_update_expr {
|
if struct_init.has_update_expr {
|
||||||
update_type := c.expr(struct_init.update_expr)
|
update_type := c.expr(struct_init.update_expr)
|
||||||
struct_init.update_expr_type = update_type
|
struct_init.update_expr_type = update_type
|
||||||
update_sym := c.table.get_type_symbol(update_type)
|
if c.table.type_kind(update_type) != .struct_ {
|
||||||
sym := c.table.get_type_symbol(struct_init.typ)
|
s := c.table.type_to_str(update_type)
|
||||||
if update_sym.kind != .struct_ {
|
c.error('expected struct, found `$s`', struct_init.update_expr.position())
|
||||||
c.error('expected struct `$sym.name`, found `$update_sym.name`', struct_init.update_expr.position())
|
|
||||||
} else if update_type != struct_init.typ {
|
} else if update_type != struct_init.typ {
|
||||||
|
sym := c.table.get_type_symbol(struct_init.typ)
|
||||||
|
update_sym := c.table.get_type_symbol(update_type)
|
||||||
c.error('expected struct `$sym.name`, found struct `$update_sym.name`', struct_init.update_expr.position())
|
c.error('expected struct `$sym.name`, found struct `$update_sym.name`', struct_init.update_expr.position())
|
||||||
|
} else if !struct_init.update_expr.is_lvalue() {
|
||||||
|
// cgen will repeat `update_expr` for each field
|
||||||
|
// so enforce an lvalue for efficiency
|
||||||
|
c.error('expression is not an lvalue', struct_init.update_expr.position())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return struct_init.typ
|
return struct_init.typ
|
||||||
|
|
|
@ -1,7 +1,28 @@
|
||||||
vlib/v/checker/tests/struct_init_update_type_err.vv:11:6: error: expected struct `Foo`, found `int`
|
vlib/v/checker/tests/struct_init_update_type_err.vv:11:6: error: expected struct, found `int`
|
||||||
9 | f3 := 2
|
9 | i := 2
|
||||||
10 | _ := Foo{
|
10 | _ := Foo{
|
||||||
11 | ...f3
|
11 | ...i
|
||||||
| ~~
|
| ^
|
||||||
12 | name: 'f2'
|
12 | name: 'f2'
|
||||||
13 | }
|
13 | }
|
||||||
|
vlib/v/checker/tests/struct_init_update_type_err.vv:16:6: error: expected struct, found `&int`
|
||||||
|
14 | p := &i
|
||||||
|
15 | _ = Foo{
|
||||||
|
16 | ...p
|
||||||
|
| ^
|
||||||
|
17 | }
|
||||||
|
18 | f2 := Foo2{}
|
||||||
|
vlib/v/checker/tests/struct_init_update_type_err.vv:20:6: error: expected struct `Foo`, found struct `Foo2`
|
||||||
|
18 | f2 := Foo2{}
|
||||||
|
19 | _ = Foo{
|
||||||
|
20 | ...f2
|
||||||
|
| ~~
|
||||||
|
21 | }
|
||||||
|
22 | _ = Foo{
|
||||||
|
vlib/v/checker/tests/struct_init_update_type_err.vv:23:6: error: expression is not an lvalue
|
||||||
|
21 | }
|
||||||
|
22 | _ = Foo{
|
||||||
|
23 | ...Foo{}
|
||||||
|
| ~~~~~
|
||||||
|
24 | }
|
||||||
|
25 | }
|
||||||
|
|
|
@ -3,13 +3,24 @@ struct Foo {
|
||||||
age int
|
age int
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Foo2 {}
|
struct Foo2 {b bool}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
f3 := 2
|
i := 2
|
||||||
_ := Foo{
|
_ := Foo{
|
||||||
...f3
|
...i
|
||||||
name: 'f2'
|
name: 'f2'
|
||||||
}
|
}
|
||||||
|
p := &i
|
||||||
|
_ = Foo{
|
||||||
|
...p
|
||||||
|
}
|
||||||
|
f2 := Foo2{}
|
||||||
|
_ = Foo{
|
||||||
|
...f2
|
||||||
|
}
|
||||||
|
_ = Foo{
|
||||||
|
...Foo{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue