diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index e00e7c150e..00f42cccc9 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -832,7 +832,7 @@ fn (ar []string) contains(val string) bool { // TODO generic fn (ar []int) contains(val int) bool { - for i, s in ar { + for s in ar { if s == val { return true } @@ -1206,7 +1206,7 @@ pub fn (a []string) join(del string) string { return '' } mut len := 0 - for i, val in a { + for val in a { len += val.len + del.len } len -= del.len diff --git a/vlib/os/os.v b/vlib/os/os.v index 99e75e31ea..357b0a182d 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -1061,7 +1061,7 @@ pub fn walk_ext(path, ext string) []string { } mut res := []string{} separator := if path.ends_with(os.path_separator) { '' } else { os.path_separator } - for i, file in files { + for file in files { if file.starts_with('.') { continue } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 3b9aaca323..1b7d68dd58 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -270,12 +270,13 @@ pub struct Stmt { */ pub struct Var { pub: - name string - expr Expr - is_mut bool + name string + expr Expr + is_mut bool mut: - typ table.Type - pos token.Position + typ table.Type + pos token.Position + is_used bool } pub struct GlobalDecl { diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index fa0fb7c5c7..6a5571220b 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -12,15 +12,9 @@ mut: children []&Scope start_pos int end_pos int - unused_vars map[string]UnusedVar objects map[string]ScopeObject } -pub struct UnusedVar { - name string - pos token.Position -} - pub fn new_scope(parent &Scope, start_pos int) &Scope { return &ast.Scope{ parent: parent @@ -63,12 +57,12 @@ pub fn (s &Scope) is_known(name string) bool { return false } -pub fn (s &Scope) find_var(name string) ?Var { +pub fn (s &Scope) find_var(name string) ?&Var { if obj := s.find(name) { v := ScopeObject(obj) match v { Var { - return *it + return it } else {} } @@ -76,12 +70,12 @@ pub fn (s &Scope) find_var(name string) ?Var { return none } -pub fn (s &Scope) find_const(name string) ?ConstField { +pub fn (s &Scope) find_const(name string) ?&ConstField { if obj := s.find(name) { cf := ScopeObject(obj) match cf { ConstField { - return *it + return it } else {} } @@ -112,37 +106,13 @@ pub fn (s mut Scope) register(name string, obj ScopeObject) { if name == '_' { return } - if x := s.find(name) { + if _ := s.find(name) { // println('existing obect: $name') return } s.objects[name] = obj } -pub fn (s mut Scope) register_unused_var(name string, pos token.Position) { - s.unused_vars[name] = UnusedVar{name, pos} -} - -pub fn (s mut Scope) remove_unused_var(name string) { - mut sc := s - for !isnil(sc) { - sc.unused_vars.delete(name) - sc = sc.parent - } -} - -pub fn (s mut Scope) unused_vars() []UnusedVar { - ret := []UnusedVar{} - for _, v in s.unused_vars { - ret << v - } - return ret -} - -pub fn (s mut Scope) clear_unused_vars() { - s.unused_vars = map[string]UnusedVar -} - pub fn (s &Scope) outermost() &Scope { mut sc := s for !isnil(sc.parent) { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index fae1791ffc..e3c84d04bb 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -203,7 +203,7 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) { } c.error('struct name must begin with capital letter', pos) } - for fi, field in decl.fields { + for field in decl.fields { sym := c.table.get_type_symbol(field.typ) if sym.kind == .placeholder && !decl.is_c && !sym.name.starts_with('C.') { c.error('unknown type `$sym.name`', field.pos) @@ -554,7 +554,7 @@ pub fn (mut c Checker) call_method(call_expr mut ast.CallExpr) table.Type { mut scope := c.file.scope.innermost(call_expr.pos.pos) scope.update_var_type('it', array_info.elem_type) } - for i, arg in call_expr.args { + for arg in call_expr.args { c.expr(arg.expr) } // need to return `array_xxx` instead of `array` diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 354a526d8c..953c45c998 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -480,7 +480,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { g.typedefs.writeln('typedef enum {') mut cur_enum_expr := '' mut cur_enum_offset := 0 - for j, field in it.fields { + for field in it.fields { g.typedefs.write('\t${enum_name}_${field.name}') if field.has_expr { g.typedefs.write(' = ') @@ -1918,7 +1918,7 @@ fn (mut g Gen) return_statement(node ast.Return) { } fn (mut g Gen) const_decl(node ast.ConstDecl) { - for i, field in node.fields { + for field in node.fields { name := c_name(field.name) // TODO hack. Cut the generated value and paste it into definitions. pos := g.out.len @@ -3061,7 +3061,7 @@ fn (mut g Gen) gen_str_for_enum(info table.Enum, styp, str_fn_name string) { g.definitions.writeln('string ${str_fn_name}($styp it); // auto') g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { /* gen_str_for_enum */') g.auto_str_funcs.writeln('\tswitch(it) {') - for i, val in info.vals { + for val in info.vals { g.auto_str_funcs.writeln('\t\tcase ${s}_$val: return tos3("$val");') } g.auto_str_funcs.writeln('\t\tdefault: return tos3("unknown enum value");') @@ -3075,7 +3075,7 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) { mut fnames2strfunc := { '': '' } // map[string]string // TODO vfmt bug - for i, field in info.fields { + for field in info.fields { sym := g.table.get_type_symbol(field.typ) if sym.kind in [.struct_, .array, .array_fixed, .map, .enum_] { field_styp := g.typ(field.typ) diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 61e5400fec..eedbb7e58e 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -426,7 +426,7 @@ fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) { is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic) gen_vargs := is_variadic && !is_forwarding_varg mut arg_no := 0 - for i, arg in args { + for arg in args { if gen_vargs && arg_no == expected_types.len - 1 { break } diff --git a/vlib/v/gen/x64/gen.v b/vlib/v/gen/x64/gen.v index 9f7877d59a..2071be0d86 100644 --- a/vlib/v/gen/x64/gen.v +++ b/vlib/v/gen/x64/gen.v @@ -600,7 +600,7 @@ fn (mut g Gen) allocate_var(name string, size, initial_val int) { fn (mut g Gen) assign_stmt(node ast.AssignStmt) { // `a := 1` | `a,b := 1,2` - for i, ident in node.left { + for ident in node.left { match node.right[0] { ast.IntegerLiteral { g.allocate_var(ident.name, 4, it.val.int()) diff --git a/vlib/v/parser/assign.v b/vlib/v/parser/assign.v index 5cee8840f9..33c2f53a6f 100644 --- a/vlib/v/parser/assign.v +++ b/vlib/v/parser/assign.v @@ -32,11 +32,13 @@ fn (mut p Parser) assign_stmt() ast.Stmt { name: ident.name expr: exprs[i] is_mut: ident.is_mut || p.inside_for + pos: ident.pos }) } else { p.scope.register(ident.name, ast.Var{ name: ident.name is_mut: ident.is_mut || p.inside_for + pos: ident.pos }) } } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index e6707f66d8..e7565483b1 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -37,10 +37,14 @@ pub fn (mut p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr { p.scope.register('err', ast.Var{ name: 'err' typ: table.string_type + pos: p.tok.position() + is_used: true }) p.scope.register('errcode', ast.Var{ name: 'errcode' typ: table.int_type + pos: p.tok.position() + is_used: true }) is_or_block_used = true or_stmts = p.parse_block_no_scope() @@ -164,6 +168,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl { name: arg.name typ: arg.typ is_mut: arg.is_mut + pos: p.tok.position() + is_used: true }) // Do not allow `mut` with simple types // TODO move to checker? @@ -264,6 +270,8 @@ fn (mut p Parser) anon_fn() ast.AnonFn { p.scope.register(arg.name, ast.Var{ name: arg.name typ: arg.typ + pos: p.tok.position() + is_used: true }) } mut return_type := table.void_type diff --git a/vlib/v/parser/for.v b/vlib/v/parser/for.v index 5ca4e2815b..8842f372ba 100644 --- a/vlib/v/parser/for.v +++ b/vlib/v/parser/for.v @@ -67,12 +67,16 @@ fn (mut p Parser) for_stmt() ast.Stmt { } } else if p.peek_tok.kind in [.key_in, .comma] { // `for i in vals`, `for i in start .. end` + mut val_var_pos := p.tok.position() mut key_var_name := '' mut val_var_name := p.check_name() if p.tok.kind == .comma { p.check(.comma) + key_var_pos := val_var_pos + val_var_pos = p.tok.position() key_var_name = val_var_name val_var_name = p.check_name() + if p.scope.known_var(key_var_name) { p.error('redefinition of key iteration variable `$key_var_name`') } @@ -82,6 +86,7 @@ fn (mut p Parser) for_stmt() ast.Stmt { p.scope.register(key_var_name, ast.Var{ name: key_var_name typ: table.int_type + pos: key_var_pos }) } else if p.scope.known_var(val_var_name) { p.error('redefinition of value iteration variable `$val_var_name`') @@ -104,11 +109,13 @@ fn (mut p Parser) for_stmt() ast.Stmt { p.scope.register(val_var_name, ast.Var{ name: val_var_name typ: table.int_type + pos: val_var_pos }) } else { // this type will be set in checker p.scope.register(val_var_name, ast.Var{ name: val_var_name + pos: val_var_pos }) } p.inside_for = false diff --git a/vlib/v/parser/if.v b/vlib/v/parser/if.v index aed61e55ba..f0b1c29c0c 100644 --- a/vlib/v/parser/if.v +++ b/vlib/v/parser/if.v @@ -43,12 +43,14 @@ fn (mut p Parser) if_expr() ast.IfExpr { if p.peek_tok.kind == .decl_assign { is_or = true p.open_scope() + var_pos := p.tok.position() var_name := p.check_name() p.check(.decl_assign) expr := p.expr(0) p.scope.register(var_name, ast.Var{ name: var_name expr: expr + pos: var_pos }) cond = ast.IfGuardExpr{ var_name: var_name @@ -89,6 +91,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr { if is_mut { p.next() } + cond_pos := p.tok.position() cond := p.expr(0) p.inside_match = false p.check(.lcbr) @@ -119,6 +122,8 @@ fn (mut p Parser) match_expr() ast.MatchExpr { p.scope.register('it', ast.Var{ name: 'it' typ: typ.to_ptr() + pos: cond_pos + is_used: true }) // TODO if p.tok.kind == .comma { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 66582c02cb..f993f41d4f 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -195,16 +195,22 @@ pub fn (mut p Parser) open_scope() { } pub fn (mut p Parser) close_scope() { - if !p.pref.is_repl && !p.pref.is_fmt { - for v in p.scope.unused_vars() { - if p.pref.is_prod { - p.error_with_pos('Unused variable: $v.name', v.pos) - } else { - p.warn_with_pos('Unused variable: $v.name', v.pos) + if !p.pref.is_repl && !p.scanner.is_fmt { + for _, obj in p.scope.objects { + match obj { + ast.Var { + if !it.is_used && !it.name.starts_with('__') { + if p.pref.is_prod { + p.error_with_pos('Unused variable: $it.name', it.pos) + } else { + p.warn_with_pos('Unused variable: $it.name', it.pos) + } + } + } + else {} } } } - p.scope.clear_unused_vars() p.scope.end_pos = p.tok.pos p.scope.parent.children << p.scope p.scope = p.scope.parent @@ -393,9 +399,6 @@ pub fn (mut p Parser) stmt() ast.Stmt { } } .key_mut, .key_static, .key_var { - if p.peek_tok.kind == .name && p.peek_tok.lit != '_' && !p.peek_tok.lit.starts_with('__') { - p.scope.register_unused_var(p.peek_tok.lit, p.peek_tok.position()) - } return p.assign_stmt() } .key_for { @@ -457,14 +460,7 @@ pub fn (mut p Parser) stmt() ast.Stmt { else { // `x := ...` if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign, .comma] { - register_unused := p.peek_tok.kind == .decl_assign - lit := p.tok.lit - pos := p.tok.position() - ret := p.assign_stmt() - if register_unused && lit != '_' && !lit.starts_with('__') { - p.scope.register_unused_var(lit, pos) - } - return ret + return p.assign_stmt() } else if p.tok.kind == .name && p.peek_tok.kind == .colon { // `label:` name := p.check_name() @@ -472,8 +468,6 @@ pub fn (mut p Parser) stmt() ast.Stmt { return ast.GotoLabel{ name: name } - } else if p.tok.kind == .name { - p.scope.remove_unused_var(p.tok.lit) } epos := p.tok.position() expr := p.expr(0) @@ -609,7 +603,16 @@ pub fn (mut p Parser) name_expr() ast.Expr { if p.tok.lit in ['r', 'c', 'js'] && p.peek_tok.kind == .string && p.prev_tok.kind != .str_dollar { return p.string_expr() } - known_var := p.scope.known_var(p.tok.lit) + mut known_var := false + if obj := p.scope.find(p.tok.lit) { + match mut obj { + ast.Var { + known_var = true + it.is_used = true + } + else {} + } + } if p.peek_tok.kind == .dot && !known_var && (is_c || is_js || p.known_import(p.tok.lit) || p.mod.all_after('.') == p.tok.lit) { if is_c { @@ -753,6 +756,8 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr { fn (mut p Parser) filter() { p.scope.register('it', ast.Var{ name: 'it' + pos: p.tok.position() + is_used: true }) } @@ -783,10 +788,14 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr { p.scope.register('errcode', ast.Var{ name: 'errcode' typ: table.int_type + pos: p.tok.position() + is_used: true }) p.scope.register('err', ast.Var{ name: 'err' typ: table.string_type + pos: p.tok.position() + is_used: true }) is_or_block_used = true or_stmts = p.parse_block_no_scope() @@ -1028,9 +1037,6 @@ fn (mut p Parser) return_stmt() ast.Return { } } for { - if p.tok.kind == .name { - p.scope.remove_unused_var(p.tok.lit) - } expr := p.expr(0) exprs << expr if p.tok.kind == .comma { @@ -1220,10 +1226,11 @@ fn (mut p Parser) type_decl() ast.TypeDecl { fn (mut p Parser) assoc() ast.Assoc { var_name := p.check_name() pos := p.tok.position() - v := p.scope.find_var(var_name) or { + mut v := p.scope.find_var(var_name) or { p.error('unknown variable `$var_name`') return ast.Assoc{} } + v.is_used = true // println('assoc var $name typ=$var.typ') mut fields := []string{} mut vals := []ast.Expr{} @@ -1245,7 +1252,7 @@ fn (mut p Parser) assoc() ast.Assoc { fields: fields exprs: vals pos: pos - typ: v.typ + // typ: v.typ } } diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index ff60363aad..1461100d92 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -16,7 +16,6 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { // Prefix match p.tok.kind { .name { - p.scope.remove_unused_var(p.tok.lit) node = p.name_expr() p.is_stmt_ident = is_stmt_ident } @@ -79,7 +78,6 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { type_name: p.check_name() } } else { - p.scope.remove_unused_var(p.tok.lit) sizeof_type := p.parse_type() node = ast.SizeOf{ typ: sizeof_type @@ -104,7 +102,6 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { } else { // it should be a struct if p.peek_tok.kind == .pipe { - p.scope.remove_unused_var(p.tok.lit) node = p.assoc() } else if p.peek_tok.kind == .colon || p.tok.kind == .rcbr { node = p.struct_init(true) // short_syntax: true diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index d571760c47..ca9adceaec 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -66,7 +66,7 @@ pub fn (t Type) is_ptr() bool { [inline] pub fn (t Type) set_nr_muls(nr_muls int) Type { if nr_muls < 0 || nr_muls > 255 { - panic('typ_set_nr_muls: nr_muls must be between 0 & 255') + panic('set_nr_muls: nr_muls must be between 0 & 255') } return (((int(t) >> 24) & 0xff) << 24) | (nr_muls << 16) | (u16(t) & 0xffff) } @@ -76,7 +76,7 @@ pub fn (t Type) set_nr_muls(nr_muls int) Type { pub fn (t Type) to_ptr() Type { nr_muls := (int(t) >> 16) & 0xff if nr_muls == 255 { - panic('type_to_pre: nr_muls is already at max of 255') + panic('to_ptr: nr_muls is already at max of 255') } return (((int(t) >> 24) & 0xff) << 24) | ((nr_muls + 1) << 16) | (u16(t) & 0xffff) }