mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
checker: disallow structs with @[params]
attribute as mutable function parameters (#21206)
This commit is contained in:
parent
206441c9df
commit
f0abc452fa
4 changed files with 38 additions and 16 deletions
|
@ -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 {
|
||||
|
@ -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')
|
||||
}
|
||||
|
|
7
vlib/v/checker/tests/mut_parms_struct_param_err.out
Normal file
7
vlib/v/checker/tests/mut_parms_struct_param_err.out
Normal file
|
@ -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
vlib/v/checker/tests/mut_parms_struct_param_err.vv
Normal file
12
vlib/v/checker/tests/mut_parms_struct_param_err.vv
Normal file
|
@ -0,0 +1,12 @@
|
|||
@[params]
|
||||
struct Params {
|
||||
mut:
|
||||
a bool
|
||||
x int
|
||||
}
|
||||
|
||||
fn foo(mut opts Params) bool {
|
||||
return opts.a
|
||||
}
|
||||
|
||||
foo(a: true)
|
|
@ -25,7 +25,8 @@ struct Lol {
|
|||
|
||||
struct User {
|
||||
name string
|
||||
age int
|
||||
mut:
|
||||
age int
|
||||
}
|
||||
|
||||
struct Foo {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue