From 4b3c3d9082ddb50b29d068fcf42684a907392119 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 7 Jun 2022 18:33:08 +0300 Subject: [PATCH] checker: add error for `if c >= A && c <= Z {` in non generic functions --- vlib/v/checker/checker.v | 12 +++++++++++- vlib/v/checker/comptime.v | 4 +++- vlib/v/checker/for.v | 9 ++++++--- vlib/v/checker/infix.v | 7 +++++++ .../generic_type_name_in_non_generic_function.out | 7 +++++++ .../generic_type_name_in_non_generic_function.vv | 8 ++++++++ vlib/vweb/vweb.v | 2 +- 7 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 vlib/v/checker/tests/generic_type_name_in_non_generic_function.out create mode 100644 vlib/v/checker/tests/generic_type_name_in_non_generic_function.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 2a894b3a8c..e1d8300157 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -89,6 +89,7 @@ pub mut: inside_defer bool // true inside `defer {}` blocks inside_fn_arg bool // `a`, `b` in `a.f(b)` inside_ct_attr bool // true inside `[if expr]` + inside_x_is_type bool // true inside the Type expression of `if x is Type {` inside_comptime_for_field bool skip_flags bool // should `#flag` and `#include` be skipped fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc @@ -156,6 +157,7 @@ fn (mut c Checker) reset_checker_state_at_start_of_new_file() { c.inside_defer = false c.inside_fn_arg = false c.inside_ct_attr = false + c.inside_x_is_type = false c.skip_flags = false c.fn_level = 0 c.expr_level = 0 @@ -1605,9 +1607,10 @@ fn (mut c Checker) assert_stmt(node ast.AssertStmt) { fn (mut c Checker) block(node ast.Block) { if node.is_unsafe { + prev_unsafe := c.inside_unsafe c.inside_unsafe = true c.stmts(node.stmts) - c.inside_unsafe = false + c.inside_unsafe = prev_unsafe } else { c.stmts(node.stmts) } @@ -2021,7 +2024,9 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type { c.error('incorrect use of compile-time type', node.pos) } ast.EmptyExpr { + print_backtrace() c.error('checker.expr(): unhandled EmptyExpr', token.Pos{}) + return ast.void_type } ast.CTempVar { return node.typ @@ -2269,6 +2274,11 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type { return c.struct_init(mut node) } ast.TypeNode { + if !c.inside_x_is_type && node.typ.has_flag(.generic) && unsafe { c.table.cur_fn != 0 } + && c.table.cur_fn.generic_names.len == 0 { + c.error('unexpected generic variable in non-generic function `$c.table.cur_fn.name`', + node.pos) + } return node.typ } ast.TypeOf { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index d5ad6185d3..f44132e7d5 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -9,7 +9,9 @@ import v.util import v.pkgconfig fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { - node.left_type = c.expr(node.left) + if node.left !is ast.EmptyExpr { + node.left_type = c.expr(node.left) + } if node.method_name == 'compile_error' { c.error(node.args_var, node.pos) return ast.void_type diff --git a/vlib/v/checker/for.v b/vlib/v/checker/for.v index 32863f3d56..eb0346a12f 100644 --- a/vlib/v/checker/for.v +++ b/vlib/v/checker/for.v @@ -165,9 +165,12 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) { c.in_for_count++ prev_loop_label := c.loop_label c.expected_type = ast.bool_type - typ := c.expr(node.cond) - if !node.is_inf && typ.idx() != ast.bool_type_idx && !c.pref.translated && !c.file.is_translated { - c.error('non-bool used as for condition', node.pos) + if node.cond !is ast.EmptyExpr { + typ := c.expr(node.cond) + if !node.is_inf && typ.idx() != ast.bool_type_idx && !c.pref.translated + && !c.file.is_translated { + c.error('non-bool used as for condition', node.pos) + } } if mut node.cond is ast.InfixExpr { if node.cond.op == .key_is { diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index 0846c49d28..ed73eafad4 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -12,7 +12,14 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { mut left_type := c.expr(node.left) node.left_type = left_type c.expected_type = left_type + + if node.op == .key_is { + c.inside_x_is_type = true + } mut right_type := c.expr(node.right) + if node.op == .key_is { + c.inside_x_is_type = false + } node.right_type = right_type if left_type.is_number() && !left_type.is_ptr() && right_type in [ast.int_literal_type, ast.float_literal_type] { diff --git a/vlib/v/checker/tests/generic_type_name_in_non_generic_function.out b/vlib/v/checker/tests/generic_type_name_in_non_generic_function.out new file mode 100644 index 0000000000..7a6fcf1d0a --- /dev/null +++ b/vlib/v/checker/tests/generic_type_name_in_non_generic_function.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/generic_type_name_in_non_generic_function.vv:3:10: error: unexpected generic variable in non-generic function `main` + 1 | fn main() { + 2 | c := u8(`D`) + 3 | if c >= A && c <= Z { + | ^ + 4 | println('yes') + 5 | } else { diff --git a/vlib/v/checker/tests/generic_type_name_in_non_generic_function.vv b/vlib/v/checker/tests/generic_type_name_in_non_generic_function.vv new file mode 100644 index 0000000000..0004498c4a --- /dev/null +++ b/vlib/v/checker/tests/generic_type_name_in_non_generic_function.vv @@ -0,0 +1,8 @@ +fn main() { + c := u8(`D`) + if c >= A && c <= Z { + println('yes') + } else { + println('no') + } +} diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index 6fb12c7234..102a92266e 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -252,7 +252,7 @@ pub fn (mut ctx Context) file(f_path string) Result { return Result{} } content_type := vweb.mime_types[ext] - if content_type.len == O { + if content_type.len == 0 { eprintln('no MIME type found for extension $ext') ctx.server_error(500) } else {