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]
|
||||||
|
|
|
@ -5,4 +5,4 @@ use `_` if you do not need the variable
|
||||||
3 | for k in kvs {
|
3 | for k in kvs {
|
||||||
| ^
|
| ^
|
||||||
4 | println('$k')
|
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} {
|
20 | for _, mut j in {'aa': 1, 'bb': 2} {
|
||||||
| ~~~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~~
|
||||||
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