From 9ccd3bde0134911de88081c9e3aef098070ea5ae Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 25 Jul 2019 13:16:17 +0200 Subject: [PATCH] do not allow declaring a mutable variable if it's never modified --- compiler/fn.v | 33 +++++++++++++++++++++++++-------- compiler/main.v | 4 ++-- compiler/parser.v | 26 +++++++++++++++++++------- compiler/table.v | 3 +-- 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/compiler/fn.v b/compiler/fn.v index 479113bea7..f0b07d7f6e 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -49,9 +49,20 @@ fn (f mut Fn) open_scope() { fn (f &Fn) mark_var_used(v Var) { for i, vv in f.local_vars { if vv.name == v.name { - mut ptr := &f.local_vars[i] - ptr.is_used = true - // / f.local_vars[i].is_used = true + //mut ptr := &f.local_vars[i] + //ptr.is_used = true + f.local_vars[i].is_used = true + return + } + } +} + +fn (f &Fn) mark_var_changed(v Var) { + for i, vv in f.local_vars { + if vv.name == v.name { + //mut ptr := &f.local_vars[i] + //ptr.is_used = true + f.local_vars[i].is_changed = true // return } } @@ -86,13 +97,11 @@ fn (p mut Parser) is_sig() bool { } fn new_fn(pkg string, is_public bool) *Fn { - mut f := &Fn { + return &Fn { pkg: pkg - local_vars: [Var{} - ; MaxLocalVars] + local_vars: [Var{} ; MaxLocalVars] is_public: is_public } - return f } // Function signatures are added to the top of the .c file in the first run. @@ -444,6 +453,11 @@ fn (p mut Parser) check_unused_variables() { p.scanner.line_nr = var.line_nr - 1 p.error('`$var.name` declared and not used') } + + if !var.is_changed && var.is_mut && !p.pref.is_repl && !var.is_arg && !p.pref.translated && var.name != '_' { + p.scanner.line_nr = var.line_nr - 1 + p.error('`$var.name` is declared mutable, but it was never changed') + } } } @@ -555,7 +569,10 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin if receiver.is_mut && !p.expr_var.is_mut { println('$method_call recv=$receiver.name recv_mut=$receiver.is_mut') p.error('`$p.expr_var.name` is immutable') - } + } + if !p.expr_var.is_changed { + p.cur_fn.mark_var_changed(p.expr_var) + } // if receiver is key_mut or a ref (&), generate & for the first arg if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) { method_call += '& /* ? */' diff --git a/compiler/main.v b/compiler/main.v index 60794ba80a..76e13cd6db 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -639,7 +639,7 @@ fn (c &V) cc_windows_cross() { mut obj_name := c.out_name obj_name = obj_name.replace('.exe', '') obj_name = obj_name.replace('.o.o', '.o') - mut include := '-I $winroot/include ' + include := '-I $winroot/include ' cmd := 'clang -o $obj_name -w $include -DUNICODE -D_UNICODE -m32 -c -target x86_64-win32 $ModPath/$c.out_name_c' if c.pref.show_c_cmd { println(cmd) @@ -1259,7 +1259,7 @@ fn run_repl() []string { } else { lines << line - mut vals := s.split('\n') + vals := s.split('\n') for i:=0; i `str_typ` is `Company` fn (p mut Parser) dot(str_typ string, method_ph int) string { p.check(.dot) - mut field_name := p.lit + field_name := p.lit p.fgen(field_name) p.log('dot() field_name=$field_name typ=$str_typ') //if p.fileis('main.v') { @@ -1713,7 +1719,7 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string { return field.typ } // method - mut method := p.table.find_method(typ, field_name) + method := p.table.find_method(typ, field_name) p.fn_call(method, method_ph, '', str_typ) // Methods returning `array` should return `array_string` if method.typ == 'array' && typ.name.starts_with('array_') { @@ -1956,6 +1962,9 @@ fn (p mut Parser) expression() string { if !p.expr_var.is_mut && !p.pref.translated { p.error('`$p.expr_var.name` is immutable (can\'t <<)') } + if !p.expr_var.is_changed { + p.cur_fn.mark_var_changed(p.expr_var) + } expr_type := p.expression() // Two arrays of the same type? push_array := typ == expr_type @@ -3092,6 +3101,7 @@ fn (p mut Parser) for_st() { typ: 'int' // parent_fn: p.cur_fn is_mut: true + is_changed: true } p.register_var(i_var) p.genln(';\nfor (int $i = 0; $i < $tmp .len; $i ++) {') @@ -3102,6 +3112,7 @@ fn (p mut Parser) for_st() { name: i typ: 'string' is_mut: true + is_changed: true } p.register_var(i_var) p.genln('array_string keys_$tmp = map_keys(& $tmp ); ') @@ -3159,6 +3170,7 @@ fn (p mut Parser) for_st() { name: val typ: var_type ptr: typ.contains('*') + is_changed: true } p.register_var(val_var) i := p.get_tmp() @@ -3348,7 +3360,7 @@ fn (p mut Parser) go_statement() { p.next() p.check(.dot) typ := p.table.find_type(v.typ) - mut method := p.table.find_method(typ, p.lit) + method := p.table.find_method(typ, p.lit) p.async_fn_call(method, 0, var_name, v.typ) } // Normal function diff --git a/compiler/table.v b/compiler/table.v index 1d76f6835c..b5d3d318ea 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -695,11 +695,10 @@ fn (table &Table) qualify_module(mod string, file_path string) string { } fn new_file_import_table(file_path string) *FileImportTable { - mut t := &FileImportTable{ + return &FileImportTable{ file_path: file_path imports: map[string]string{} } - return t } fn (fit &FileImportTable) known_import(mod string) bool {