Skip to content

Commit

Permalink
checker: disallow structs with @[params] attribute as mutable funct…
Browse files Browse the repository at this point in the history
…ion parameters (#21206)
  • Loading branch information
ttytm committed May 4, 2024
1 parent 206441c commit f0abc45
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 16 deletions.
11 changes: 9 additions & 2 deletions vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.error('generic struct `${pure_sym_name}` in fn declaration must specify the generic type names, e.g. ${pure_sym_name}[T]',
param.type_pos)
}
if param.is_mut && arg_typ_sym.info.attrs.any(it.name == 'params') {
c.error('declaring a mutable parameter that accepts a struct with the `@[params]` attribute is not allowed',
param.type_pos)
}
} else if arg_typ_sym.info is ast.Interface {
if arg_typ_sym.info.generic_types.len > 0 && !param.typ.has_flag(.generic)
&& arg_typ_sym.info.concrete_types.len == 0 {
Expand Down Expand Up @@ -1278,8 +1282,11 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
} else {
if param.is_mut {
tok := param.specifier()
c.error('function `${node.name}` parameter `${param.name}` is `${tok}`, so use `${tok} ${call_arg.expr}` instead',
call_arg.expr.pos())
param_sym := c.table.sym(param.typ)
if !(param_sym.info is ast.Struct && param_sym.info.attrs.any(it.name == 'params')) {
c.error('function `${node.name}` parameter `${param.name}` is `${tok}`, so use `${tok} ${call_arg.expr}` instead',
call_arg.expr.pos())
}
} else {
c.fail_if_unreadable(call_arg.expr, arg_typ, 'argument')
}
Expand Down
7 changes: 7 additions & 0 deletions vlib/v/checker/tests/mut_parms_struct_param_err.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
vlib/v/checker/tests/mut_parms_struct_param_err.vv:8:17: error: declaring a mutable parameter that accepts a struct with the `@[params]` attribute is not allowed
6 | }
7 |
8 | fn foo(mut opts Params) bool {
| ~~~~~~
9 | return opts.a
10 | }
12 changes: 12 additions & 0 deletions vlib/v/checker/tests/mut_parms_struct_param_err.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@[params]
struct Params {
mut:
a bool
x int
}

fn foo(mut opts Params) bool {
return opts.a
}

foo(a: true)
24 changes: 10 additions & 14 deletions vlib/v/tests/struct_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ struct Lol {

struct User {
name string
age int
mut:
age int
}

struct Foo {
Expand Down Expand Up @@ -257,14 +258,12 @@ fn bar_config(c Config, def int) {
assert c.def == def
}

fn mut_bar_config(mut c Config, def int) &Config {
c.n = c.def
assert c.n == def
return unsafe { c }
}

fn foo_user(u User) {}

fn foo_mut_user(mut u User) {
u.age++
}

fn test_struct_literal_args() {
foo_config(20,
n: 10
Expand All @@ -277,17 +276,14 @@ fn test_struct_literal_args() {
bar_config(Config{}, 10)
bar_config(Config{ def: 4 }, 4)

mut c_ := Config{
def: 10
}
c := mut_bar_config(mut c_, 10)
assert c.n == 10
assert c.def == 10

foo_user(name: 'Peter')
foo_user(name: 'Peter')
foo_user(age: 7)
foo_user(name: 'Stew', age: 50)

mut user := User{'Stew', 50}
foo_mut_user(mut user)
assert user.age == 51
}

struct City {
Expand Down

0 comments on commit f0abc45

Please sign in to comment.