1
0
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:
Swastik Baranwal 2023-01-03 13:51:32 +05:30 committed by GitHub
parent 2e54a8cb0e
commit 09766c44b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 2 deletions

View File

@ -459,6 +459,7 @@ pub mut:
typ Type // the type of this struct
update_expr Expr // `a` in `...a`
update_expr_type Type
update_expr_pos token.Pos
update_expr_comments []Comment
is_update_embed bool
has_update_expr bool // has `...a`

View File

@ -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
if !type_sym.is_pub && type_sym.kind != .placeholder && type_sym.language != .c
&& (type_sym.mod != c.mod && !(node.typ.has_flag(.generic) && type_sym.mod != 'builtin')) {
if !node.has_update_expr && !type_sym.is_pub && type_sym.kind != .placeholder
&& 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)
}
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 {
update_type := c.expr(node.update_expr)
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_ {
s := c.table.type_to_str(update_type)
c.error('expected struct, found `${s}`', node.update_expr.pos())

View 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 | }

View 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)
}

View File

@ -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_comments := []ast.Comment{}
mut has_update_expr := false
mut update_expr_pos := token.Pos{}
for p.tok.kind !in [.rcbr, .rpar, .eof] {
mut field_name := ''
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)
} else if is_update_expr {
// struct updating syntax; f2 := Foo{ ...f, name: 'f2' }
update_expr_pos = p.tok.pos()
p.check(.ellipsis)
update_expr = p.expr(0)
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
fields: fields
update_expr: update_expr
update_expr_pos: update_expr_pos
update_expr_comments: update_expr_comments
has_update_expr: has_update_expr
name_pos: first_pos