checker: fix mut check bypass with for in loops (#12208)
							parent
							
								
									e6b7ab8b9d
								
							
						
					
					
						commit
						fd3a10ab43
					
				|  | @ -121,7 +121,8 @@ pub fn new_checker(table &ast.Table, pref &pref.Preferences) &Checker { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (mut c Checker) check(ast_file &ast.File) { | ||||
| pub fn (mut c Checker) check(ast_file_ &ast.File) { | ||||
| 	mut ast_file := ast_file_ | ||||
| 	c.change_current_file(ast_file) | ||||
| 	for i, ast_import in ast_file.imports { | ||||
| 		for sym in ast_import.syms { | ||||
|  | @ -212,7 +213,7 @@ pub fn (mut c Checker) check_files(ast_files []&ast.File) { | |||
| 	mut has_main_fn := false | ||||
| 	mut files_from_main_module := []&ast.File{} | ||||
| 	for i in 0 .. ast_files.len { | ||||
| 		file := unsafe { ast_files[i] } | ||||
| 		mut file := unsafe { ast_files[i] } | ||||
| 		c.timers.start('checker_check $file.path') | ||||
| 		c.check(file) | ||||
| 		if file.mod.name == 'main' { | ||||
|  | @ -5092,6 +5093,13 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { | |||
| 					ast.MapInit { | ||||
| 						c.error('map literal is immutable, it cannot be changed', node.cond.pos) | ||||
| 					} | ||||
| 					ast.SelectorExpr { | ||||
| 						root_ident := node.cond.root_ident() or { node.cond.expr as ast.Ident } | ||||
| 						if !(root_ident.obj as ast.Var).is_mut { | ||||
| 							c.error('field `$node.cond.field_name` is immutable, it cannot be changed', | ||||
| 								node.cond.pos) | ||||
| 						} | ||||
| 					} | ||||
| 					else {} | ||||
| 				} | ||||
| 			} | ||||
|  | @ -5199,7 +5207,7 @@ fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) { | |||
| 	mut aliases := c.asm_ios(stmt.output, mut stmt.scope, true) | ||||
| 	aliases2 := c.asm_ios(stmt.input, mut stmt.scope, false) | ||||
| 	aliases << aliases2 | ||||
| 	for template in stmt.templates { | ||||
| 	for mut template in stmt.templates { | ||||
| 		if template.is_directive { | ||||
| 			/* | ||||
| 			align n[,value] | ||||
|  |  | |||
|  | @ -5,4 +5,4 @@ use `_` if you do not need the variable | |||
|     3 |     for k in kvs { | ||||
|       |         ^ | ||||
|     4 |         println('$k') | ||||
|     5 |     } | ||||
|     5 |     } | ||||
|  |  | |||
|  | @ -39,4 +39,11 @@ vlib/v/checker/tests/for_in_mut_val_type.vv:20:18: error: map literal is immutab | |||
|    20 |     for _, mut j in {'aa': 1, 'bb': 2} { | ||||
|       |                     ~~~~~~~~~~~~~~~~~~ | ||||
|    21 |         j *= 2 | ||||
|    22 |     } | ||||
|    22 |     } | ||||
| vlib/v/checker/tests/for_in_mut_val_type.vv:30:17: error: field `a` is immutable, it cannot be changed | ||||
|    28 | | ||||
|    29 | fn foo(t Test) { | ||||
|    30 |     for mut e in t.a { | ||||
|       |                    ^ | ||||
|    31 |         e = 0 | ||||
|    32 |     } | ||||
|  |  | |||
|  | @ -21,3 +21,13 @@ fn main() { | |||
| 		j *= 2 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct Test { | ||||
| 	a []int = [1, 2] | ||||
| } | ||||
| 
 | ||||
| fn foo(t Test) { | ||||
| 	for mut e in t.a { | ||||
| 		e = 0 | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -5634,7 +5634,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { | |||
| 		g.go_back_out(3) | ||||
| 		return | ||||
| 	} | ||||
| 	sym := g.table.get_final_type_symbol(g.unwrap_generic(struct_init.typ)) | ||||
| 	mut sym := g.table.get_final_type_symbol(g.unwrap_generic(struct_init.typ)) | ||||
| 	is_amp := g.is_amp | ||||
| 	is_multiline := struct_init.fields.len > 5 | ||||
| 	g.is_amp = false // reset the flag immediately so that other struct inits in this expr are handled correctly
 | ||||
|  | @ -5721,7 +5721,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { | |||
| 	// `inited_fields` is a list of fields that have been init'ed, they are skipped
 | ||||
| 	mut nr_fields := 1 | ||||
| 	if sym.kind == .struct_ { | ||||
| 		info := sym.info as ast.Struct | ||||
| 		mut info := sym.info as ast.Struct | ||||
| 		nr_fields = info.fields.len | ||||
| 		if info.is_union && struct_init.fields.len > 1 { | ||||
| 			verror('union must not have more than 1 initializer') | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ pub mut: | |||
| } | ||||
| 
 | ||||
| fn test_for_in_mut_reference_selector_val() { | ||||
| 	bb := BB{ | ||||
| 	mut bb := BB{ | ||||
| 		arr: [&AA{ | ||||
| 			id: 'Test1' | ||||
| 		}, &AA{ | ||||
|  |  | |||
|  | @ -15,12 +15,12 @@ pub fn new_transformer(pref &pref.Preferences) &Transformer { | |||
| 
 | ||||
| pub fn (t Transformer) transform_files(ast_files []&ast.File) { | ||||
| 	for i in 0 .. ast_files.len { | ||||
| 		file := unsafe { ast_files[i] } | ||||
| 		t.transform(file) | ||||
| 		mut file := unsafe { ast_files[i] } | ||||
| 		t.transform(mut file) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (t Transformer) transform(ast_file &ast.File) { | ||||
| pub fn (t Transformer) transform(mut ast_file ast.File) { | ||||
| 	for mut stmt in ast_file.stmts { | ||||
| 		t.stmt(mut stmt) | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue