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