checker: add error for `if c >= A && c <= Z {` in non generic functions

master
Delyan Angelov 2022-06-07 18:33:08 +03:00
parent 96a9faf2fd
commit 4b3c3d9082
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
7 changed files with 43 additions and 6 deletions

View File

@ -89,6 +89,7 @@ pub mut:
inside_defer bool // true inside `defer {}` blocks inside_defer bool // true inside `defer {}` blocks
inside_fn_arg bool // `a`, `b` in `a.f(b)` inside_fn_arg bool // `a`, `b` in `a.f(b)`
inside_ct_attr bool // true inside `[if expr]` 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 inside_comptime_for_field bool
skip_flags bool // should `#flag` and `#include` be skipped 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 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_defer = false
c.inside_fn_arg = false c.inside_fn_arg = false
c.inside_ct_attr = false c.inside_ct_attr = false
c.inside_x_is_type = false
c.skip_flags = false c.skip_flags = false
c.fn_level = 0 c.fn_level = 0
c.expr_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) { fn (mut c Checker) block(node ast.Block) {
if node.is_unsafe { if node.is_unsafe {
prev_unsafe := c.inside_unsafe
c.inside_unsafe = true c.inside_unsafe = true
c.stmts(node.stmts) c.stmts(node.stmts)
c.inside_unsafe = false c.inside_unsafe = prev_unsafe
} else { } else {
c.stmts(node.stmts) 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) c.error('incorrect use of compile-time type', node.pos)
} }
ast.EmptyExpr { ast.EmptyExpr {
print_backtrace()
c.error('checker.expr(): unhandled EmptyExpr', token.Pos{}) c.error('checker.expr(): unhandled EmptyExpr', token.Pos{})
return ast.void_type
} }
ast.CTempVar { ast.CTempVar {
return node.typ return node.typ
@ -2269,6 +2274,11 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
return c.struct_init(mut node) return c.struct_init(mut node)
} }
ast.TypeNode { 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 return node.typ
} }
ast.TypeOf { ast.TypeOf {

View File

@ -9,7 +9,9 @@ import v.util
import v.pkgconfig import v.pkgconfig
fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { 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' { if node.method_name == 'compile_error' {
c.error(node.args_var, node.pos) c.error(node.args_var, node.pos)
return ast.void_type return ast.void_type

View File

@ -165,9 +165,12 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
c.in_for_count++ c.in_for_count++
prev_loop_label := c.loop_label prev_loop_label := c.loop_label
c.expected_type = ast.bool_type c.expected_type = ast.bool_type
typ := c.expr(node.cond) if node.cond !is ast.EmptyExpr {
if !node.is_inf && typ.idx() != ast.bool_type_idx && !c.pref.translated && !c.file.is_translated { typ := c.expr(node.cond)
c.error('non-bool used as for condition', node.pos) 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 mut node.cond is ast.InfixExpr {
if node.cond.op == .key_is { if node.cond.op == .key_is {

View File

@ -12,7 +12,14 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
mut left_type := c.expr(node.left) mut left_type := c.expr(node.left)
node.left_type = left_type node.left_type = left_type
c.expected_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) mut right_type := c.expr(node.right)
if node.op == .key_is {
c.inside_x_is_type = false
}
node.right_type = right_type node.right_type = right_type
if left_type.is_number() && !left_type.is_ptr() if left_type.is_number() && !left_type.is_ptr()
&& right_type in [ast.int_literal_type, ast.float_literal_type] { && right_type in [ast.int_literal_type, ast.float_literal_type] {

View File

@ -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 {

View File

@ -0,0 +1,8 @@
fn main() {
c := u8(`D`)
if c >= A && c <= Z {
println('yes')
} else {
println('no')
}
}

View File

@ -252,7 +252,7 @@ pub fn (mut ctx Context) file(f_path string) Result {
return Result{} return Result{}
} }
content_type := vweb.mime_types[ext] content_type := vweb.mime_types[ext]
if content_type.len == O { if content_type.len == 0 {
eprintln('no MIME type found for extension $ext') eprintln('no MIME type found for extension $ext')
ctx.server_error(500) ctx.server_error(500)
} else { } else {