mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: check if mut function arg is declared as mut (#5579)
This commit is contained in:
parent
8d7eccb8e1
commit
8a46911725
@ -155,7 +155,7 @@ fn (mut cfg DocConfig) serve_html() {
|
|||||||
default_filename: def_name
|
default_filename: def_name
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
con := server.accept() or {
|
mut con := server.accept() or {
|
||||||
server.close() or { }
|
server.close() or { }
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ pub const (
|
|||||||
|
|
||||||
// A cipher is an instance of AES encryption using a particular key.
|
// A cipher is an instance of AES encryption using a particular key.
|
||||||
struct AesCipher {
|
struct AesCipher {
|
||||||
|
mut:
|
||||||
enc []u32
|
enc []u32
|
||||||
dec []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) 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 {
|
if src.len < block_size {
|
||||||
panic('crypto.aes: input not full block')
|
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')
|
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]) {
|
if subtle.inexact_overlap((*dst)[..block_size], (*src)[..block_size]) {
|
||||||
panic('crypto.aes: invalid buffer overlap')
|
panic('crypto.aes: invalid buffer overlap')
|
||||||
}
|
}
|
||||||
// for now use generic version
|
// 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 {
|
if src.len < block_size {
|
||||||
panic('crypto.aes: input not full block')
|
panic('crypto.aes: input not full block')
|
||||||
}
|
}
|
||||||
if dst.len < block_size {
|
if dst.len < block_size {
|
||||||
panic('crypto.aes: output not full block')
|
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')
|
panic('crypto.aes: invalid buffer overlap')
|
||||||
}
|
}
|
||||||
// for now use generic version
|
// 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 {
|
if dst.len < src.len {
|
||||||
panic('crypto.cipher: output smaller than input')
|
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')
|
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 {
|
for src.len > 0 {
|
||||||
// Write the xor to dst, then encrypt in place.
|
// Write the xor to dst, then encrypt in place.
|
||||||
cipher.xor_bytes(mut (*dst)[..x.block_size], src[..x.block_size], iv)
|
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.
|
// Move to the next block with this block as the next iv.
|
||||||
iv = (*dst)[..x.block_size]
|
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.
|
// Loop over all but the first block.
|
||||||
for start > 0 {
|
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))
|
cipher.xor_bytes(mut (*dst).slice(start, end), (*dst).slice(start, end), src.slice(prev, start))
|
||||||
|
|
||||||
end = 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.
|
// 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)
|
cipher.xor_bytes(mut (*dst).slice(start, end), (*dst).slice(start, end), x.iv)
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ module aes
|
|||||||
import encoding.binary
|
import encoding.binary
|
||||||
|
|
||||||
// Encrypt one block from src into dst, using the expanded key xk.
|
// 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
|
_ = src[15] // early bounds check
|
||||||
mut s0 := binary.big_endian_u32(src[..4])
|
mut s0 := binary.big_endian_u32(src[..4])
|
||||||
mut s1 := binary.big_endian_u32(src.slice(4, 8))
|
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]
|
s3 ^= xk[k+3]
|
||||||
|
|
||||||
_ := dst[15] // early bounds check
|
_ := dst[15] // early bounds check
|
||||||
binary.big_endian_put_u32(mut dst[..4], s0)
|
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(4, 8), s1)
|
||||||
binary.big_endian_put_u32(mut dst.slice(8, 12), s2)
|
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).slice(12, 16), s3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt one block from src into dst, using the expanded key xk.
|
// 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
|
_ = 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 s1 := binary.big_endian_u32(src.slice(4, 8))
|
||||||
mut s2 := binary.big_endian_u32(src.slice(8, 12))
|
mut s2 := binary.big_endian_u32(src.slice(8, 12))
|
||||||
mut s3 := binary.big_endian_u32(src.slice(12, 16))
|
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]
|
s3 ^= xk[k+3]
|
||||||
|
|
||||||
_ = dst[15] // early bounds check
|
_ = dst[15] // early bounds check
|
||||||
binary.big_endian_put_u32(mut dst[..4], s0)
|
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(4, 8), s1)
|
||||||
binary.big_endian_put_u32(mut dst.slice(8, 12), s2)
|
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).slice(12, 16), s3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply s_box0 to each byte in w.
|
// Apply s_box0 to each byte in w.
|
||||||
|
@ -117,7 +117,7 @@ pub fn (mut d Digest) checksum() []byte {
|
|||||||
panic('d.nx != 0')
|
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, d.s[0])
|
||||||
binary.little_endian_put_u32(mut digest[4..], d.s[1])
|
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.
|
// 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.
|
// 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 {
|
if src.len == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ fn (mut d Digest) checksum() []byte {
|
|||||||
panic('d.nx != 0')
|
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, d.h[0])
|
||||||
binary.big_endian_put_u32(mut digest[4..], d.h[1])
|
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 {
|
else {
|
||||||
c.error('unexpected expression `${typeof(expr)}`', expr.position())
|
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',
|
c.error('when forwarding a varg variable, it must be the final argument',
|
||||||
call_expr.pos)
|
call_expr.pos)
|
||||||
}
|
}
|
||||||
if arg.is_mut && !call_arg.is_mut {
|
if call_arg.is_mut {
|
||||||
c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`',
|
c.fail_if_immutable(call_arg.expr)
|
||||||
call_arg.expr.position())
|
if !arg.is_mut {
|
||||||
} 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())
|
||||||
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
|
// Handle expected interface
|
||||||
if arg_typ_sym.kind == .interface_ {
|
if arg_typ_sym.kind == .interface_ {
|
||||||
|
6
vlib/v/checker/tests/immutable_arg.out
Normal file
6
vlib/v/checker/tests/immutable_arg.out
Normal file
@ -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 | }
|
14
vlib/v/checker/tests/immutable_arg.vv
Normal file
14
vlib/v/checker/tests/immutable_arg.vv
Normal file
@ -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)
|
||||||
|
}
|
6
vlib/v/checker/tests/immutable_rec.out
Normal file
6
vlib/v/checker/tests/immutable_rec.out
Normal file
@ -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 | }
|
14
vlib/v/checker/tests/immutable_rec.vv
Normal file
14
vlib/v/checker/tests/immutable_rec.vv
Normal file
@ -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() {
|
fn test_create() {
|
||||||
create<User>()
|
create<User>()
|
||||||
create<City>()
|
create<City>()
|
||||||
u := User{}
|
mut u := User{}
|
||||||
mut_arg<User>(mut u)
|
mut_arg<User>(mut u)
|
||||||
mut_arg2<User>(mut u)
|
mut_arg2<User>(mut u)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user