From 91799a17425ecfd6a0542377a44989035784530f Mon Sep 17 00:00:00 2001 From: Makhnev Petr <51853996+i582@users.noreply.github.com> Date: Tue, 24 Jan 2023 12:03:37 +0400 Subject: [PATCH] checker: add error for inc/dec for non lvalue (#17091) --- vlib/v/checker/checker.v | 25 -------------- vlib/v/checker/postfix.v | 41 +++++++++++++++++++++++ vlib/v/checker/tests/inc_dec_fun_call.out | 6 ++++ vlib/v/checker/tests/inc_dec_fun_call.vv | 5 +++ vlib/v/checker/tests/inc_num_literal.out | 4 +++ vlib/v/checker/tests/inc_num_literal.vv | 1 + vlib/v/checker/tests/inc_ok.out | 0 vlib/v/checker/tests/inc_ok.vv | 6 ++++ vlib/v/checker/tests/inc_paren_expr.out | 4 +++ vlib/v/checker/tests/inc_paren_expr.vv | 1 + 10 files changed, 68 insertions(+), 25 deletions(-) create mode 100644 vlib/v/checker/postfix.v create mode 100644 vlib/v/checker/tests/inc_dec_fun_call.out create mode 100644 vlib/v/checker/tests/inc_dec_fun_call.vv create mode 100644 vlib/v/checker/tests/inc_num_literal.out create mode 100644 vlib/v/checker/tests/inc_num_literal.vv create mode 100644 vlib/v/checker/tests/inc_ok.out create mode 100644 vlib/v/checker/tests/inc_ok.vv create mode 100644 vlib/v/checker/tests/inc_paren_expr.out create mode 100644 vlib/v/checker/tests/inc_paren_expr.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 988b9f7823..3f3f2878d7 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3565,31 +3565,6 @@ pub fn (mut c Checker) is_comptime_var(node ast.Expr) bool { && (node as ast.Ident).info is ast.IdentVar && (node as ast.Ident).kind == .variable && ((node as ast.Ident).obj as ast.Var).is_comptime_field } -fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type { - typ := c.unwrap_generic(c.expr(node.expr)) - typ_sym := c.table.sym(typ) - is_non_void_pointer := (typ.is_ptr() || typ.is_pointer()) && typ_sym.kind != .voidptr - if !c.inside_unsafe && is_non_void_pointer && !node.expr.is_auto_deref_var() { - c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos) - } - if !(typ_sym.is_number() || ((c.inside_unsafe || c.pref.translated) && is_non_void_pointer)) { - if c.inside_comptime_for_field { - if c.is_comptime_var(node.expr) { - return c.comptime_fields_default_type - } else if node.expr is ast.ComptimeSelector { - return c.comptime_fields_default_type - } - } - - typ_str := c.table.type_to_str(typ) - c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)', - node.pos) - } else { - node.auto_locked, _ = c.fail_if_immutable(node.expr) - } - return typ -} - fn (mut c Checker) mark_as_referenced(mut node ast.Expr, as_interface bool) { match mut node { ast.Ident { diff --git a/vlib/v/checker/postfix.v b/vlib/v/checker/postfix.v new file mode 100644 index 0000000000..85e5c82311 --- /dev/null +++ b/vlib/v/checker/postfix.v @@ -0,0 +1,41 @@ +module checker + +import v.ast + +fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type { + typ := c.unwrap_generic(c.expr(node.expr)) + typ_sym := c.table.sym(typ) + is_non_void_pointer := (typ.is_ptr() || typ.is_pointer()) && typ_sym.kind != .voidptr + + if node.op in [.inc, .dec] && !node.expr.is_lvalue() { + op_kind, bin_op_alt := if node.op == .inc { + 'increment', '+' + } else { + 'decrement', '-' + } + + c.add_error_detail('try rewrite this as `${node.expr} ${bin_op_alt} 1`') + c.error('cannot ${op_kind} `${node.expr}` because it is non lvalue expression', + node.expr.pos()) + } + + if !c.inside_unsafe && is_non_void_pointer && !node.expr.is_auto_deref_var() { + c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos) + } + if !(typ_sym.is_number() || ((c.inside_unsafe || c.pref.translated) && is_non_void_pointer)) { + if c.inside_comptime_for_field { + if c.is_comptime_var(node.expr) { + return c.comptime_fields_default_type + } else if node.expr is ast.ComptimeSelector { + return c.comptime_fields_default_type + } + } + + typ_str := c.table.type_to_str(typ) + c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)', + node.pos) + } else { + node.auto_locked, _ = c.fail_if_immutable(node.expr) + } + return typ +} diff --git a/vlib/v/checker/tests/inc_dec_fun_call.out b/vlib/v/checker/tests/inc_dec_fun_call.out new file mode 100644 index 0000000000..85760117a7 --- /dev/null +++ b/vlib/v/checker/tests/inc_dec_fun_call.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/inc_dec_fun_call.vv:5:1: error: cannot decrement `foo()` because it is non lvalue expression + 3 | } + 4 | + 5 | foo()-- + | ~~~~~ +Details: try rewrite this as `foo() - 1` \ No newline at end of file diff --git a/vlib/v/checker/tests/inc_dec_fun_call.vv b/vlib/v/checker/tests/inc_dec_fun_call.vv new file mode 100644 index 0000000000..666842debc --- /dev/null +++ b/vlib/v/checker/tests/inc_dec_fun_call.vv @@ -0,0 +1,5 @@ +fn foo() int { + return 100 +} + +foo()-- diff --git a/vlib/v/checker/tests/inc_num_literal.out b/vlib/v/checker/tests/inc_num_literal.out new file mode 100644 index 0000000000..c7a703b506 --- /dev/null +++ b/vlib/v/checker/tests/inc_num_literal.out @@ -0,0 +1,4 @@ +vlib/v/checker/tests/inc_num_literal.vv:1:1: error: cannot increment `100` because it is non lvalue expression + 1 | 100++ + | ~~~ +Details: try rewrite this as `100 + 1` \ No newline at end of file diff --git a/vlib/v/checker/tests/inc_num_literal.vv b/vlib/v/checker/tests/inc_num_literal.vv new file mode 100644 index 0000000000..cd31b8fde5 --- /dev/null +++ b/vlib/v/checker/tests/inc_num_literal.vv @@ -0,0 +1 @@ +100++ diff --git a/vlib/v/checker/tests/inc_ok.out b/vlib/v/checker/tests/inc_ok.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vlib/v/checker/tests/inc_ok.vv b/vlib/v/checker/tests/inc_ok.vv new file mode 100644 index 0000000000..be29163cea --- /dev/null +++ b/vlib/v/checker/tests/inc_ok.vv @@ -0,0 +1,6 @@ +mut mp := map[string]int{} +mut val := 100 + +(val)++ +val++ +mp["100"]++ diff --git a/vlib/v/checker/tests/inc_paren_expr.out b/vlib/v/checker/tests/inc_paren_expr.out new file mode 100644 index 0000000000..8272e8839e --- /dev/null +++ b/vlib/v/checker/tests/inc_paren_expr.out @@ -0,0 +1,4 @@ +vlib/v/checker/tests/inc_paren_expr.vv:1:1: error: cannot increment `(100 * 10)` because it is non lvalue expression + 1 | (100 * 10)++ + | ~~~~~~~~~~ +Details: try rewrite this as `(100 * 10) + 1` \ No newline at end of file diff --git a/vlib/v/checker/tests/inc_paren_expr.vv b/vlib/v/checker/tests/inc_paren_expr.vv new file mode 100644 index 0000000000..b1a4ff9197 --- /dev/null +++ b/vlib/v/checker/tests/inc_paren_expr.vv @@ -0,0 +1 @@ +(100 * 10)++