From 5ee3fecf60417a9b309bf6772c98831345683d70 Mon Sep 17 00:00:00 2001 From: yuyi Date: Sat, 23 Jan 2021 17:40:17 +0800 Subject: [PATCH] checker: check for mut val in immutable obj (#8285) --- cmd/tools/vtest-all.v | 64 +++++++++----------- vlib/v/checker/checker.v | 20 ++++++ vlib/v/checker/tests/for_in_mut_val_type.out | 42 +++++++++++++ vlib/v/checker/tests/for_in_mut_val_type.vv | 23 +++++++ 4 files changed, 115 insertions(+), 34 deletions(-) create mode 100644 vlib/v/checker/tests/for_in_mut_val_type.out create mode 100644 vlib/v/checker/tests/for_in_mut_val_type.vv diff --git a/cmd/tools/vtest-all.v b/cmd/tools/vtest-all.v index ae56b6d70a..4955d903e2 100644 --- a/cmd/tools/vtest-all.v +++ b/cmd/tools/vtest-all.v @@ -4,17 +4,38 @@ import os import term import time -const vexe = os.getenv('VEXE') - -const vroot = os.dir(vexe) - -const args_string = os.args[1..].join(' ') - -const vargs = args_string.all_before('test-all') +const ( + vexe = os.getenv('VEXE') + vroot = os.dir(vexe) + args_string = os.args[1..].join(' ') + vargs = args_string.all_before('test-all') +) fn main() { - commands := get_all_commands() - commands.summary() + mut commands := get_all_commands() + // summary + sw := time.new_stopwatch({}) + for mut cmd in commands { + cmd.run() + } + spent := sw.elapsed().milliseconds() + oks := commands.filter(it.ecode == 0) + fails := commands.filter(it.ecode != 0) + println('') + println(term.header(term.colorize(term.yellow, term.colorize(term.bold, 'Summary of `v test-all`:')), + '-')) + println(term.colorize(term.yellow, 'Total runtime: $spent ms')) + for ocmd in oks { + msg := if ocmd.okmsg != '' { ocmd.okmsg } else { ocmd.line } + println(term.colorize(term.green, '> OK: $msg ')) + } + for fcmd in fails { + msg := if fcmd.errmsg != '' { fcmd.errmsg } else { fcmd.line } + println(term.colorize(term.red, '> Failed: $msg ')) + } + if fails.len > 0 { + exit(1) + } } struct Command { @@ -80,28 +101,3 @@ fn (mut cmd Command) run() { println(term.colorize(term.yellow, '> Running: "$cmd.line" took: $spent ms.')) println('') } - -fn (commands []Command) summary() { - sw := time.new_stopwatch({}) - for mut cmd in commands { - cmd.run() - } - spent := sw.elapsed().milliseconds() - oks := commands.filter(it.ecode == 0) - fails := commands.filter(it.ecode != 0) - println('') - println(term.header(term.colorize(term.yellow, term.colorize(term.bold, 'Summary of `v test-all`:')), - '-')) - println(term.colorize(term.yellow, 'Total runtime: $spent ms')) - for ocmd in oks { - msg := if ocmd.okmsg != '' { ocmd.okmsg } else { ocmd.line } - println(term.colorize(term.green, '> OK: $msg ')) - } - for fcmd in fails { - msg := if fcmd.errmsg != '' { fcmd.errmsg } else { fcmd.line } - println(term.colorize(term.red, '> Failed: $msg ')) - } - if fails.len > 0 { - exit(1) - } -} diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 433d4bf3bf..96aa8185a2 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3079,6 +3079,26 @@ fn (mut c Checker) stmt(node ast.Stmt) { } if node.val_is_mut { value_type = value_type.to_ptr() + match node.cond { + ast.Ident { + if node.cond.obj is ast.Var { + obj := node.cond.obj as ast.Var + if !obj.is_mut { + c.error('`$obj.name` is immutable, it cannot be changed', + node.cond.pos) + } + } + } + ast.ArrayInit { + c.error('array literal is immutable, it cannot be changed', + node.cond.pos) + } + ast.MapInit { + c.error('map literal is immutable, it cannot be changed', + node.cond.pos) + } + else {} + } } node.cond_type = typ node.kind = sym.kind diff --git a/vlib/v/checker/tests/for_in_mut_val_type.out b/vlib/v/checker/tests/for_in_mut_val_type.out new file mode 100644 index 0000000000..da7eb715fc --- /dev/null +++ b/vlib/v/checker/tests/for_in_mut_val_type.out @@ -0,0 +1,42 @@ +vlib/v/checker/tests/for_in_mut_val_type.vv:3:15: error: `a1` is immutable, it cannot be changed + 1 | fn main() { + 2 | a1 := [1, 2, 3] + 3 | for mut j in a1 { + | ~~ + 4 | j *= 2 + 5 | } +vlib/v/checker/tests/for_in_mut_val_type.vv:7:15: error: `a2` is immutable, it cannot be changed + 5 | } + 6 | a2 := [1, 2, 3]! + 7 | for mut j in a2 { + | ~~ + 8 | j *= 2 + 9 | } +vlib/v/checker/tests/for_in_mut_val_type.vv:11:18: error: `m` is immutable, it cannot be changed + 9 | } + 10 | m := {'aa': 1, 'bb': 2} + 11 | for _, mut j in m { + | ^ + 12 | j *= 2 + 13 | } +vlib/v/checker/tests/for_in_mut_val_type.vv:14:15: error: array literal is immutable, it cannot be changed + 12 | j *= 2 + 13 | } + 14 | for mut j in [1, 2, 3] { + | ~~~~~~~~~ + 15 | j *= 2 + 16 | } +vlib/v/checker/tests/for_in_mut_val_type.vv:17:15: error: array literal is immutable, it cannot be changed + 15 | j *= 2 + 16 | } + 17 | for mut j in [1, 2, 3]! { + | ~~~~~~~~~~ + 18 | j *= 2 + 19 | } +vlib/v/checker/tests/for_in_mut_val_type.vv:20:19: error: map literal is immutable, it cannot be changed + 18 | j *= 2 + 19 | } + 20 | for _, mut j in {'aa': 1, 'bb': 2} { + | ~~~~ + 21 | j *= 2 + 22 | } diff --git a/vlib/v/checker/tests/for_in_mut_val_type.vv b/vlib/v/checker/tests/for_in_mut_val_type.vv new file mode 100644 index 0000000000..afd714bdf5 --- /dev/null +++ b/vlib/v/checker/tests/for_in_mut_val_type.vv @@ -0,0 +1,23 @@ +fn main() { + a1 := [1, 2, 3] + for mut j in a1 { + j *= 2 + } + a2 := [1, 2, 3]! + for mut j in a2 { + j *= 2 + } + m := {'aa': 1, 'bb': 2} + for _, mut j in m { + j *= 2 + } + for mut j in [1, 2, 3] { + j *= 2 + } + for mut j in [1, 2, 3]! { + j *= 2 + } + for _, mut j in {'aa': 1, 'bb': 2} { + j *= 2 + } +}