mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
do not allow declaring a mutable variable if it's never modified
This commit is contained in:
parent
dbf027acb8
commit
9ccd3bde01
@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -556,6 +570,9 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
|
||||
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 += '& /* ? */'
|
||||
|
@ -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<vals.len-1; i++ {
|
||||
println(vals[i])
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ mut:
|
||||
access_mod AccessMod
|
||||
is_global bool // __global (translated from C only)
|
||||
is_used bool
|
||||
is_changed bool
|
||||
scope_level int
|
||||
}
|
||||
|
||||
@ -708,7 +709,7 @@ fn (p mut Parser) check_space(expected Token) {
|
||||
fn (p mut Parser) check(expected Token) {
|
||||
if p.tok != expected {
|
||||
println('check()')
|
||||
mut s := 'expected `${expected.str()}` but got `${p.strtok()}`'
|
||||
s := 'expected `${expected.str()}` but got `${p.strtok()}`'
|
||||
p.next()
|
||||
println('next token = `${p.strtok()}`')
|
||||
print_backtrace()
|
||||
@ -1158,6 +1159,9 @@ fn (p mut Parser) assign_statement(v Var, ph int, is_map bool) {
|
||||
if !v.is_mut && !v.is_arg && !p.pref.translated && !v.is_global{
|
||||
p.error('`$v.name` is immutable')
|
||||
}
|
||||
if !v.is_changed {
|
||||
p.cur_fn.mark_var_changed(v)
|
||||
}
|
||||
is_str := v.typ == 'string'
|
||||
switch tok {
|
||||
case Token.assign:
|
||||
@ -1263,10 +1267,9 @@ fn (p mut Parser) var_decl() {
|
||||
is_mut: is_mut
|
||||
is_alloc: p.is_alloc
|
||||
})
|
||||
mut cgen_typ := typ
|
||||
if !or_else {
|
||||
gen_name := p.table.var_cgen_name(name)
|
||||
mut nt_gen := p.table.cgen_name_type_pair(gen_name, cgen_typ) + '='
|
||||
mut nt_gen := p.table.cgen_name_type_pair(gen_name, typ) + '='
|
||||
if is_static {
|
||||
nt_gen = 'static $nt_gen'
|
||||
}
|
||||
@ -1502,7 +1505,7 @@ fn (p mut Parser) name_expr() string {
|
||||
return cfn.typ
|
||||
}
|
||||
// Constant
|
||||
mut c := p.table.find_const(name)
|
||||
c := p.table.find_const(name)
|
||||
if c.name != '' && ptr && !c.is_global {
|
||||
p.error('cannot take the address of constant `$c.name`')
|
||||
}
|
||||
@ -1614,6 +1617,9 @@ fn (p mut Parser) var_expr(v Var) string {
|
||||
if !v.is_mut && !v.is_arg && !p.pref.translated {
|
||||
p.error('`$v.name` is immutable')
|
||||
}
|
||||
if !v.is_changed {
|
||||
p.cur_fn.mark_var_changed(v)
|
||||
}
|
||||
if typ != 'int' {
|
||||
if !p.pref.translated && !is_number_type(typ) {
|
||||
p.error('cannot ++/-- value of type `$typ`')
|
||||
@ -1649,7 +1655,7 @@ fn (p &Parser) fileis(s string) bool {
|
||||
// user.company.name => `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
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user