checker: check if mut function arg is declared as mut (#5579)
parent
8d7eccb8e1
commit
8a46911725
|
@ -155,7 +155,7 @@ fn (mut cfg DocConfig) serve_html() {
|
|||
default_filename: def_name
|
||||
}
|
||||
for {
|
||||
con := server.accept() or {
|
||||
mut con := server.accept() or {
|
||||
server.close() or { }
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ pub const (
|
|||
|
||||
// A cipher is an instance of AES encryption using a particular key.
|
||||
struct AesCipher {
|
||||
mut:
|
||||
enc []u32
|
||||
dec []u32
|
||||
}
|
||||
|
@ -40,7 +41,7 @@ pub fn new_cipher(key []byte) AesCipher {
|
|||
|
||||
pub fn (c &AesCipher) block_size() int { return block_size }
|
||||
|
||||
pub fn (c &AesCipher) encrypt(dst, src []byte) {
|
||||
pub fn (c &AesCipher) encrypt(mut dst []byte, mut src []byte) {
|
||||
if src.len < block_size {
|
||||
panic('crypto.aes: input not full block')
|
||||
}
|
||||
|
@ -48,23 +49,23 @@ pub fn (c &AesCipher) encrypt(dst, src []byte) {
|
|||
panic('crypto.aes: output not full block')
|
||||
}
|
||||
// if subtle.inexact_overlap(dst[:block_size], src[:block_size]) {
|
||||
if subtle.inexact_overlap(dst[..block_size], src[..block_size]) {
|
||||
if subtle.inexact_overlap((*dst)[..block_size], (*src)[..block_size]) {
|
||||
panic('crypto.aes: invalid buffer overlap')
|
||||
}
|
||||
// for now use generic version
|
||||
encrypt_block_generic(c.enc, dst, src)
|
||||
encrypt_block_generic(c.enc, mut dst, src)
|
||||
}
|
||||
|
||||
pub fn (c &AesCipher) decrypt(dst, src []byte) {
|
||||
pub fn (c &AesCipher) decrypt(mut dst []byte, mut src []byte) {
|
||||
if src.len < block_size {
|
||||
panic('crypto.aes: input not full block')
|
||||
}
|
||||
if dst.len < block_size {
|
||||
panic('crypto.aes: output not full block')
|
||||
}
|
||||
if subtle.inexact_overlap(dst[..block_size], src[..block_size]) {
|
||||
if subtle.inexact_overlap((*dst)[..block_size], (*src)[..block_size]) {
|
||||
panic('crypto.aes: invalid buffer overlap')
|
||||
}
|
||||
// for now use generic version
|
||||
decrypt_block_generic(c.dec, dst, src)
|
||||
decrypt_block_generic(c.dec, mut dst, src)
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ pub fn (x &AesCbc) encrypt_blocks(mut dst []byte, src_ []byte) {
|
|||
if dst.len < src.len {
|
||||
panic('crypto.cipher: output smaller than input')
|
||||
}
|
||||
if subtle.inexact_overlap((*dst)[..src.len], src) {
|
||||
if subtle.inexact_overlap((*dst)[..src.len], src_) {
|
||||
panic('crypto.cipher: invalid buffer overlap')
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ pub fn (x &AesCbc) encrypt_blocks(mut dst []byte, src_ []byte) {
|
|||
for src.len > 0 {
|
||||
// Write the xor to dst, then encrypt in place.
|
||||
cipher.xor_bytes(mut (*dst)[..x.block_size], src[..x.block_size], iv)
|
||||
x.b.encrypt((*dst)[..x.block_size], (*dst)[..x.block_size])
|
||||
x.b.encrypt(mut (*dst)[..x.block_size], mut (*dst)[..x.block_size])
|
||||
|
||||
// Move to the next block with this block as the next iv.
|
||||
iv = (*dst)[..x.block_size]
|
||||
|
@ -104,7 +104,7 @@ pub fn (mut x AesCbc) decrypt_blocks(mut dst []byte, src []byte) {
|
|||
|
||||
// Loop over all but the first block.
|
||||
for start > 0 {
|
||||
x.b.decrypt((*dst).slice(start, end), src.slice(start, end))
|
||||
x.b.decrypt(mut (*dst).slice(start, end), mut src.slice(start, end))
|
||||
cipher.xor_bytes(mut (*dst).slice(start, end), (*dst).slice(start, end), src.slice(prev, start))
|
||||
|
||||
end = start
|
||||
|
@ -113,7 +113,7 @@ pub fn (mut x AesCbc) decrypt_blocks(mut dst []byte, src []byte) {
|
|||
}
|
||||
|
||||
// The first block is special because it uses the saved iv.
|
||||
x.b.decrypt((*dst).slice(start, end), src.slice(start, end))
|
||||
x.b.decrypt(mut (*dst).slice(start, end), mut src.slice(start, end))
|
||||
cipher.xor_bytes(mut (*dst).slice(start, end), (*dst).slice(start, end), x.iv)
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ module aes
|
|||
import encoding.binary
|
||||
|
||||
// Encrypt one block from src into dst, using the expanded key xk.
|
||||
fn encrypt_block_generic(xk []u32, dst, src []byte) {
|
||||
fn encrypt_block_generic(xk []u32, mut dst []byte, src []byte) {
|
||||
_ = src[15] // early bounds check
|
||||
mut s0 := binary.big_endian_u32(src[..4])
|
||||
mut s1 := binary.big_endian_u32(src.slice(4, 8))
|
||||
|
@ -85,16 +85,16 @@ fn encrypt_block_generic(xk []u32, dst, src []byte) {
|
|||
s3 ^= xk[k+3]
|
||||
|
||||
_ := dst[15] // early bounds check
|
||||
binary.big_endian_put_u32(mut dst[..4], s0)
|
||||
binary.big_endian_put_u32(mut dst.slice(4, 8), s1)
|
||||
binary.big_endian_put_u32(mut dst.slice(8, 12), s2)
|
||||
binary.big_endian_put_u32(mut dst.slice(12, 16), s3)
|
||||
binary.big_endian_put_u32(mut (*dst)[0..4], s0)
|
||||
binary.big_endian_put_u32(mut (*dst).slice(4, 8), s1)
|
||||
binary.big_endian_put_u32(mut (*dst).slice(8, 12), s2)
|
||||
binary.big_endian_put_u32(mut (*dst).slice(12, 16), s3)
|
||||
}
|
||||
|
||||
// Decrypt one block from src into dst, using the expanded key xk.
|
||||
fn decrypt_block_generic(xk []u32, dst, src []byte) {
|
||||
fn decrypt_block_generic(xk []u32, mut dst []byte, src []byte) {
|
||||
_ = src[15] // early bounds check
|
||||
mut s0 := binary.big_endian_u32(src[..4])
|
||||
mut s0 := binary.big_endian_u32(src[0..4])
|
||||
mut s1 := binary.big_endian_u32(src.slice(4, 8))
|
||||
mut s2 := binary.big_endian_u32(src.slice(8, 12))
|
||||
mut s3 := binary.big_endian_u32(src.slice(12, 16))
|
||||
|
@ -137,10 +137,10 @@ fn decrypt_block_generic(xk []u32, dst, src []byte) {
|
|||
s3 ^= xk[k+3]
|
||||
|
||||
_ = dst[15] // early bounds check
|
||||
binary.big_endian_put_u32(mut dst[..4], s0)
|
||||
binary.big_endian_put_u32(mut dst.slice(4, 8), s1)
|
||||
binary.big_endian_put_u32(mut dst.slice(8, 12), s2)
|
||||
binary.big_endian_put_u32(mut dst.slice(12, 16), s3)
|
||||
binary.big_endian_put_u32(mut (*dst)[..4], s0)
|
||||
binary.big_endian_put_u32(mut (*dst).slice(4, 8), s1)
|
||||
binary.big_endian_put_u32(mut (*dst).slice(8, 12), s2)
|
||||
binary.big_endian_put_u32(mut (*dst).slice(12, 16), s3)
|
||||
}
|
||||
|
||||
// Apply s_box0 to each byte in w.
|
||||
|
|
|
@ -117,7 +117,7 @@ pub fn (mut d Digest) checksum() []byte {
|
|||
panic('d.nx != 0')
|
||||
}
|
||||
|
||||
digest := []byte{len:(size)}
|
||||
mut digest := []byte{len:(size)}
|
||||
|
||||
binary.little_endian_put_u32(mut digest, d.s[0])
|
||||
binary.little_endian_put_u32(mut digest[4..], d.s[1])
|
||||
|
|
|
@ -59,7 +59,7 @@ pub fn (mut c Cipher) reset() {
|
|||
|
||||
// xor_key_stream sets dst to the result of XORing src with the key stream.
|
||||
// Dst and src must overlap entirely or not at all.
|
||||
pub fn (mut c Cipher) xor_key_stream(mut dst []byte, src []byte) {
|
||||
pub fn (mut c Cipher) xor_key_stream(mut dst, src []byte) {
|
||||
if src.len == 0 {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ fn (mut d Digest) checksum() []byte {
|
|||
panic('d.nx != 0')
|
||||
}
|
||||
|
||||
digest := []byte{len:(size)}
|
||||
mut digest := []byte{len:(size)}
|
||||
|
||||
binary.big_endian_put_u32(mut digest, d.h[0])
|
||||
binary.big_endian_put_u32(mut digest[4..], d.h[1])
|
||||
|
|
|
@ -690,6 +690,17 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) {
|
|||
}
|
||||
}
|
||||
}
|
||||
ast.CallExpr {
|
||||
// TODO: should only work for builtin method
|
||||
if expr.name == 'slice' {
|
||||
return
|
||||
} else {
|
||||
c.error('cannot use function call as mut', expr.pos)
|
||||
}
|
||||
}
|
||||
ast.ArrayInit {
|
||||
return
|
||||
}
|
||||
else {
|
||||
c.error('unexpected expression `${typeof(expr)}`', expr.position())
|
||||
}
|
||||
|
@ -1097,11 +1108,16 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
|||
c.error('when forwarding a varg variable, it must be the final argument',
|
||||
call_expr.pos)
|
||||
}
|
||||
if arg.is_mut && !call_arg.is_mut {
|
||||
c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`',
|
||||
call_arg.expr.position())
|
||||
} else if !arg.is_mut && call_arg.is_mut {
|
||||
c.error('`$arg.name` argument is not mutable, `mut` is not needed`', call_arg.expr.position())
|
||||
if call_arg.is_mut {
|
||||
c.fail_if_immutable(call_arg.expr)
|
||||
if !arg.is_mut {
|
||||
c.error('`$arg.name` argument is not mutable, `mut` is not needed`', call_arg.expr.position())
|
||||
}
|
||||
} else {
|
||||
if arg.is_mut {
|
||||
c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`',
|
||||
call_arg.expr.position())
|
||||
}
|
||||
}
|
||||
// Handle expected interface
|
||||
if arg_typ_sym.kind == .interface_ {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/immutable_arg.v:13:8: error: `a` is immutable, declare it with `mut` to make it mutable
|
||||
11 | fn main() {
|
||||
12 | a := St{e: 2}
|
||||
13 | f(mut a)
|
||||
| ^
|
||||
14 | }
|
|
@ -0,0 +1,14 @@
|
|||
struct St {
|
||||
mut:
|
||||
e int
|
||||
}
|
||||
|
||||
fn f(mut x St) {
|
||||
x.e++
|
||||
println(x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := St{e: 2}
|
||||
f(mut a)
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/immutable_rec.v:13:2: error: `a` is immutable, declare it with `mut` to make it mutable
|
||||
11 | fn main() {
|
||||
12 | a := St{e: 2}
|
||||
13 | a.f()
|
||||
| ^
|
||||
14 | }
|
|
@ -0,0 +1,14 @@
|
|||
struct St {
|
||||
mut:
|
||||
e int
|
||||
}
|
||||
|
||||
fn (mut x St) f() {
|
||||
x.e++
|
||||
println(x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := St{e: 2}
|
||||
a.f()
|
||||
}
|
|
@ -77,7 +77,7 @@ fn mut_arg2<T>(mut x T) T {
|
|||
fn test_create() {
|
||||
create<User>()
|
||||
create<City>()
|
||||
u := User{}
|
||||
mut u := User{}
|
||||
mut_arg<User>(mut u)
|
||||
mut_arg2<User>(mut u)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue