From 682838a0cf42d3364aa9e69192ac50245df8c4a2 Mon Sep 17 00:00:00 2001 From: Enzo Baldisserri Date: Mon, 27 Apr 2020 22:53:26 +0200 Subject: [PATCH] checker: check array and fields mutability --- cmd/tools/vtest-fixed.v | 4 +- vlib/bitfield/bitfield_test.v | 4 +- vlib/builtin/array.v | 3 +- vlib/builtin/builtin_windows.c.v | 1 + vlib/builtin/map_test.v | 3 +- vlib/builtin/string.v | 2 +- vlib/flag/flag.v | 2 +- vlib/rand/random_numbers_test.v | 2 +- vlib/time/stopwatch.v | 3 +- vlib/v/ast/ast.v | 23 ++--- vlib/v/ast/str.v | 2 +- vlib/v/builder/builder.v | 2 +- vlib/v/checker/checker.v | 85 ++++++++++++------- .../tests/immutable_array_field_assign.out | 6 ++ .../tests/immutable_array_field_assign.v | 10 +++ .../tests/immutable_array_field_assign.vv | 10 +++ .../tests/immutable_array_field_shift.out | 6 ++ .../tests/immutable_array_field_shift.v | 15 ++++ .../tests/immutable_array_field_shift.vv | 15 ++++ .../tests/immutable_array_struct_assign.out | 6 ++ .../tests/immutable_array_struct_assign.v | 9 ++ .../tests/immutable_array_struct_assign.vv | 9 ++ .../tests/immutable_array_struct_shift.out | 6 ++ .../tests/immutable_array_struct_shift.v | 9 ++ .../tests/immutable_array_struct_shift.vv | 9 ++ vlib/v/checker/tests/immutable_array_var.out | 6 ++ vlib/v/checker/tests/immutable_array_var.v | 4 + vlib/v/checker/tests/immutable_array_var.vv | 4 + vlib/v/checker/tests/immutable_field.out | 6 ++ vlib/v/checker/tests/immutable_field.v | 9 ++ vlib/v/checker/tests/immutable_field.vv | 9 ++ vlib/v/checker/tests/immutable_var.out | 6 ++ vlib/v/checker/tests/immutable_var.v | 4 + vlib/v/checker/tests/immutable_var.vv | 4 + vlib/v/checker/tests/left_shift_err.out | 2 +- vlib/v/checker/tests/left_shift_err.v | 2 +- vlib/v/checker/tests/left_shift_err.vv | 2 +- vlib/v/checker/tests/struct_pub_field.out | 6 ++ vlib/v/checker/tests/struct_pub_field.v | 10 +++ vlib/v/checker/tests/struct_pub_field.vv | 10 +++ vlib/v/gen/cgen.v | 2 +- vlib/v/gen/js/js.v | 16 ++-- vlib/v/gen/profile.v | 1 - vlib/v/parser/fn.v | 2 +- vlib/v/parser/if.v | 9 +- vlib/v/parser/parser.v | 7 +- vlib/v/parser/pratt.v | 4 +- vlib/v/parser/struct.v | 18 ++++ vlib/v/table/atypes.v | 28 ++++++ vlib/v/table/cflags_test.v | 2 +- vlib/v/table/table.v | 5 +- vlib/v/util/scanning.v | 2 +- 52 files changed, 340 insertions(+), 86 deletions(-) create mode 100644 vlib/v/checker/tests/immutable_array_field_assign.out create mode 100644 vlib/v/checker/tests/immutable_array_field_assign.v create mode 100644 vlib/v/checker/tests/immutable_array_field_assign.vv create mode 100644 vlib/v/checker/tests/immutable_array_field_shift.out create mode 100644 vlib/v/checker/tests/immutable_array_field_shift.v create mode 100644 vlib/v/checker/tests/immutable_array_field_shift.vv create mode 100644 vlib/v/checker/tests/immutable_array_struct_assign.out create mode 100644 vlib/v/checker/tests/immutable_array_struct_assign.v create mode 100644 vlib/v/checker/tests/immutable_array_struct_assign.vv create mode 100644 vlib/v/checker/tests/immutable_array_struct_shift.out create mode 100644 vlib/v/checker/tests/immutable_array_struct_shift.v create mode 100644 vlib/v/checker/tests/immutable_array_struct_shift.vv create mode 100644 vlib/v/checker/tests/immutable_array_var.out create mode 100644 vlib/v/checker/tests/immutable_array_var.v create mode 100644 vlib/v/checker/tests/immutable_array_var.vv create mode 100644 vlib/v/checker/tests/immutable_field.out create mode 100644 vlib/v/checker/tests/immutable_field.v create mode 100644 vlib/v/checker/tests/immutable_field.vv create mode 100644 vlib/v/checker/tests/immutable_var.out create mode 100644 vlib/v/checker/tests/immutable_var.v create mode 100644 vlib/v/checker/tests/immutable_var.vv create mode 100644 vlib/v/checker/tests/struct_pub_field.out create mode 100644 vlib/v/checker/tests/struct_pub_field.v create mode 100644 vlib/v/checker/tests/struct_pub_field.vv diff --git a/cmd/tools/vtest-fixed.v b/cmd/tools/vtest-fixed.v index b25e4d3f68..6944530456 100644 --- a/cmd/tools/vtest-fixed.v +++ b/cmd/tools/vtest-fixed.v @@ -24,8 +24,8 @@ const ( 'vlib/v/tests/live_test.v', // Linux & Solaris only; since live does not actually work for now with v2, just skip 'vlib/v/tests/asm_test.v', // skip everywhere for now, works on linux with cc != tcc ] - skip_on_linux = []string - skip_on_non_linux = []string + skip_on_linux = []string{} + skip_on_non_linux = []string{} ) fn main() { diff --git a/vlib/bitfield/bitfield_test.v b/vlib/bitfield/bitfield_test.v index b2193d377a..f4deef8af6 100644 --- a/vlib/bitfield/bitfield_test.v +++ b/vlib/bitfield/bitfield_test.v @@ -141,7 +141,7 @@ fn test_bf_from_str() { rand.seed(time.now().unix) len := 80 mut input := '' - for i in 0..len { + for _ in 0..len { if rand.next(2) == 1 { input = input + '1' } @@ -244,7 +244,7 @@ fn test_bf_resize() { rand.seed(time.now().unix) len := 80 mut input := bitfield.new(rand.next(len) + 1) - for i in 0..100 { + for _ in 0..100 { input.resize(rand.next(len) + 1) input.setbit(input.getsize() - 1) } diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index b3ddbf7681..56aa9991d6 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -7,11 +7,12 @@ import strings pub struct array { pub: + element_size int +pub mut: data voidptr// Using a void pointer allows to implement arrays without generics and without generating // extra code for every type. len int cap int - element_size int } // Internal function, used by V (`nums := []int`) diff --git a/vlib/builtin/builtin_windows.c.v b/vlib/builtin/builtin_windows.c.v index 1a774616b7..9d75a032d4 100644 --- a/vlib/builtin/builtin_windows.c.v +++ b/vlib/builtin/builtin_windows.c.v @@ -33,6 +33,7 @@ pub mut: } pub struct Line64 { +pub mut: f_size_of_struct u32 f_key voidptr f_line_number u32 diff --git a/vlib/builtin/map_test.v b/vlib/builtin/map_test.v index b1bb61db91..1474248a5a 100644 --- a/vlib/builtin/map_test.v +++ b/vlib/builtin/map_test.v @@ -5,6 +5,7 @@ struct User { } struct A { +mut: m map[string]int users map[string]User } @@ -24,7 +25,7 @@ fn test_map() { assert 'hi' in m mut sum := 0 // Test `for in` - for key, val in m { + for _, val in m { sum += val } assert sum == 80 + 101 diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 00f42cccc9..efc6c63c13 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -51,7 +51,7 @@ pub: // hash_cache int pub struct ustring { -pub: +pub mut: s string runes []int len int diff --git a/vlib/flag/flag.v b/vlib/flag/flag.v index 5601f895aa..0919a92bfb 100644 --- a/vlib/flag/flag.v +++ b/vlib/flag/flag.v @@ -435,7 +435,7 @@ pub fn (fs FlagParser) usage() string { if fs.flags.len > 0 { use += 'Options:\n' for f in fs.flags { - mut onames:=[]string + mut onames := []string{} if f.abbr != 0 { onames << '-${f.abbr.str()}' } diff --git a/vlib/rand/random_numbers_test.v b/vlib/rand/random_numbers_test.v index 082126acb8..2655964b1e 100644 --- a/vlib/rand/random_numbers_test.v +++ b/vlib/rand/random_numbers_test.v @@ -28,7 +28,7 @@ fn test_rand_r_seed_update() { for _ in 0..rnd_count { prev_seed := seed - res := rand.rand_r(&seed) + _ := rand.rand_r(&seed) assert prev_seed != seed } diff --git a/vlib/time/stopwatch.v b/vlib/time/stopwatch.v index d93b4d2785..9d416efa60 100644 --- a/vlib/time/stopwatch.v +++ b/vlib/time/stopwatch.v @@ -4,8 +4,9 @@ module time pub struct StopWatch { +mut: pause_time u64 -pub: +pub mut: start u64 end u64 } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 1b7d68dd58..f32ca89271 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -134,9 +134,10 @@ mut: pub struct ConstDecl { pub: - fields []ConstField is_pub bool pos token.Position +pub mut: + fields []ConstField } pub struct StructDecl { @@ -162,10 +163,10 @@ pub: pub struct StructInitField { pub: - name string expr Expr pos token.Position mut: + name string typ table.Type expected_type table.Type } @@ -173,10 +174,10 @@ mut: pub struct StructInit { pub: pos token.Position - fields []StructInitField is_short bool mut: typ table.Type + fields []StructInitField } // import statement @@ -198,7 +199,6 @@ pub struct FnDecl { pub: name string stmts []Stmt - return_type table.Type args []table.Arg is_deprecated bool is_pub bool @@ -213,6 +213,8 @@ pub: is_builtin bool // this function is defined in builtin/strconv ctdefine string // has [if myflag] tag pos token.Position +pub mut: + return_type table.Type } pub struct BranchStmt { @@ -224,10 +226,10 @@ pub struct CallExpr { pub: pos token.Position left Expr // `user` in `user.register()` - is_method bool mod string mut: name string + is_method bool args []CallArg expected_arg_types []table.Type is_c bool @@ -292,10 +294,11 @@ pub struct File { pub: path string mod Module - imports []Import stmts []Stmt scope &Scope global_scope &Scope +mut: + imports []Import } pub struct IdentFn { @@ -331,11 +334,11 @@ pub: tok_kind token.Kind mod string pos token.Position - is_mut bool mut: name string kind IdentKind info IdentInfo + is_mut bool } pub fn (i &Ident) var_info() IdentVar { @@ -508,11 +511,11 @@ pub: pub struct AssignStmt { pub: - left []Ident right []Expr op token.Kind pos token.Position -mut: +pub mut: + left []Ident left_types []table.Type right_types []table.Type is_static bool // for translated code only @@ -670,8 +673,8 @@ pub: expr Expr // `buf` arg Expr // `n` in `string(buf, n)` typ table.Type // `string` - typname string mut: + typname string expr_type table.Type // `byteptr` has_arg bool } diff --git a/vlib/v/ast/str.v b/vlib/v/ast/str.v index 83eb33c89c..635c9ad0cb 100644 --- a/vlib/v/ast/str.v +++ b/vlib/v/ast/str.v @@ -121,7 +121,7 @@ pub fn (x Expr) str() string { return '${it.expr.str()}.${it.field}' } StringInterLiteral { - res := []string{} + mut res := []string{} res << "'" for i, val in it.vals { res << val diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v index f9e243adcd..25b60813ba 100644 --- a/vlib/v/builder/builder.v +++ b/vlib/v/builder/builder.v @@ -17,12 +17,12 @@ import v.depgraph pub struct Builder { pub: - pref &pref.Preferences table &table.Table checker checker.Checker compiled_dir string // contains os.real_path() of the dir of the final file beeing compiled, or the dir itself when doing `v .` module_path string mut: + pref &pref.Preferences module_search_paths []string parsed_files []ast.File global_scope &ast.Scope diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index e3c84d04bb..7ef277e4d9 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -364,11 +364,7 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { .left_shift { if left.kind == .array { // `array << elm` - match infix_expr.left { - ast.Ident {} - ast.SelectorExpr {} - else { println('typeof: ${typeof(infix_expr.left)}') } - } + c.fail_if_immutable(infix_expr.left) // the expressions have different types (array_x and x) if c.table.check(c.table.value_type(left_type), right_type) { // []T << T @@ -446,6 +442,58 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { } } +fn (mut c Checker) fail_if_immutable(expr ast.Expr) { + match expr { + ast.Ident { + scope := c.file.scope.innermost(expr.position().pos) + if v := scope.find_var(it.name) { + if !v.is_mut && !v.typ.is_ptr() { + c.error('`$it.name` is immutable, declare it with `mut` to make it mutable', + it.pos) + } + } + } + ast.IndexExpr { + c.fail_if_immutable(it.left) + } + ast.ParExpr { + c.fail_if_immutable(it.expr) + } + ast.PrefixExpr { + c.fail_if_immutable(it.right) + } + ast.SelectorExpr { + // retrieve table.Field + typ_sym := c.table.get_type_symbol(it.expr_type) + match typ_sym.kind { + .struct_ { + struct_info := typ_sym.info as table.Struct + field_info := struct_info.get_field(it.field) + if !field_info.is_mut { + type_str := c.table.type_to_str(it.expr_type) + c.error('field `$it.field` of struct `${type_str}` is immutable', it.pos) + } + c.fail_if_immutable(it.expr) + } + .array, .string { + // This should only happen in `builtin` + // TODO Remove `crypto.rand` when possible (see vlib/crypto/rand/rand.v, + // if `c_array_to_bytes_tmp` doesn't exist, then it's safe to remove it) + if c.file.mod.name !in ['builtin', 'crypto.rand'] { + c.error('`$typ_sym.kind` can not be modified', expr.position()) + } + } + else { + c.error('unexpected symbol `${typ_sym.kind}`', expr.position()) + } + } + } + else { + c.error('unexpected expression `${typeof(expr)}`', expr.position()) + } + } +} + fn (mut c Checker) assign_expr(assign_expr mut ast.AssignExpr) { c.expected_type = table.void_type left_type := c.expr(assign_expr.left) @@ -460,32 +508,7 @@ fn (mut c Checker) assign_expr(assign_expr mut ast.AssignExpr) { return } // Make sure the variable is mutable - match assign_expr.left { - ast.Ident { - scope := c.file.scope.innermost(assign_expr.pos.pos) - if v := scope.find_var(it.name) { - if !v.is_mut { - c.error('`$it.name` is immutable, declare it with `mut` to assign to it', - assign_expr.pos) - } - } - } - ast.IndexExpr { - // `m[key] = val` - if it.left is ast.Ident { - ident := it.left as ast.Ident - // TODO copy pasta - scope := c.file.scope.innermost(assign_expr.pos.pos) - if v := scope.find_var(ident.name) { - if !v.is_mut { - c.error('`$ident.name` is immutable, declare it with `mut` to assign to it', - assign_expr.pos) - } - } - } - } - else {} - } + c.fail_if_immutable(assign_expr.left) // Single side check match assign_expr.op { .assign {} // No need to do single side check for =. But here put it first for speed. diff --git a/vlib/v/checker/tests/immutable_array_field_assign.out b/vlib/v/checker/tests/immutable_array_field_assign.out new file mode 100644 index 0000000000..047d342c8a --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_field_assign.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/immutable_array_field_assign.v:9:4: error: field `i` of struct `A` is immutable + 7| i: [0] + 8| } + 9| a.i[0] = 3 + ^ + 10| } diff --git a/vlib/v/checker/tests/immutable_array_field_assign.v b/vlib/v/checker/tests/immutable_array_field_assign.v new file mode 100644 index 0000000000..1dbe3759be --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_field_assign.v @@ -0,0 +1,10 @@ +struct A { + i []int +} + +fn main() { + mut a := A{ + i: [0] + } + a.i[0] = 3 +} diff --git a/vlib/v/checker/tests/immutable_array_field_assign.vv b/vlib/v/checker/tests/immutable_array_field_assign.vv new file mode 100644 index 0000000000..1dbe3759be --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_field_assign.vv @@ -0,0 +1,10 @@ +struct A { + i []int +} + +fn main() { + mut a := A{ + i: [0] + } + a.i[0] = 3 +} diff --git a/vlib/v/checker/tests/immutable_array_field_shift.out b/vlib/v/checker/tests/immutable_array_field_shift.out new file mode 100644 index 0000000000..703e5b1e32 --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_field_shift.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/immutable_array_field_shift.v:14:4: error: field `a` of struct `B` is immutable + 12| a: A{} + 13| } + 14| b.a.i << 3 + ^ + 15| } diff --git a/vlib/v/checker/tests/immutable_array_field_shift.v b/vlib/v/checker/tests/immutable_array_field_shift.v new file mode 100644 index 0000000000..9740edd3c5 --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_field_shift.v @@ -0,0 +1,15 @@ +struct A { +mut: + i []int +} + +struct B { + a A +} + +fn main() { + mut b := B{ + a: A{} + } + b.a.i << 3 +} diff --git a/vlib/v/checker/tests/immutable_array_field_shift.vv b/vlib/v/checker/tests/immutable_array_field_shift.vv new file mode 100644 index 0000000000..9740edd3c5 --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_field_shift.vv @@ -0,0 +1,15 @@ +struct A { +mut: + i []int +} + +struct B { + a A +} + +fn main() { + mut b := B{ + a: A{} + } + b.a.i << 3 +} diff --git a/vlib/v/checker/tests/immutable_array_struct_assign.out b/vlib/v/checker/tests/immutable_array_struct_assign.out new file mode 100644 index 0000000000..06cba8ac4a --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_struct_assign.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/immutable_array_struct_assign.v:8:2: error: `a` is immutable, declare it with `mut` to make it mutable + 6| fn main() { + 7| a := A{} + 8| a.i[0] += 3 + ^ + 9| } diff --git a/vlib/v/checker/tests/immutable_array_struct_assign.v b/vlib/v/checker/tests/immutable_array_struct_assign.v new file mode 100644 index 0000000000..e7823eb8ec --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_struct_assign.v @@ -0,0 +1,9 @@ +struct A { +pub mut: + i []int +} + +fn main() { + a := A{} + a.i[0] += 3 +} diff --git a/vlib/v/checker/tests/immutable_array_struct_assign.vv b/vlib/v/checker/tests/immutable_array_struct_assign.vv new file mode 100644 index 0000000000..e7823eb8ec --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_struct_assign.vv @@ -0,0 +1,9 @@ +struct A { +pub mut: + i []int +} + +fn main() { + a := A{} + a.i[0] += 3 +} diff --git a/vlib/v/checker/tests/immutable_array_struct_shift.out b/vlib/v/checker/tests/immutable_array_struct_shift.out new file mode 100644 index 0000000000..dfef405090 --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_struct_shift.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/immutable_array_struct_shift.v:8:2: error: `a` is immutable, declare it with `mut` to make it mutable + 6| fn main() { + 7| a := []A{} + 8| a[0].i << 3 + ^ + 9| } diff --git a/vlib/v/checker/tests/immutable_array_struct_shift.v b/vlib/v/checker/tests/immutable_array_struct_shift.v new file mode 100644 index 0000000000..c89a5a7880 --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_struct_shift.v @@ -0,0 +1,9 @@ +struct A { +pub mut: + i []int +} + +fn main() { + a := []A{} + a[0].i << 3 +} diff --git a/vlib/v/checker/tests/immutable_array_struct_shift.vv b/vlib/v/checker/tests/immutable_array_struct_shift.vv new file mode 100644 index 0000000000..c89a5a7880 --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_struct_shift.vv @@ -0,0 +1,9 @@ +struct A { +pub mut: + i []int +} + +fn main() { + a := []A{} + a[0].i << 3 +} diff --git a/vlib/v/checker/tests/immutable_array_var.out b/vlib/v/checker/tests/immutable_array_var.out new file mode 100644 index 0000000000..397d02991e --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_var.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/immutable_array_var.v:3:2: error: `a` is immutable, declare it with `mut` to make it mutable + 1| fn main() { + 2| a := [1, 2] + 3| a << 3 + ^ + 4| } diff --git a/vlib/v/checker/tests/immutable_array_var.v b/vlib/v/checker/tests/immutable_array_var.v new file mode 100644 index 0000000000..1afa343425 --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_var.v @@ -0,0 +1,4 @@ +fn main() { + a := [1, 2] + a << 3 +} diff --git a/vlib/v/checker/tests/immutable_array_var.vv b/vlib/v/checker/tests/immutable_array_var.vv new file mode 100644 index 0000000000..1afa343425 --- /dev/null +++ b/vlib/v/checker/tests/immutable_array_var.vv @@ -0,0 +1,4 @@ +fn main() { + a := [1, 2] + a << 3 +} diff --git a/vlib/v/checker/tests/immutable_field.out b/vlib/v/checker/tests/immutable_field.out new file mode 100644 index 0000000000..b69fa62cee --- /dev/null +++ b/vlib/v/checker/tests/immutable_field.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/immutable_field.v:8:4: error: field `i1` of struct `A` is immutable + 6| fn main() { + 7| a := A{1} + 8| a.i1 = 2 + ~~ + 9| } diff --git a/vlib/v/checker/tests/immutable_field.v b/vlib/v/checker/tests/immutable_field.v new file mode 100644 index 0000000000..52fea4cd84 --- /dev/null +++ b/vlib/v/checker/tests/immutable_field.v @@ -0,0 +1,9 @@ +struct A { +pub: + i1 int +} + +fn main() { + a := A{1} + a.i1 = 2 +} diff --git a/vlib/v/checker/tests/immutable_field.vv b/vlib/v/checker/tests/immutable_field.vv new file mode 100644 index 0000000000..52fea4cd84 --- /dev/null +++ b/vlib/v/checker/tests/immutable_field.vv @@ -0,0 +1,9 @@ +struct A { +pub: + i1 int +} + +fn main() { + a := A{1} + a.i1 = 2 +} diff --git a/vlib/v/checker/tests/immutable_var.out b/vlib/v/checker/tests/immutable_var.out new file mode 100644 index 0000000000..c64f402365 --- /dev/null +++ b/vlib/v/checker/tests/immutable_var.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/immutable_var.v:3:2: error: `a` is immutable, declare it with `mut` to make it mutable + 1| fn main() { + 2| a := 1 + 3| a = 2 + ^ + 4| } diff --git a/vlib/v/checker/tests/immutable_var.v b/vlib/v/checker/tests/immutable_var.v new file mode 100644 index 0000000000..d83612c7b8 --- /dev/null +++ b/vlib/v/checker/tests/immutable_var.v @@ -0,0 +1,4 @@ +fn main() { + a := 1 + a = 2 +} diff --git a/vlib/v/checker/tests/immutable_var.vv b/vlib/v/checker/tests/immutable_var.vv new file mode 100644 index 0000000000..d83612c7b8 --- /dev/null +++ b/vlib/v/checker/tests/immutable_var.vv @@ -0,0 +1,4 @@ +fn main() { + a := 1 + a = 2 +} diff --git a/vlib/v/checker/tests/left_shift_err.out b/vlib/v/checker/tests/left_shift_err.out index 1c01098b02..f056e33cec 100644 --- a/vlib/v/checker/tests/left_shift_err.out +++ b/vlib/v/checker/tests/left_shift_err.out @@ -1,6 +1,6 @@ vlib/v/checker/tests/left_shift_err.v:3:7: error: cannot shift type string into array_int 1| fn main() { - 2| l := []int{} + 2| mut l := []int{} 3| l << 'test' ~~~~~~ 4| } diff --git a/vlib/v/checker/tests/left_shift_err.v b/vlib/v/checker/tests/left_shift_err.v index df62f079be..52c6ea7191 100644 --- a/vlib/v/checker/tests/left_shift_err.v +++ b/vlib/v/checker/tests/left_shift_err.v @@ -1,4 +1,4 @@ fn main() { - l := []int{} + mut l := []int{} l << 'test' } diff --git a/vlib/v/checker/tests/left_shift_err.vv b/vlib/v/checker/tests/left_shift_err.vv index df62f079be..52c6ea7191 100644 --- a/vlib/v/checker/tests/left_shift_err.vv +++ b/vlib/v/checker/tests/left_shift_err.vv @@ -1,4 +1,4 @@ fn main() { - l := []int{} + mut l := []int{} l << 'test' } diff --git a/vlib/v/checker/tests/struct_pub_field.out b/vlib/v/checker/tests/struct_pub_field.out new file mode 100644 index 0000000000..879e9a33bb --- /dev/null +++ b/vlib/v/checker/tests/struct_pub_field.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/struct_pub_field.v:9:4: error: field `i` of struct `A` is immutable + 7| i: 1 + 8| } + 9| a.i = 2 + ^ + 10| } diff --git a/vlib/v/checker/tests/struct_pub_field.v b/vlib/v/checker/tests/struct_pub_field.v new file mode 100644 index 0000000000..df9f190061 --- /dev/null +++ b/vlib/v/checker/tests/struct_pub_field.v @@ -0,0 +1,10 @@ +struct A { + i int +} + +fn main() { + a := A{ + i: 1 + } + a.i = 2 +} diff --git a/vlib/v/checker/tests/struct_pub_field.vv b/vlib/v/checker/tests/struct_pub_field.vv new file mode 100644 index 0000000000..df9f190061 --- /dev/null +++ b/vlib/v/checker/tests/struct_pub_field.vv @@ -0,0 +1,10 @@ +struct A { + i int +} + +fn main() { + a := A{ + i: 1 + } + a.i = 2 +} diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 953c45c998..e2b57d9175 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -56,7 +56,6 @@ struct Gen { auto_str_funcs strings.Builder // function bodies of all auto generated _str funcs comptime_defines strings.Builder // custom defines, given by -d/-define flags on the CLI pcs_declarations strings.Builder // -prof profile counter declarations for each function - pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name table &table.Table pref &pref.Preferences mut: @@ -86,6 +85,7 @@ mut: threaded_fns []string // for generating unique wrapper types and fns for `go xxx()` array_fn_definitions []string // array equality functions that have been defined is_json_fn bool // inside json.encode() + pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name } const ( diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 38a70077a2..dcc52bdf10 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -16,15 +16,15 @@ const ( ) struct JsGen { - out strings.Builder + table &table.Table + definitions strings.Builder + pref &pref.Preferences +mut: + out strings.Builder namespaces map[string]strings.Builder namespaces_pub map[string][]string - namespace string - table &table.Table - definitions strings.Builder - pref &pref.Preferences + namespace string doc &JsDoc - mut: constants strings.Builder // all global V constants file ast.File tmp_count int @@ -110,7 +110,7 @@ pub fn (g mut JsGen) escape_namespace() { pub fn (g mut JsGen) push_pub_var(s string) { // Workaround until `m[key]< 0 { name = '${p.expr_mod}.$name' } - mut ident := ast.Ident{ + return ast.Ident{ kind: .unresolved name: name is_c: is_c @@ -573,7 +573,6 @@ pub fn (mut p Parser) parse_ident(is_c, is_js bool) ast.Ident { mod: p.mod pos: pos } - return ident } pub fn (mut p Parser) name_expr() ast.Expr { @@ -694,9 +693,7 @@ pub fn (mut p Parser) name_expr() ast.Expr { mod: mod } } else { - mut ident := ast.Ident{} - ident = p.parse_ident(is_c, is_js) - node = ident + node = p.parse_ident(is_c, is_js) } p.expr_mod = '' return node diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index 1461100d92..43871a2d1f 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -193,14 +193,12 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr { p.inside_is = true } right = p.expr(precedence) - mut expr := ast.Expr{} - expr = ast.InfixExpr{ + return ast.InfixExpr{ left: left right: right op: op pos: pos } - return expr } fn (mut p Parser) prefix_expr() ast.PrefixExpr { diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index ff3b945ddb..fec773f3a0 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -38,6 +38,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl { mut mut_pos := -1 mut pub_pos := -1 mut pub_mut_pos := -1 + mut is_field_mut := false + mut is_field_pub := false + mut is_field_global := false if !no_body { p.check(.lcbr) for p.tok.kind != .rcbr { @@ -50,17 +53,29 @@ fn (mut p Parser) struct_decl() ast.StructDecl { if p.tok.kind == .key_mut { p.check(.key_mut) pub_mut_pos = fields.len + is_field_pub = true + is_field_mut = true + is_field_global = false } else { pub_pos = fields.len + is_field_pub = true + is_field_mut = false + is_field_global = false } p.check(.colon) } else if p.tok.kind == .key_mut { p.check(.key_mut) p.check(.colon) mut_pos = fields.len + is_field_pub = false + is_field_mut = true + is_field_global = false } else if p.tok.kind == .key_global { p.check(.key_global) p.check(.colon) + is_field_pub = true + is_field_mut = true + is_field_global = true } field_name := p.check_name() field_pos := p.tok.position() @@ -108,6 +123,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl { typ: typ default_expr: default_expr has_default_expr: has_default_expr + is_pub: is_field_pub + is_mut: is_field_mut + is_global: is_field_global } // println('struct field $ti.name $field_name') } diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index ca9adceaec..7eef570cb1 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -311,6 +311,14 @@ pub fn (t &TypeSymbol) map_info() Map { } } +[inline] +pub fn (t &TypeSymbol) struct_info() Struct { + match t.info { + Struct { return it } + else { panic('TypeSymbol.struct_info(): no struct info for type: $t.name') } + } +} + /* pub fn (t TypeSymbol) str() string { return t.name @@ -499,6 +507,7 @@ pub mut: } pub struct Interface { +mut: gen_types []string foo string } @@ -522,6 +531,9 @@ mut: has_default_expr bool default_val string attr string + is_pub bool + is_mut bool + is_global bool } pub struct Array { @@ -594,3 +606,19 @@ pub fn (table &Table) type_to_str(t Type) string { */ return res } + +pub fn (s Struct) find_field(name string) ?Field { + for field in s.fields { + if field.name == name { + return field + } + } + return none +} + +pub fn (s Struct) get_field(name string) Field { + if field := s.find_field(name) { + return field + } + panic('unknown field `$name`') +} diff --git a/vlib/v/table/cflags_test.v b/vlib/v/table/cflags_test.v index 48a5ec4b4c..36f4a38a72 100644 --- a/vlib/v/table/cflags_test.v +++ b/vlib/v/table/cflags_test.v @@ -3,7 +3,7 @@ import v.cflag const ( module_name = 'main' - cdefines = []string + cdefines = []string{} no_name = '' no_flag = '' no_os = '' diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 1f7dddfdde..cc68acf067 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -18,7 +18,6 @@ pub mut: pub struct Fn { pub: - name string args []Arg return_type Type is_variadic bool @@ -28,6 +27,8 @@ pub: is_pub bool mod string ctdefine string // compile time define. myflag, when [if myflag] tag +pub mut: + name string } pub struct Arg { @@ -486,7 +487,7 @@ pub fn (t &Table) check(got, expected Type) bool { exp_type_sym := t.get_type_symbol(expected) // if exp_type_sym.kind == .interface_ { - info := exp_type_sym.info as Interface + mut info := exp_type_sym.info as Interface // println('gen_types before') // println(info.gen_types) info.gen_types << got_type_sym.name diff --git a/vlib/v/util/scanning.v b/vlib/v/util/scanning.v index 0981cfab67..861b38530f 100644 --- a/vlib/v/util/scanning.v +++ b/vlib/v/util/scanning.v @@ -40,5 +40,5 @@ pub fn cescaped_path(s string) string { } pub fn is_fmt() bool { - return os.executable().contains('vfmt') + return os.executable().contains('vfmt') }