mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
parser: fix mutability with chained fields
This commit is contained in:
parent
dae4c4b83f
commit
4f0f99e663
@ -11,19 +11,20 @@ import time
|
|||||||
struct CGen {
|
struct CGen {
|
||||||
out os.File
|
out os.File
|
||||||
out_path string
|
out_path string
|
||||||
typedefs []string
|
//types []string
|
||||||
type_aliases []string
|
|
||||||
includes []string
|
|
||||||
thread_args []string
|
|
||||||
thread_fns []string
|
thread_fns []string
|
||||||
consts []string
|
|
||||||
fns []string
|
|
||||||
so_fns []string
|
|
||||||
consts_init []string
|
|
||||||
//buf strings.Builder
|
//buf strings.Builder
|
||||||
is_user bool
|
is_user bool
|
||||||
mut:
|
mut:
|
||||||
lines []string
|
lines []string
|
||||||
|
typedefs []string
|
||||||
|
type_aliases []string
|
||||||
|
includes []string
|
||||||
|
thread_args []string
|
||||||
|
consts []string
|
||||||
|
fns []string
|
||||||
|
so_fns []string
|
||||||
|
consts_init []string
|
||||||
pass Pass
|
pass Pass
|
||||||
nogen bool
|
nogen bool
|
||||||
tmp_line string
|
tmp_line string
|
||||||
|
@ -34,6 +34,8 @@ mut:
|
|||||||
mod string
|
mod string
|
||||||
inside_const bool
|
inside_const bool
|
||||||
expr_var Var
|
expr_var Var
|
||||||
|
has_immutable_field bool
|
||||||
|
first_immutable_field Var
|
||||||
assigned_type string
|
assigned_type string
|
||||||
expected_type string
|
expected_type string
|
||||||
tmp_cnt int
|
tmp_cnt int
|
||||||
@ -1405,6 +1407,7 @@ fn (p mut Parser) bterm() string {
|
|||||||
|
|
||||||
// also called on *, &, @, . (enum)
|
// also called on *, &, @, . (enum)
|
||||||
fn (p mut Parser) name_expr() string {
|
fn (p mut Parser) name_expr() string {
|
||||||
|
p.has_immutable_field = false
|
||||||
ph := p.cgen.add_placeholder()
|
ph := p.cgen.add_placeholder()
|
||||||
// amp
|
// amp
|
||||||
ptr := p.tok == .amp
|
ptr := p.tok == .amp
|
||||||
@ -1774,17 +1777,24 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string {
|
|||||||
if has_field {
|
if has_field {
|
||||||
struct_field := if typ.name != 'Option' { p.table.var_cgen_name(field_name) } else { field_name }
|
struct_field := if typ.name != 'Option' { p.table.var_cgen_name(field_name) } else { field_name }
|
||||||
field := p.table.find_field(typ, struct_field)
|
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?)
|
// Is the next token `=`, `+=` etc? (Are we modifying the field?)
|
||||||
next := p.peek()
|
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')
|
is_vi := p.fileis('vid')
|
||||||
if !p.builtin_mod && !p.pref.translated && modifying && !field.is_mut && !is_vi {
|
if !p.builtin_mod && !p.pref.translated && modifying && !is_vi
|
||||||
p.error('cannot modify immutable field `$struct_field` (type `$typ.name`)\n' +
|
&& p.has_immutable_field {
|
||||||
'declare the field with `mut:`
|
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:
|
mut:
|
||||||
$struct_field $field.typ
|
$f.name $f.typ
|
||||||
}
|
}
|
||||||
')
|
')
|
||||||
}
|
}
|
||||||
@ -1796,13 +1806,6 @@ struct $typ.name {
|
|||||||
// println(field.access_mod)
|
// println(field.access_mod)
|
||||||
p.error('cannot refer to unexported field `$struct_field` (type `$typ.name`)')
|
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.gen(dot + struct_field)
|
||||||
p.next()
|
p.next()
|
||||||
return field.typ
|
return field.typ
|
||||||
|
@ -27,6 +27,7 @@ mut:
|
|||||||
|
|
||||||
struct GenTable {
|
struct GenTable {
|
||||||
fn_name string
|
fn_name string
|
||||||
|
mut:
|
||||||
types []string
|
types []string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,6 +424,7 @@ fn (t mut Type) add_field(name, typ string, is_mut bool, attr string, access_mod
|
|||||||
typ: typ
|
typ: typ
|
||||||
is_mut: is_mut
|
is_mut: is_mut
|
||||||
attr: attr
|
attr: attr
|
||||||
|
parent_fn: t.name // Name of the parent type
|
||||||
access_mod: access_mod
|
access_mod: access_mod
|
||||||
}
|
}
|
||||||
t.fields << v
|
t.fields << v
|
||||||
|
78
compiler/tests/repl/chained_fields.repl
Normal file
78
compiler/tests/repl/chained_fields.repl
Normal file
@ -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 <<)
|
@ -214,6 +214,7 @@ struct Test2 {
|
|||||||
|
|
||||||
struct Test {
|
struct Test {
|
||||||
a string
|
a string
|
||||||
|
mut:
|
||||||
b []Test2
|
b []Test2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,10 +63,11 @@ struct Context {
|
|||||||
line_vbo u32
|
line_vbo u32
|
||||||
vbo u32
|
vbo u32
|
||||||
chars []Character
|
chars []Character
|
||||||
utf_runes []string
|
|
||||||
utf_chars []Character
|
|
||||||
face C.FT_Face
|
face C.FT_Face
|
||||||
scale int // retina = 2 , normal = 1
|
scale int // retina = 2 , normal = 1
|
||||||
|
mut:
|
||||||
|
utf_runes []string
|
||||||
|
utf_chars []Character
|
||||||
}
|
}
|
||||||
|
|
||||||
struct C.Bitmap {
|
struct C.Bitmap {
|
||||||
|
@ -20,6 +20,7 @@ pub:
|
|||||||
conn net.Socket
|
conn net.Socket
|
||||||
form map[string]string
|
form map[string]string
|
||||||
// TODO Response
|
// TODO Response
|
||||||
|
mut:
|
||||||
headers []string // response headers
|
headers []string // response headers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user