From 9db8a61b92c2b0d1c1b672880fd7a85d4e6ccfb0 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 12 Mar 2021 15:09:01 +0000 Subject: [PATCH] checker: disallow array append in an expression (#9265) --- vlib/v/ast/ast.v | 5 +++-- vlib/v/checker/check_types.v | 2 +- vlib/v/checker/checker.v | 3 +++ vlib/v/checker/tests/append_err.out | 20 +++++++++++++++++++ .../{left_shift_err.vv => append_err.vv} | 3 +++ .../tests/array_literal_modify_err.out | 4 ++-- vlib/v/checker/tests/left_shift_err.out | 6 ------ .../tests/rshift_op_wrong_left_type_err.out | 2 +- .../tests/shift_op_wrong_left_type_err.out | 2 +- vlib/v/parser/pratt.v | 2 ++ 10 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 vlib/v/checker/tests/append_err.out rename vlib/v/checker/tests/{left_shift_err.vv => append_err.vv} (58%) delete mode 100644 vlib/v/checker/tests/left_shift_err.out diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index f38dd598ba..be4f34ac28 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -579,8 +579,9 @@ pub fn (i &Ident) var_info() IdentVar { // See: token.Kind.is_infix pub struct InfixExpr { pub: - op token.Kind - pos token.Position + op token.Kind + pos token.Position + is_stmt bool pub mut: left Expr right Expr diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 4939d1819a..49671c377e 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -155,7 +155,7 @@ fn (mut c Checker) check_shift(left_type table.Type, right_type table.Type, left // allow `bool << 2` in translated C code return table.int_type } - c.error('invalid operation: shift of type `$sym.name`', left_pos) + c.error('invalid operation: shift on type `$sym.name`', left_pos) return table.void_type } else if !right_type.is_int() { c.error('cannot shift non-integer type `${c.table.get_type_symbol(right_type).name}` into type `${c.table.get_type_symbol(left_type).name}`', diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index fd4bdd94d8..af472ebf25 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -875,6 +875,9 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type { } .left_shift { if left_final.kind == .array { + if !infix_expr.is_stmt { + c.error('array append cannot be used in an expression', infix_expr.pos) + } // `array << elm` infix_expr.auto_locked, _ = c.fail_if_immutable(infix_expr.left) left_value_type := c.table.value_type(left_type) diff --git a/vlib/v/checker/tests/append_err.out b/vlib/v/checker/tests/append_err.out new file mode 100644 index 0000000000..4c87f24ef2 --- /dev/null +++ b/vlib/v/checker/tests/append_err.out @@ -0,0 +1,20 @@ +vlib/v/checker/tests/append_err.vv:3:7: error: cannot append `string` to `[]int` + 1 | fn main() { + 2 | mut l := []int{} + 3 | l << 'test' + | ~~~~~~ + 4 | + 5 | _ = l << 3 +vlib/v/checker/tests/append_err.vv:5:8: error: array append cannot be used in an expression + 3 | l << 'test' + 4 | + 5 | _ = l << 3 + | ~~ + 6 | _ = (l << 3).len + 7 | } +vlib/v/checker/tests/append_err.vv:6:9: error: array append cannot be used in an expression + 4 | + 5 | _ = l << 3 + 6 | _ = (l << 3).len + | ~~ + 7 | } diff --git a/vlib/v/checker/tests/left_shift_err.vv b/vlib/v/checker/tests/append_err.vv similarity index 58% rename from vlib/v/checker/tests/left_shift_err.vv rename to vlib/v/checker/tests/append_err.vv index 52c6ea7191..bc506b64a2 100644 --- a/vlib/v/checker/tests/left_shift_err.vv +++ b/vlib/v/checker/tests/append_err.vv @@ -1,4 +1,7 @@ fn main() { mut l := []int{} l << 'test' + + _ = l << 3 + _ = (l << 3).len } diff --git a/vlib/v/checker/tests/array_literal_modify_err.out b/vlib/v/checker/tests/array_literal_modify_err.out index 7c8d8ebed5..eaec4f986f 100644 --- a/vlib/v/checker/tests/array_literal_modify_err.out +++ b/vlib/v/checker/tests/array_literal_modify_err.out @@ -1,7 +1,7 @@ -vlib/v/checker/tests/array_literal_modify_err.vv:2:14: error: array literal can not be modified +vlib/v/checker/tests/array_literal_modify_err.vv:2:24: error: array append cannot be used in an expression 1 | fn main() { 2 | mut nums := [1, 2, 3] << 4 - | ~~~~~~~~~ + | ~~ 3 | println(nums) 4 | } vlib/v/checker/tests/array_literal_modify_err.vv:3:2: error: `println` can not print void expressions diff --git a/vlib/v/checker/tests/left_shift_err.out b/vlib/v/checker/tests/left_shift_err.out deleted file mode 100644 index 8ca85c221b..0000000000 --- a/vlib/v/checker/tests/left_shift_err.out +++ /dev/null @@ -1,6 +0,0 @@ -vlib/v/checker/tests/left_shift_err.vv:3:7: error: cannot append `string` to `[]int` - 1 | fn main() { - 2 | mut l := []int{} - 3 | l << 'test' - | ~~~~~~ - 4 | } diff --git a/vlib/v/checker/tests/rshift_op_wrong_left_type_err.out b/vlib/v/checker/tests/rshift_op_wrong_left_type_err.out index 35daa5f408..60866d5051 100644 --- a/vlib/v/checker/tests/rshift_op_wrong_left_type_err.out +++ b/vlib/v/checker/tests/rshift_op_wrong_left_type_err.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/rshift_op_wrong_left_type_err.vv:2:10: error: invalid operation: shift of type `float literal` +vlib/v/checker/tests/rshift_op_wrong_left_type_err.vv:2:10: error: invalid operation: shift on type `float literal` 1 | fn main() { 2 | println(0.5 >> 1) | ~~~ diff --git a/vlib/v/checker/tests/shift_op_wrong_left_type_err.out b/vlib/v/checker/tests/shift_op_wrong_left_type_err.out index f9dcdf76f6..1bdeb5e2e2 100644 --- a/vlib/v/checker/tests/shift_op_wrong_left_type_err.out +++ b/vlib/v/checker/tests/shift_op_wrong_left_type_err.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/shift_op_wrong_left_type_err.vv:2:10: error: invalid operation: shift of type `float literal` +vlib/v/checker/tests/shift_op_wrong_left_type_err.vv:2:10: error: invalid operation: shift on type `float literal` 1 | fn main() { 2 | println(0.5 << 1) | ~~~ diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index f1ccf4dba1..9adb5ac5c3 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -377,6 +377,7 @@ pub fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_iden right: right op: tok.kind pos: pos + is_stmt: true } } else if p.tok.kind.is_infix() { if p.tok.kind.is_prefix() && p.tok.line_nr != p.prev_tok.line_nr { @@ -473,6 +474,7 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr { right: right op: op pos: pos + is_stmt: p.is_stmt_ident or_block: ast.OrExpr{ stmts: or_stmts kind: or_kind