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) | 	c.change_current_file(ast_file) | ||||||
| 	for i, ast_import in ast_file.imports { | 	for i, ast_import in ast_file.imports { | ||||||
| 		for sym in ast_import.syms { | 		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 has_main_fn := false | ||||||
| 	mut files_from_main_module := []&ast.File{} | 	mut files_from_main_module := []&ast.File{} | ||||||
| 	for i in 0 .. ast_files.len { | 	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.timers.start('checker_check $file.path') | ||||||
| 		c.check(file) | 		c.check(file) | ||||||
| 		if file.mod.name == 'main' { | 		if file.mod.name == 'main' { | ||||||
|  | @ -5092,6 +5093,13 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { | ||||||
| 					ast.MapInit { | 					ast.MapInit { | ||||||
| 						c.error('map literal is immutable, it cannot be changed', node.cond.pos) | 						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 {} | 					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) | 	mut aliases := c.asm_ios(stmt.output, mut stmt.scope, true) | ||||||
| 	aliases2 := c.asm_ios(stmt.input, mut stmt.scope, false) | 	aliases2 := c.asm_ios(stmt.input, mut stmt.scope, false) | ||||||
| 	aliases << aliases2 | 	aliases << aliases2 | ||||||
| 	for template in stmt.templates { | 	for mut template in stmt.templates { | ||||||
| 		if template.is_directive { | 		if template.is_directive { | ||||||
| 			/* | 			/* | ||||||
| 			align n[,value] | 			align n[,value] | ||||||
|  |  | ||||||
|  | @ -40,3 +40,10 @@ vlib/v/checker/tests/for_in_mut_val_type.vv:20:18: error: map literal is immutab | ||||||
|       |                     ~~~~~~~~~~~~~~~~~~ |       |                     ~~~~~~~~~~~~~~~~~~ | ||||||
|    21 |         j *= 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 | 		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) | 		g.go_back_out(3) | ||||||
| 		return | 		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_amp := g.is_amp | ||||||
| 	is_multiline := struct_init.fields.len > 5 | 	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
 | 	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
 | 	// `inited_fields` is a list of fields that have been init'ed, they are skipped
 | ||||||
| 	mut nr_fields := 1 | 	mut nr_fields := 1 | ||||||
| 	if sym.kind == .struct_ { | 	if sym.kind == .struct_ { | ||||||
| 		info := sym.info as ast.Struct | 		mut info := sym.info as ast.Struct | ||||||
| 		nr_fields = info.fields.len | 		nr_fields = info.fields.len | ||||||
| 		if info.is_union && struct_init.fields.len > 1 { | 		if info.is_union && struct_init.fields.len > 1 { | ||||||
| 			verror('union must not have more than 1 initializer') | 			verror('union must not have more than 1 initializer') | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ pub mut: | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn test_for_in_mut_reference_selector_val() { | fn test_for_in_mut_reference_selector_val() { | ||||||
| 	bb := BB{ | 	mut bb := BB{ | ||||||
| 		arr: [&AA{ | 		arr: [&AA{ | ||||||
| 			id: 'Test1' | 			id: 'Test1' | ||||||
| 		}, &AA{ | 		}, &AA{ | ||||||
|  |  | ||||||
|  | @ -15,12 +15,12 @@ pub fn new_transformer(pref &pref.Preferences) &Transformer { | ||||||
| 
 | 
 | ||||||
| pub fn (t Transformer) transform_files(ast_files []&ast.File) { | pub fn (t Transformer) transform_files(ast_files []&ast.File) { | ||||||
| 	for i in 0 .. ast_files.len { | 	for i in 0 .. ast_files.len { | ||||||
| 		file := unsafe { ast_files[i] } | 		mut file := unsafe { ast_files[i] } | ||||||
| 		t.transform(file) | 		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 { | 	for mut stmt in ast_file.stmts { | ||||||
| 		t.stmt(mut stmt) | 		t.stmt(mut stmt) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue