checker: error if variable used before declaration
parent
1d8d19c977
commit
ddd83f1fc6
|
@ -62,20 +62,33 @@ pub fn (mut c Checker) check(ast_file ast.File) {
|
|||
c.expr_level = 0
|
||||
c.stmt(stmt)
|
||||
}
|
||||
// Check scopes
|
||||
// TODO
|
||||
/*
|
||||
for i, obj in c.file.global_scope.objects {
|
||||
c.check_scope_vars(c.file.scope)
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) check_scope_vars(sc &ast.Scope) {
|
||||
for _, obj in sc.objects {
|
||||
match obj {
|
||||
ast.Var {
|
||||
if it.is_mut && !it.is_changed {
|
||||
c.warn('`$it.name` is declared as mutable, but it was never changed', it.pos)
|
||||
if !c.pref.is_repl {
|
||||
if !obj.is_used && obj.name[0] != `_` {
|
||||
if c.pref.is_prod {
|
||||
c.error('unused variable: `$obj.name`', obj.pos)
|
||||
} else {
|
||||
c.warn('unused variable: `$obj.name`', obj.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: fix all of these warnings
|
||||
// if obj.is_mut && !obj.is_changed {
|
||||
// c.warn('`$obj.name` is declared as mutable, but it was never changed', obj.pos)
|
||||
// }
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
*/
|
||||
for _, child in sc.children {
|
||||
c.check_scope_vars(child)
|
||||
}
|
||||
}
|
||||
|
||||
// not used right now
|
||||
|
@ -1917,12 +1930,10 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
ast.ComptimeCall {
|
||||
node.sym = c.table.get_type_symbol(c.unwrap_generic(c.expr(node.left)))
|
||||
if node.is_vweb {
|
||||
x := *c.pref
|
||||
xx := {
|
||||
x |
|
||||
is_vweb: true
|
||||
} // TODO assoc parser bug
|
||||
mut c2 := new_checker(c.table, xx)
|
||||
// TODO assoc parser bug
|
||||
pref := *c.pref
|
||||
pref2 := {pref|is_vweb: true}
|
||||
mut c2 := new_checker(c.table, pref2)
|
||||
c2.check(node.vweb_tmpl)
|
||||
c.warnings << c2.warnings
|
||||
c.errors << c2.errors
|
||||
|
@ -2088,6 +2099,11 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
|||
return obj.typ
|
||||
}
|
||||
ast.Var {
|
||||
// incase var was not marked as used yet (vweb tmpl)
|
||||
obj.is_used = true
|
||||
if ident.pos.pos < obj.pos.pos {
|
||||
c.error('undefined variable `$ident.name` (used before declaration)', ident.pos)
|
||||
}
|
||||
mut typ := obj.typ
|
||||
if typ == 0 {
|
||||
if obj.expr is ast.Ident {
|
||||
|
|
|
@ -1,27 +1,13 @@
|
|||
vlib/v/checker/tests/run/assign_expr_unresolved_variables_err_chain.v:3:2: warning: unused variable: `b`
|
||||
1 | fn main() {
|
||||
2 | a := b
|
||||
3 | b := c
|
||||
| ^
|
||||
4 | c := a
|
||||
5 | }
|
||||
vlib/v/checker/tests/run/assign_expr_unresolved_variables_err_chain.v:4:2: warning: unused variable: `c`
|
||||
2 | a := b
|
||||
3 | b := c
|
||||
4 | c := a
|
||||
| ^
|
||||
5 | }
|
||||
vlib/v/checker/tests/run/assign_expr_unresolved_variables_err_chain.v:2:7: error: unresolved variable: `b`
|
||||
vlib/v/checker/tests/run/assign_expr_unresolved_variables_err_chain.v:2:7: error: undefined variable `b` (used before declaration)
|
||||
1 | fn main() {
|
||||
2 | a := b
|
||||
| ^
|
||||
3 | b := c
|
||||
4 | c := a
|
||||
vlib/v/checker/tests/run/assign_expr_unresolved_variables_err_chain.v:3:7: error: unresolved variable: `c`
|
||||
vlib/v/checker/tests/run/assign_expr_unresolved_variables_err_chain.v:3:7: error: undefined variable `c` (used before declaration)
|
||||
1 | fn main() {
|
||||
2 | a := b
|
||||
3 | b := c
|
||||
| ^
|
||||
4 | c := a
|
||||
5 | }
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/var_used_before_declaration.v:2:13: error: undefined variable `x` (used before declaration)
|
||||
1 | fn main() {
|
||||
2 | println(x)
|
||||
| ^
|
||||
3 | x := 'hello v'
|
||||
4 | }
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
println(x)
|
||||
x := 'hello v'
|
||||
}
|
|
@ -107,7 +107,7 @@ fn (mut p Parser) vweb() ast.ComptimeCall {
|
|||
start_pos: 0
|
||||
parent: p.global_scope
|
||||
}
|
||||
file := parse_text(v_code, p.table, p.pref, scope, p.global_scope)
|
||||
mut file := parse_text(v_code, p.table, p.pref, scope, p.global_scope)
|
||||
if p.pref.is_verbose {
|
||||
println('\n\n')
|
||||
println('>>> vweb template for ${path}:')
|
||||
|
@ -115,6 +115,7 @@ fn (mut p Parser) vweb() ast.ComptimeCall {
|
|||
println('>>> end of vweb template END')
|
||||
println('\n\n')
|
||||
}
|
||||
file = {file| path:html_name}
|
||||
// copy vars from current fn scope into vweb_tmpl scope
|
||||
for stmt in file.stmts {
|
||||
if stmt is ast.FnDecl {
|
||||
|
@ -124,12 +125,11 @@ fn (mut p Parser) vweb() ast.ComptimeCall {
|
|||
for _, obj in p.scope.objects {
|
||||
if obj is ast.Var {
|
||||
mut v := obj as ast.Var
|
||||
v.pos = fn_decl.body_pos
|
||||
tmpl_scope.register(v.name, *v)
|
||||
// TODO: this is yuck, track idents in parser
|
||||
// or defer unused var logic to checker
|
||||
if v_code.contains(v.name) {
|
||||
v.is_used = true
|
||||
}
|
||||
// set the controller action var to used
|
||||
// if its unused in the template it will warn
|
||||
v.is_used = true
|
||||
}
|
||||
}
|
||||
break
|
||||
|
|
|
@ -275,29 +275,6 @@ pub fn (mut p Parser) open_scope() {
|
|||
}
|
||||
|
||||
pub fn (mut p Parser) close_scope() {
|
||||
// TODO move this to checker since is_changed is set there?
|
||||
if !p.pref.is_repl && !p.scanner.is_fmt {
|
||||
for _, obj in p.scope.objects {
|
||||
match obj {
|
||||
ast.Var {
|
||||
if !obj.is_used && obj.name[0] != `_` {
|
||||
if p.pref.is_prod {
|
||||
p.error_with_pos('unused variable: `$obj.name`', obj.pos)
|
||||
} else {
|
||||
p.warn_with_pos('unused variable: `$obj.name`', obj.pos)
|
||||
}
|
||||
}
|
||||
/*
|
||||
if it.is_mut && !it.is_changed {
|
||||
p.warn_with_pos('`$it.name` is declared as mutable, but it was never changed',
|
||||
it.pos)
|
||||
}
|
||||
*/
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
p.scope.end_pos = p.tok.pos
|
||||
p.scope.parent.children << p.scope
|
||||
p.scope = p.scope.parent
|
||||
|
|
Loading…
Reference in New Issue