From 7bf873177805746127339c17905353f07dd16c3b Mon Sep 17 00:00:00 2001 From: Enzo Baldisserri Date: Tue, 28 Apr 2020 11:20:19 +0200 Subject: [PATCH] checker: check variable mutability for postfix exprs --- vlib/bitfield/bitfield.v | 5 ----- vlib/strings/builder_test.v | 6 +++--- vlib/v/checker/checker.v | 14 ++++---------- vlib/v/checker/tests/division_by_zero_err.v | 3 +++ vlib/v/checker/tests/immutable_field_postfix.out | 13 +++++++++++++ vlib/v/checker/tests/immutable_field_postfix.v | 9 +++++++++ vlib/v/checker/tests/immutable_field_postfix.vv | 9 +++++++++ vlib/v/checker/tests/immutable_map_postfix.out | 13 +++++++++++++ vlib/v/checker/tests/immutable_map_postfix.v | 5 +++++ vlib/v/checker/tests/immutable_map_postfix.vv | 5 +++++ vlib/v/checker/tests/immutable_struct_postfix.out | 13 +++++++++++++ vlib/v/checker/tests/immutable_struct_postfix.v | 10 ++++++++++ vlib/v/checker/tests/immutable_struct_postfix.vv | 10 ++++++++++ vlib/v/checker/tests/immutable_var_postfix.out | 13 +++++++++++++ vlib/v/checker/tests/immutable_var_postfix.v | 5 +++++ vlib/v/checker/tests/immutable_var_postfix.vv | 5 +++++ 16 files changed, 120 insertions(+), 18 deletions(-) create mode 100644 vlib/v/checker/tests/division_by_zero_err.v create mode 100644 vlib/v/checker/tests/immutable_field_postfix.out create mode 100644 vlib/v/checker/tests/immutable_field_postfix.v create mode 100644 vlib/v/checker/tests/immutable_field_postfix.vv create mode 100644 vlib/v/checker/tests/immutable_map_postfix.out create mode 100644 vlib/v/checker/tests/immutable_map_postfix.v create mode 100644 vlib/v/checker/tests/immutable_map_postfix.vv create mode 100644 vlib/v/checker/tests/immutable_struct_postfix.out create mode 100644 vlib/v/checker/tests/immutable_struct_postfix.v create mode 100644 vlib/v/checker/tests/immutable_struct_postfix.vv create mode 100644 vlib/v/checker/tests/immutable_var_postfix.out create mode 100644 vlib/v/checker/tests/immutable_var_postfix.v create mode 100644 vlib/v/checker/tests/immutable_var_postfix.vv diff --git a/vlib/bitfield/bitfield.v b/vlib/bitfield/bitfield.v index 2d63a0a229..9e4d135692 100644 --- a/vlib/bitfield/bitfield.v +++ b/vlib/bitfield/bitfield.v @@ -136,7 +136,6 @@ pub fn bfand(input1 BitField, input2 BitField) BitField { mut output := new(size) for i in 0..bitnslots { output.field[i] = input1.field[i] & input2.field[i] - i++ } output.cleartail() return output @@ -149,7 +148,6 @@ pub fn bfnot(input BitField) BitField { mut output := new(size) for i in 0..bitnslots { output.field[i] = ~input.field[i] - i++ } output.cleartail() return output @@ -164,7 +162,6 @@ pub fn bfor(input1 BitField, input2 BitField) BitField { mut output := new(size) for i in 0..bitnslots { output.field[i] = input1.field[i] | input2.field[i] - i++ } output.cleartail() return output @@ -179,7 +176,6 @@ pub fn bfxor(input1 BitField, input2 BitField) BitField { mut output := new(size) for i in 0..bitnslots { output.field[i] = input1.field[i] ^ input2.field[i] - i++ } output.cleartail() return output @@ -241,7 +237,6 @@ pub fn (instance BitField) clone() BitField { mut output := new(instance.size) for i in 0..bitnslots { output.field[i] = instance.field[i] - i++ } return output } diff --git a/vlib/strings/builder_test.v b/vlib/strings/builder_test.v index 0e48a01574..2f66fd401b 100644 --- a/vlib/strings/builder_test.v +++ b/vlib/strings/builder_test.v @@ -5,14 +5,14 @@ fn test_sb() { sb.write('hi') sb.write('!') sb.write('hello') - assert sb.str() == 'hi!hello' assert sb.len == 8 + assert sb.str() == 'hi!hello' + assert sb.len == 0 sb = strings.new_builder(10) sb.write('a') sb.write('b') - println(sb.str()) - assert sb.str() == 'ab' assert sb.len == 2 + assert sb.str() == 'ab' } const ( diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b4d8fb99b1..7877ec2b45 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -484,11 +484,11 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) { // TODO Remove `crypto.rand` when possible (see vlib/crypto/rand/rand.v, // if `c_array_to_bytes_tmp` doesn't exist, then it's safe to remove it) if c.file.mod.name !in ['builtin', 'crypto.rand'] { - c.error('`$typ_sym.kind` can not be modified', expr.position()) + c.error('`$typ_sym.kind` can not be modified', it.pos) } } else { - c.error('unexpected symbol `${typ_sym.kind}`', expr.position()) + c.error('unexpected symbol `${typ_sym.kind}`', it.pos) } } } @@ -1802,20 +1802,14 @@ pub fn (mut c Checker) if_expr(node mut ast.IfExpr) table.Type { } pub fn (mut c Checker) postfix_expr(node ast.PostfixExpr) table.Type { - /* - match node.expr { - ast.IdentVar { - println('postfix identvar') - } - else {} - } - */ typ := c.expr(node.expr) typ_sym := c.table.get_type_symbol(typ) // if !typ.is_number() { if !typ_sym.is_number() { println(typ_sym.kind.str()) c.error('invalid operation: $node.op.str() (non-numeric type `$typ_sym.name`)', node.pos) + } else { + c.fail_if_immutable(node.expr) } return typ } diff --git a/vlib/v/checker/tests/division_by_zero_err.v b/vlib/v/checker/tests/division_by_zero_err.v new file mode 100644 index 0000000000..996814a9a6 --- /dev/null +++ b/vlib/v/checker/tests/division_by_zero_err.v @@ -0,0 +1,3 @@ +fn main() { + println(1/0) +} diff --git a/vlib/v/checker/tests/immutable_field_postfix.out b/vlib/v/checker/tests/immutable_field_postfix.out new file mode 100644 index 0000000000..c4688fa688 --- /dev/null +++ b/vlib/v/checker/tests/immutable_field_postfix.out @@ -0,0 +1,13 @@ +vlib/v/checker/tests/immutable_field_postfix.v:7:4: error: field `i` of struct `A` is immutable + 5| fn main() { + 6| mut a := A{} + 7| a.i++ + ^ + 8| a.i-- + 9| } +vlib/v/checker/tests/immutable_field_postfix.v:8:4: error: field `i` of struct `A` is immutable + 6| mut a := A{} + 7| a.i++ + 8| a.i-- + ^ + 9| } diff --git a/vlib/v/checker/tests/immutable_field_postfix.v b/vlib/v/checker/tests/immutable_field_postfix.v new file mode 100644 index 0000000000..2dade72e4a --- /dev/null +++ b/vlib/v/checker/tests/immutable_field_postfix.v @@ -0,0 +1,9 @@ +struct A { + i int +} + +fn main() { + mut a := A{} + a.i++ + a.i-- +} diff --git a/vlib/v/checker/tests/immutable_field_postfix.vv b/vlib/v/checker/tests/immutable_field_postfix.vv new file mode 100644 index 0000000000..2dade72e4a --- /dev/null +++ b/vlib/v/checker/tests/immutable_field_postfix.vv @@ -0,0 +1,9 @@ +struct A { + i int +} + +fn main() { + mut a := A{} + a.i++ + a.i-- +} diff --git a/vlib/v/checker/tests/immutable_map_postfix.out b/vlib/v/checker/tests/immutable_map_postfix.out new file mode 100644 index 0000000000..51a80730b6 --- /dev/null +++ b/vlib/v/checker/tests/immutable_map_postfix.out @@ -0,0 +1,13 @@ +vlib/v/checker/tests/immutable_map_postfix.v:3:2: error: `m` is immutable, declare it with `mut` to make it mutable + 1| fn main() { + 2| m := map[string]int + 3| m['test']++ + ^ + 4| m['test']-- + 5| } +vlib/v/checker/tests/immutable_map_postfix.v:4:2: error: `m` is immutable, declare it with `mut` to make it mutable + 2| m := map[string]int + 3| m['test']++ + 4| m['test']-- + ^ + 5| } diff --git a/vlib/v/checker/tests/immutable_map_postfix.v b/vlib/v/checker/tests/immutable_map_postfix.v new file mode 100644 index 0000000000..13a4a503c6 --- /dev/null +++ b/vlib/v/checker/tests/immutable_map_postfix.v @@ -0,0 +1,5 @@ +fn main() { + m := map[string]int + m['test']++ + m['test']-- +} diff --git a/vlib/v/checker/tests/immutable_map_postfix.vv b/vlib/v/checker/tests/immutable_map_postfix.vv new file mode 100644 index 0000000000..13a4a503c6 --- /dev/null +++ b/vlib/v/checker/tests/immutable_map_postfix.vv @@ -0,0 +1,5 @@ +fn main() { + m := map[string]int + m['test']++ + m['test']-- +} diff --git a/vlib/v/checker/tests/immutable_struct_postfix.out b/vlib/v/checker/tests/immutable_struct_postfix.out new file mode 100644 index 0000000000..cbbb627f92 --- /dev/null +++ b/vlib/v/checker/tests/immutable_struct_postfix.out @@ -0,0 +1,13 @@ +vlib/v/checker/tests/immutable_struct_postfix.v:8:2: error: `a` is immutable, declare it with `mut` to make it mutable + 6| fn main() { + 7| a := A{} + 8| a.i++ + ^ + 9| a.i-- + 10| } +vlib/v/checker/tests/immutable_struct_postfix.v:9:2: error: `a` is immutable, declare it with `mut` to make it mutable + 7| a := A{} + 8| a.i++ + 9| a.i-- + ^ + 10| } diff --git a/vlib/v/checker/tests/immutable_struct_postfix.v b/vlib/v/checker/tests/immutable_struct_postfix.v new file mode 100644 index 0000000000..7bc4e31913 --- /dev/null +++ b/vlib/v/checker/tests/immutable_struct_postfix.v @@ -0,0 +1,10 @@ +struct A { +mut: + i int +} + +fn main() { + a := A{} + a.i++ + a.i-- +} diff --git a/vlib/v/checker/tests/immutable_struct_postfix.vv b/vlib/v/checker/tests/immutable_struct_postfix.vv new file mode 100644 index 0000000000..7bc4e31913 --- /dev/null +++ b/vlib/v/checker/tests/immutable_struct_postfix.vv @@ -0,0 +1,10 @@ +struct A { +mut: + i int +} + +fn main() { + a := A{} + a.i++ + a.i-- +} diff --git a/vlib/v/checker/tests/immutable_var_postfix.out b/vlib/v/checker/tests/immutable_var_postfix.out new file mode 100644 index 0000000000..dfb40426cb --- /dev/null +++ b/vlib/v/checker/tests/immutable_var_postfix.out @@ -0,0 +1,13 @@ +vlib/v/checker/tests/immutable_var_postfix.v:3:2: error: `a` is immutable, declare it with `mut` to make it mutable + 1| fn main() { + 2| a := 1 + 3| a++ + ^ + 4| a-- + 5| } +vlib/v/checker/tests/immutable_var_postfix.v:4:2: error: `a` is immutable, declare it with `mut` to make it mutable + 2| a := 1 + 3| a++ + 4| a-- + ^ + 5| } diff --git a/vlib/v/checker/tests/immutable_var_postfix.v b/vlib/v/checker/tests/immutable_var_postfix.v new file mode 100644 index 0000000000..ff1e94de55 --- /dev/null +++ b/vlib/v/checker/tests/immutable_var_postfix.v @@ -0,0 +1,5 @@ +fn main() { + a := 1 + a++ + a-- +} diff --git a/vlib/v/checker/tests/immutable_var_postfix.vv b/vlib/v/checker/tests/immutable_var_postfix.vv new file mode 100644 index 0000000000..ff1e94de55 --- /dev/null +++ b/vlib/v/checker/tests/immutable_var_postfix.vv @@ -0,0 +1,5 @@ +fn main() { + a := 1 + a++ + a-- +}