mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: disallow struct{...val.$(field.name)}
(#16852)
This commit is contained in:
parent
2e54a8cb0e
commit
09766c44b6
@ -459,6 +459,7 @@ pub mut:
|
|||||||
typ Type // the type of this struct
|
typ Type // the type of this struct
|
||||||
update_expr Expr // `a` in `...a`
|
update_expr Expr // `a` in `...a`
|
||||||
update_expr_type Type
|
update_expr_type Type
|
||||||
|
update_expr_pos token.Pos
|
||||||
update_expr_comments []Comment
|
update_expr_comments []Comment
|
||||||
is_update_embed bool
|
is_update_embed bool
|
||||||
has_update_expr bool // has `...a`
|
has_update_expr bool // has `...a`
|
||||||
|
@ -334,8 +334,9 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// allow init structs from generic if they're private except the type is from builtin module
|
// allow init structs from generic if they're private except the type is from builtin module
|
||||||
if !type_sym.is_pub && type_sym.kind != .placeholder && type_sym.language != .c
|
if !node.has_update_expr && !type_sym.is_pub && type_sym.kind != .placeholder
|
||||||
&& (type_sym.mod != c.mod && !(node.typ.has_flag(.generic) && type_sym.mod != 'builtin')) {
|
&& type_sym.language != .c && (type_sym.mod != c.mod && !(node.typ.has_flag(.generic)
|
||||||
|
&& type_sym.mod != 'builtin')) {
|
||||||
c.error('type `${type_sym.name}` is private', node.pos)
|
c.error('type `${type_sym.name}` is private', node.pos)
|
||||||
}
|
}
|
||||||
if type_sym.kind == .struct_ {
|
if type_sym.kind == .struct_ {
|
||||||
@ -591,6 +592,9 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
|||||||
if node.has_update_expr {
|
if node.has_update_expr {
|
||||||
update_type := c.expr(node.update_expr)
|
update_type := c.expr(node.update_expr)
|
||||||
node.update_expr_type = update_type
|
node.update_expr_type = update_type
|
||||||
|
if node.update_expr is ast.ComptimeSelector {
|
||||||
|
c.error('cannot use struct update syntax in compile time expressions', node.update_expr_pos)
|
||||||
|
}
|
||||||
if c.table.final_sym(update_type).kind != .struct_ {
|
if c.table.final_sym(update_type).kind != .struct_ {
|
||||||
s := c.table.type_to_str(update_type)
|
s := c.table.type_to_str(update_type)
|
||||||
c.error('expected struct, found `${s}`', node.update_expr.pos())
|
c.error('expected struct, found `${s}`', node.update_expr.pos())
|
||||||
|
7
vlib/v/checker/tests/struct_update_comptime_err.out
Normal file
7
vlib/v/checker/tests/struct_update_comptime_err.out
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
vlib/v/checker/tests/struct_update_comptime_err.vv:18:4: error: cannot use struct update syntax in compile time expressions
|
||||||
|
16 | $for field in U.fields {
|
||||||
|
17 | _ = struct {
|
||||||
|
18 | ...val.$(field.name)
|
||||||
|
| ~~~
|
||||||
|
19 | }
|
||||||
|
20 | }
|
32
vlib/v/checker/tests/struct_update_comptime_err.vv
Normal file
32
vlib/v/checker/tests/struct_update_comptime_err.vv
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
struct Aa {
|
||||||
|
sub Bb
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AaWithAliasType {
|
||||||
|
sub Bb
|
||||||
|
}
|
||||||
|
|
||||||
|
type AliasType = Bb
|
||||||
|
|
||||||
|
struct Bb {
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_struct[U](val U) {
|
||||||
|
$for field in U.fields {
|
||||||
|
_ = struct {
|
||||||
|
...val.$(field.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
aa := Aa{}
|
||||||
|
bb := Bb{}
|
||||||
|
aa_with_alias_type := AaWithAliasType{}
|
||||||
|
|
||||||
|
encode_struct(aa)
|
||||||
|
encode_struct(aa_with_alias_type)
|
||||||
|
|
||||||
|
encode_struct(bb)
|
||||||
|
}
|
@ -408,6 +408,7 @@ fn (mut p Parser) struct_init(typ_str string, kind ast.StructInitKind) ast.Struc
|
|||||||
mut update_expr := ast.empty_expr
|
mut update_expr := ast.empty_expr
|
||||||
mut update_expr_comments := []ast.Comment{}
|
mut update_expr_comments := []ast.Comment{}
|
||||||
mut has_update_expr := false
|
mut has_update_expr := false
|
||||||
|
mut update_expr_pos := token.Pos{}
|
||||||
for p.tok.kind !in [.rcbr, .rpar, .eof] {
|
for p.tok.kind !in [.rcbr, .rpar, .eof] {
|
||||||
mut field_name := ''
|
mut field_name := ''
|
||||||
mut expr := ast.empty_expr
|
mut expr := ast.empty_expr
|
||||||
@ -424,6 +425,7 @@ fn (mut p Parser) struct_init(typ_str string, kind ast.StructInitKind) ast.Struc
|
|||||||
comments = p.eat_comments(same_line: true)
|
comments = p.eat_comments(same_line: true)
|
||||||
} else if is_update_expr {
|
} else if is_update_expr {
|
||||||
// struct updating syntax; f2 := Foo{ ...f, name: 'f2' }
|
// struct updating syntax; f2 := Foo{ ...f, name: 'f2' }
|
||||||
|
update_expr_pos = p.tok.pos()
|
||||||
p.check(.ellipsis)
|
p.check(.ellipsis)
|
||||||
update_expr = p.expr(0)
|
update_expr = p.expr(0)
|
||||||
update_expr_comments << p.eat_comments(same_line: true)
|
update_expr_comments << p.eat_comments(same_line: true)
|
||||||
@ -475,6 +477,7 @@ fn (mut p Parser) struct_init(typ_str string, kind ast.StructInitKind) ast.Struc
|
|||||||
typ: typ
|
typ: typ
|
||||||
fields: fields
|
fields: fields
|
||||||
update_expr: update_expr
|
update_expr: update_expr
|
||||||
|
update_expr_pos: update_expr_pos
|
||||||
update_expr_comments: update_expr_comments
|
update_expr_comments: update_expr_comments
|
||||||
has_update_expr: has_update_expr
|
has_update_expr: has_update_expr
|
||||||
name_pos: first_pos
|
name_pos: first_pos
|
||||||
|
Loading…
x
Reference in New Issue
Block a user