diff --git a/cmd/tools/preludes/tests_assertions.v b/cmd/tools/preludes/tests_assertions.v index ec901e96a7..f6769ec4ff 100644 --- a/cmd/tools/preludes/tests_assertions.v +++ b/cmd/tools/preludes/tests_assertions.v @@ -11,7 +11,7 @@ import term // / since it is done in normal V code, instead of in embedded C ... // ////////////////////////////////////////////////////////////////// fn cb_assertion_failed(filename string, line int, sourceline string, funcname string) { - color_on := term.can_show_color_on_stderr() + // color_on := term.can_show_color_on_stderr() use_relative_paths := match os.getenv('VERROR_PATHS') { 'absolute'{ false diff --git a/cmd/v/v.v b/cmd/v/v.v index d8567c9227..7ee0187532 100644 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -125,6 +125,9 @@ fn parse_args(args []string) (&pref.Preferences, string) { '-live' { res.is_live = true } + '-repl' { + res.is_repl = true + } '-sharedlive' { res.is_live = true res.is_shared = true diff --git a/vlib/builtin/builtin_windows.c.v b/vlib/builtin/builtin_windows.c.v index 5cf489241c..1a774616b7 100644 --- a/vlib/builtin/builtin_windows.c.v +++ b/vlib/builtin/builtin_windows.c.v @@ -92,7 +92,8 @@ $if msvc { handle := C.GetCurrentProcess() defer { C.SymCleanup(handle) } - options := C.SymSetOptions(SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME) + C.SymSetOptions(SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME) + syminitok := C.SymInitialize( handle, 0, 1) if syminitok != 1 { println('Failed getting process: Aborting backtrace.\n') diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 720aa22f33..6aa21d6220 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -1223,7 +1223,6 @@ pub fn (a []string) join(del string) string { // Go thru every string and copy its every char one by one for i, val in a { for j in 0..val.len { - c := val[j] res.str[idx] = val.str[j] idx++ } diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index 1aca6c7346..34d9f3cddf 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -4,6 +4,7 @@ module ast import v.table +import v.token pub struct Scope { mut: @@ -11,9 +12,15 @@ 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 @@ -107,6 +114,30 @@ pub fn (s mut Scope) register(name string, obj ScopeObject) { 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/builder/cc.v b/vlib/v/builder/cc.v index f504b6aae5..fef727be91 100644 --- a/vlib/v/builder/cc.v +++ b/vlib/v/builder/cc.v @@ -174,7 +174,7 @@ fn (v mut Builder) cc() { is_cc_clang := v.pref.ccompiler.contains('clang') || guessed_compiler == 'clang' is_cc_tcc := v.pref.ccompiler.contains('tcc') || guessed_compiler == 'tcc' is_cc_gcc := v.pref.ccompiler.contains('gcc') || guessed_compiler == 'gcc' - is_cc_msvc := v.pref.ccompiler.contains('msvc') || guessed_compiler == 'msvc' + // is_cc_msvc := v.pref.ccompiler.contains('msvc') || guessed_compiler == 'msvc' // if is_cc_clang { if debug_mode { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 6491370da4..f5ae37c9d4 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1515,7 +1515,7 @@ pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type { if !has_else { mut used_values_count := 0 - for bi, branch in node.branches { + for _, branch in node.branches { used_values_count += branch.exprs.len for bi_ei, bexpr in branch.exprs { match bexpr { diff --git a/vlib/v/checker/tests/inout/match_err.vv b/vlib/v/checker/tests/inout/match_err.vv index f83c93155e..952e4b768b 100644 --- a/vlib/v/checker/tests/inout/match_err.vv +++ b/vlib/v/checker/tests/inout/match_err.vv @@ -6,4 +6,5 @@ fn main() { 2 { 'test' } else { '' } } + _ = res } diff --git a/vlib/v/checker/tests/inout/match_expr_else.out b/vlib/v/checker/tests/inout/match_expr_else.out index 962a3b44ce..2544b8f7fd 100644 --- a/vlib/v/checker/tests/inout/match_expr_else.out +++ b/vlib/v/checker/tests/inout/match_expr_else.out @@ -1,7 +1,7 @@ -vlib/v/checker/tests/inout/match_expr_else.v:5:9: error: match must be exhaustive (add match branches for: `f64` or an else{} branch) +vlib/v/checker/tests/inout/match_expr_else.v:5:6: error: match must be exhaustive (add match branches for: `f64` or an else{} branch) 3| fn main() { 4| x := A('test') - 5| res := match x { - ~~~~~~~~~ + 5| _ = match x { + ~~~~~~~~~ 6| int { 7| 'int' diff --git a/vlib/v/checker/tests/inout/match_expr_else.vv b/vlib/v/checker/tests/inout/match_expr_else.vv index d32dabd9f2..d120acbd19 100644 --- a/vlib/v/checker/tests/inout/match_expr_else.vv +++ b/vlib/v/checker/tests/inout/match_expr_else.vv @@ -2,7 +2,7 @@ type A = int | string | f64 fn main() { x := A('test') - res := match x { + _ = match x { int { 'int' } diff --git a/vlib/v/checker/tests/inout/short_struct_too_many.out b/vlib/v/checker/tests/inout/short_struct_too_many.out index b403965637..7a0e28d331 100644 --- a/vlib/v/checker/tests/inout/short_struct_too_many.out +++ b/vlib/v/checker/tests/inout/short_struct_too_many.out @@ -3,4 +3,5 @@ vlib/v/checker/tests/inout/short_struct_too_many.v:6:7: error: too many fields 5| fn main() { 6| t := Test{true, false} ~~~~~~~~~~~~~~~~~ - 7| } \ No newline at end of file + 7| _ = t + 8| } diff --git a/vlib/v/checker/tests/inout/short_struct_too_many.vv b/vlib/v/checker/tests/inout/short_struct_too_many.vv index a707dc3513..d33acc614d 100644 --- a/vlib/v/checker/tests/inout/short_struct_too_many.vv +++ b/vlib/v/checker/tests/inout/short_struct_too_many.vv @@ -4,4 +4,5 @@ struct Test { fn main() { t := Test{true, false} + _ = t } diff --git a/vlib/v/checker/tests/inout/struct_unknown_field.out b/vlib/v/checker/tests/inout/struct_unknown_field.out index 1e2d6577b7..9e01e772a3 100644 --- a/vlib/v/checker/tests/inout/struct_unknown_field.out +++ b/vlib/v/checker/tests/inout/struct_unknown_field.out @@ -4,4 +4,4 @@ vlib/v/checker/tests/inout/struct_unknown_field.v:8:9: error: unknown field `bar 8| bar: false ~~~~~~~~~~ 9| } - 10| } + 10| _ = t diff --git a/vlib/v/checker/tests/inout/struct_unknown_field.vv b/vlib/v/checker/tests/inout/struct_unknown_field.vv index 8a1145d01e..e4ec496630 100644 --- a/vlib/v/checker/tests/inout/struct_unknown_field.vv +++ b/vlib/v/checker/tests/inout/struct_unknown_field.vv @@ -7,4 +7,5 @@ fn main() { foo: true bar: false } + _ = t } diff --git a/vlib/v/checker/tests/inout/void_fn_as_value.out b/vlib/v/checker/tests/inout/void_fn_as_value.out index 0ad36288a4..94eb71e5d0 100644 --- a/vlib/v/checker/tests/inout/void_fn_as_value.out +++ b/vlib/v/checker/tests/inout/void_fn_as_value.out @@ -4,4 +4,4 @@ vlib/v/checker/tests/inout/void_fn_as_value.v:5:8: error: unknown function: x 5| a += x('a','b') ~~~~~~~~~~ 6| mut b := 'abcdef' - 7| } + 7| _ = b diff --git a/vlib/v/checker/tests/inout/void_fn_as_value.vv b/vlib/v/checker/tests/inout/void_fn_as_value.vv index d88cc2d871..4d6f97dc39 100644 --- a/vlib/v/checker/tests/inout/void_fn_as_value.vv +++ b/vlib/v/checker/tests/inout/void_fn_as_value.vv @@ -4,4 +4,5 @@ fn main() { mut a := 'aa' a += x('a','b') mut b := 'abcdef' + _ = b } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 00f145d308..c1ee187887 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -94,6 +94,8 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string x := 10 // line // sep y := 20 + _ = x + _ = y } else { } // println('start cgen2') @@ -919,7 +921,7 @@ fn (mut g Gen) expr(node ast.Expr) { ast.ArrayInit { type_sym := g.table.get_type_symbol(it.typ) if type_sym.kind != .array_fixed { - elem_sym := g.table.get_type_symbol(it.elem_type) + // elem_sym := g.table.get_type_symbol(it.elem_type) elem_type_str := g.typ(it.elem_type) if it.exprs.len == 0 { // use __new_array to fix conflicts when the name of the variable is new_array @@ -1801,8 +1803,8 @@ fn (mut g Gen) return_statement(node ast.Return) { // multiple returns if node.exprs.len > 1 { g.write(' ') - typ_sym := g.table.get_type_symbol(g.fn_decl.return_type) - mr_info := typ_sym.info as table.MultiReturn + // typ_sym := g.table.get_type_symbol(g.fn_decl.return_type) + // mr_info := typ_sym.info as table.MultiReturn mut styp := g.typ(g.fn_decl.return_type) if fn_return_is_optional { // && !table.type_is(node.types[0], .optional) && node.types[0] != styp = styp[7..] // remove 'Option_' @@ -1958,7 +1960,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { } */ // User set fields - for i, field in struct_init.fields { + for _, field in struct_init.fields { field_name := c_name(field.name) inited_fields << field.name g.write('\t.$field_name = ') diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 6812c0d2b8..6a61cfd457 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -594,7 +594,7 @@ fn (g mut JsGen) gen_branch_stmt(it ast.BranchStmt) { } fn (g mut JsGen) gen_const_decl(it ast.ConstDecl) { - old_indent := g.indents[g.namespace] + // old_indent := g.indents[g.namespace] for i, field in it.fields { // TODO hack. Cut the generated value and paste it into definitions. pos := g.out.len @@ -689,7 +689,7 @@ fn (g mut JsGen) gen_method_decl(it ast.FnDecl) { name = util.replace_op(name) } - type_name := g.typ(it.return_type) + // type_name := g.typ(it.return_type) // generate jsdoc for the function g.writeln(g.doc.gen_fn(it)) @@ -767,7 +767,7 @@ fn (g mut JsGen) gen_for_in_stmt(it ast.ForInStmt) { } else if it.kind == .array || table.type_is(it.cond_type, .variadic) { // `for num in nums {` i := if it.key_var == '' { g.new_tmp_var() } else { it.key_var } - styp := g.typ(it.val_type) + // styp := g.typ(it.val_type) g.inside_loop = true g.write('for (let $i = 0; $i < ') g.expr(it.cond) @@ -780,8 +780,8 @@ fn (g mut JsGen) gen_for_in_stmt(it ast.ForInStmt) { g.writeln('}') } else if it.kind == .map { // `for key, val in map[string]int {` - key_styp := g.typ(it.key_type) - val_styp := g.typ(it.val_type) + // key_styp := g.typ(it.key_type) + // val_styp := g.typ(it.val_type) key := if it.key_var == '' { g.new_tmp_var() } else { it.key_var } g.write('for (let [$key, $it.val_var] of ') g.expr(it.cond) @@ -817,7 +817,7 @@ fn (g mut JsGen) gen_for_stmt(it ast.ForStmt) { } fn (g mut JsGen) fn_args(args []table.Arg, is_variadic bool) { - no_names := args.len > 0 && args[0].name == 'arg_1' + // no_names := args.len > 0 && args[0].name == 'arg_1' for i, arg in args { is_varg := i == args.len - 1 && is_variadic if is_varg { @@ -860,10 +860,10 @@ fn (g mut JsGen) gen_go_stmt(node ast.GoStmt) { } fn (g mut JsGen) gen_map_init_expr(it ast.MapInit) { - key_typ_sym := g.table.get_type_symbol(it.key_type) - value_typ_sym := g.table.get_type_symbol(it.value_type) - key_typ_str := key_typ_sym.name.replace('.', '__') - value_typ_str := value_typ_sym.name.replace('.', '__') + // key_typ_sym := g.table.get_type_symbol(it.key_type) + // value_typ_sym := g.table.get_type_symbol(it.value_type) + // key_typ_str := key_typ_sym.name.replace('.', '__') + // value_typ_str := value_typ_sym.name.replace('.', '__') if it.vals.len > 0 { g.writeln('new Map([') g.inc_indent() diff --git a/vlib/v/parser/containers.v b/vlib/v/parser/containers.v index e29772bd59..157a18d76f 100644 --- a/vlib/v/parser/containers.v +++ b/vlib/v/parser/containers.v @@ -43,6 +43,7 @@ fn (var p Parser) array_init() ast.ArrayInit { // NB: do not remove the next line without testing // v selfcompilation with tcc first tcc_stack_bug := 12345 + _ = tcc_stack_bug } last_pos = p.tok.position() p.check(.rsbr) diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 8140717cdf..c2117b5acd 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -11,7 +11,6 @@ import v.util pub fn (mut p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr { first_pos := p.tok.position() - tok := p.tok name := p.check_name() fn_name := if is_c { 'C.$name' diff --git a/vlib/v/parser/for.v b/vlib/v/parser/for.v index f6ff6f78f4..8b8621463f 100644 --- a/vlib/v/parser/for.v +++ b/vlib/v/parser/for.v @@ -43,7 +43,6 @@ fn (var p Parser) for_stmt() ast.Stmt { // Allow `for i = 0; i < ...` p.check(.semicolon) if p.tok.kind != .semicolon { - var typ := table.void_type cond = p.expr(0) has_cond = true } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 90a2bf397d..6e4bfe4904 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -192,6 +192,16 @@ pub fn (mut p Parser) open_scope() { } pub fn (mut p Parser) close_scope() { + if !p.pref.is_repl { + 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) + } + } + } + p.scope.clear_unused_vars() p.scope.end_pos = p.tok.pos p.scope.parent.children << p.scope p.scope = p.scope.parent @@ -376,6 +386,9 @@ 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 { @@ -437,7 +450,14 @@ pub fn (mut p Parser) stmt() ast.Stmt { else { // `x := ...` if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign, .comma] { - return p.assign_stmt() + 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 } else if p.tok.kind == .name && p.peek_tok.kind == .colon { // `label:` name := p.check_name() @@ -445,6 +465,8 @@ 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) @@ -994,6 +1016,9 @@ 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 { diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index 5b859175cb..c3c300bf8d 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -16,6 +16,7 @@ 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 } @@ -78,6 +79,7 @@ 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 @@ -102,6 +104,7 @@ 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/tests/prod/assoc.prod.v b/vlib/v/tests/prod/assoc.prod.v index 18845a14e2..406a29b378 100644 --- a/vlib/v/tests/prod/assoc.prod.v +++ b/vlib/v/tests/prod/assoc.prod.v @@ -1,13 +1,16 @@ struct MyStruct { - s string + s string } + fn new_st() MyStruct { - return MyStruct{} + return MyStruct{} } + fn get_st() MyStruct { - r := new_st() - return {r|s:'6'} + r := new_st() + return {r|s:'6'} } + fn main() { s := get_st() println(s)