diff --git a/compiler/cgen.v b/compiler/cgen.v index 5c08d3bffb..c41cfd7579 100644 --- a/compiler/cgen.v +++ b/compiler/cgen.v @@ -11,19 +11,20 @@ import time struct CGen { out os.File out_path string - typedefs []string - type_aliases []string - includes []string - thread_args []string + //types []string thread_fns []string - consts []string - fns []string - so_fns []string - consts_init []string //buf strings.Builder is_user bool mut: lines []string + typedefs []string + type_aliases []string + includes []string + thread_args []string + consts []string + fns []string + so_fns []string + consts_init []string pass Pass nogen bool tmp_line string diff --git a/compiler/parser.v b/compiler/parser.v index 776c116d25..2d66c25ad1 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -34,6 +34,8 @@ mut: mod string inside_const bool expr_var Var + has_immutable_field bool + first_immutable_field Var assigned_type string expected_type string tmp_cnt int @@ -1405,6 +1407,7 @@ fn (p mut Parser) bterm() string { // also called on *, &, @, . (enum) fn (p mut Parser) name_expr() string { + p.has_immutable_field = false ph := p.cgen.add_placeholder() // amp ptr := p.tok == .amp @@ -1774,17 +1777,24 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string { if has_field { struct_field := if typ.name != 'Option' { p.table.var_cgen_name(field_name) } else { field_name } field := p.table.find_field(typ, struct_field) + if !field.is_mut && !p.has_immutable_field { + p.has_immutable_field = true + p.first_immutable_field = field + } // Is the next token `=`, `+=` etc? (Are we modifying the field?) next := p.peek() - modifying := next.is_assign() || next == .inc || next == .dec + modifying := next.is_assign() || next == .inc || next == .dec || + (field.typ.starts_with('array_') && next == .left_shift) is_vi := p.fileis('vid') - if !p.builtin_mod && !p.pref.translated && modifying && !field.is_mut && !is_vi { - p.error('cannot modify immutable field `$struct_field` (type `$typ.name`)\n' + - 'declare the field with `mut:` + if !p.builtin_mod && !p.pref.translated && modifying && !is_vi + && p.has_immutable_field { + f := p.first_immutable_field + p.error('cannot modify immutable field `$f.name` (type `$f.parent_fn`)\n' + + 'declare the field with `mut:` -struct $typ.name { +struct $f.parent_fn { mut: - $struct_field $field.typ + $f.name $f.typ } ') } @@ -1796,13 +1806,6 @@ struct $typ.name { // println(field.access_mod) p.error('cannot refer to unexported field `$struct_field` (type `$typ.name`)') } - // if field.access_mod ==.public && p.peek() == .assign && !p.builtin_mod && p.mod != typ.mod { - // Don't allow `str.len = 0` - if field.access_mod == .public && !p.builtin_mod && p.mod != typ.mod { - if !field.is_mut && !p.pref.translated && modifying { - p.error('cannot modify public immutable field `$struct_field` (type `$typ.name`)') - } - } p.gen(dot + struct_field) p.next() return field.typ diff --git a/compiler/table.v b/compiler/table.v index da472893db..6a71ebeb1f 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -27,6 +27,7 @@ mut: struct GenTable { fn_name string +mut: types []string } @@ -423,6 +424,7 @@ fn (t mut Type) add_field(name, typ string, is_mut bool, attr string, access_mod typ: typ is_mut: is_mut attr: attr + parent_fn: t.name // Name of the parent type access_mod: access_mod } t.fields << v diff --git a/compiler/tests/repl/chained_fields.repl b/compiler/tests/repl/chained_fields.repl new file mode 100644 index 0000000000..8784880ef5 --- /dev/null +++ b/compiler/tests/repl/chained_fields.repl @@ -0,0 +1,78 @@ +/* 1 */ struct A { mut: v int } +/* 2 */ struct B { a A } +/* 3 */ struct C { mut: b B } +/* 4 */ struct D { mut: c C } + +/* 5 */ struct E { mut: v []int } +/* 6 */ struct F { e []E } + +/* 7 */ mut s := 'hello world' +/*( 8)*/ s.len = 0 // Error (field len immutable) + +/* 8 */ mut b := B{} +/*( 9)*/ b.a.v = 1 // Error (field a immutable) +/*( 9)*/ b.a = A{} // Error (field a immutable) +/* 9 */ b = B{A{2}} // Correct + +/* 10 */ mut c := C{} +/* 11 */ c.b = B{} // Correct +/*(12)*/ c.b.a = A{} // Error (field a immutable) +/*(12)*/ c.b.a.v = 1 // Error (field a immutable) + +/* 12 */ c2 := C{} +/*(13)*/ c2.b = B{} // Error (c2 immutable) +/* 13 */ mut d := D{} +/* 14 */ d.c.b = B{} // Correct + +/* 15 */ mut f := F{} +/*(16)*/ f.e << E{} // Error (field e immutable) +/*(16)*/ f.e[0].v << 1 // Error (field e immutable) + +/* 16 */ e := E{} +/*(17)*/ e.v << 1 // Error (e immutable) + +===output=== +.vrepl_temp.v:8:14: cannot modify immutable field `len` (type `string`) +declare the field with `mut:` +struct string { + mut: + len int +} +.vrepl_temp.v:9:14: cannot modify immutable field `a` (type `B`) +declare the field with `mut:` +struct B { + mut: + a A +} +.vrepl_temp.v:9:12: cannot modify immutable field `a` (type `B`) +declare the field with `mut:` +struct B { + mut: + a A +} +.vrepl_temp.v:12:14: cannot modify immutable field `a` (type `B`) +declare the field with `mut:` +struct B { + mut: + a A +} +.vrepl_temp.v:12:16: cannot modify immutable field `a` (type `B`) +declare the field with `mut:` +struct B { + mut: + a A +} +.vrepl_temp.v:13:15: `c2` is immutable. +.vrepl_temp.v:16:12: cannot modify immutable field `e` (type `F`) +declare the field with `mut:` +struct F { + mut: + e []E +} +.vrepl_temp.v:16:17: cannot modify immutable field `e` (type `F`) +declare the field with `mut:` +struct F { + mut: + e []E +} +.vrepl_temp.v:17:17: `e` is immutable (can't <<) diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index 68a82b176d..f7fded9cec 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -214,6 +214,7 @@ struct Test2 { struct Test { a string +mut: b []Test2 } diff --git a/vlib/freetype/freetype.v b/vlib/freetype/freetype.v index 70dc7717dc..9a4a8db916 100644 --- a/vlib/freetype/freetype.v +++ b/vlib/freetype/freetype.v @@ -63,10 +63,11 @@ struct Context { line_vbo u32 vbo u32 chars []Character - utf_runes []string - utf_chars []Character face C.FT_Face scale int // retina = 2 , normal = 1 +mut: + utf_runes []string + utf_chars []Character } struct C.Bitmap { diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index 4d56434fdf..dd71689f83 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -20,6 +20,7 @@ pub: conn net.Socket form map[string]string // TODO Response +mut: headers []string // response headers }