checker: add mutability checks for interface fields; add tests (#8312)
parent
815104e5d0
commit
4be45e8d02
|
@ -1147,13 +1147,18 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.interface_ {
|
.interface_ {
|
||||||
// TODO: mutability checks on interface fields?
|
|
||||||
interface_info := typ_sym.info as table.Interface
|
interface_info := typ_sym.info as table.Interface
|
||||||
interface_info.find_field(expr.field_name) or {
|
mut field_info := interface_info.find_field(expr.field_name) or {
|
||||||
type_str := c.table.type_to_str(expr.expr_type)
|
type_str := c.table.type_to_str(expr.expr_type)
|
||||||
c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
|
c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
|
||||||
return '', pos
|
return '', pos
|
||||||
}
|
}
|
||||||
|
if !field_info.is_mut {
|
||||||
|
type_str := c.table.type_to_str(expr.expr_type)
|
||||||
|
c.error('field `$expr.field_name` of interface `$type_str` is immutable',
|
||||||
|
expr.pos)
|
||||||
|
}
|
||||||
|
c.fail_if_immutable(expr.expr)
|
||||||
}
|
}
|
||||||
.array, .string {
|
.array, .string {
|
||||||
// This should only happen in `builtin`
|
// This should only happen in `builtin`
|
||||||
|
@ -1942,6 +1947,10 @@ fn (mut c Checker) type_implements(typ table.Type, inter_typ table.Type, pos tok
|
||||||
c.error('`$styp` incorrectly implements field `$ifield.name` of interface `$inter_sym.name`, expected `$exp`, got `$got`',
|
c.error('`$styp` incorrectly implements field `$ifield.name` of interface `$inter_sym.name`, expected `$exp`, got `$got`',
|
||||||
pos)
|
pos)
|
||||||
return false
|
return false
|
||||||
|
} else if ifield.is_mut && !(field.is_mut || field.is_global) {
|
||||||
|
c.error('`$styp` incorrectly implements interface `$inter_sym.name`, field `$ifield.name` must be mutable',
|
||||||
|
pos)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
vlib/v/checker/tests/immutable_interface_field.vv:10:4: error: field `i1` of interface `&Bbb` is immutable
|
||||||
|
8 |
|
||||||
|
9 | fn mutate_interface(mut b Bbb) {
|
||||||
|
10 | b.i1 = 2
|
||||||
|
| ~~
|
||||||
|
11 | }
|
||||||
|
12 |
|
|
@ -0,0 +1,16 @@
|
||||||
|
struct Aaa {
|
||||||
|
i1 int
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Bbb {
|
||||||
|
i1 int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mutate_interface(mut b Bbb) {
|
||||||
|
b.i1 = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut a := Aaa{1}
|
||||||
|
mutate_interface(mut a)
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
vlib/v/checker/tests/unimplemented_interface_h.vv:9:13: error: `Cat` doesn't implement field `name` of interface `Animal`
|
||||||
|
7 | fn main() {
|
||||||
|
8 | mut animals := []Animal{}
|
||||||
|
9 | animals << Cat{}
|
||||||
|
| ~~~~~
|
||||||
|
10 | }
|
|
@ -0,0 +1,10 @@
|
||||||
|
interface Animal {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cat {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut animals := []Animal{}
|
||||||
|
animals << Cat{}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
vlib/v/checker/tests/unimplemented_interface_i.vv:11:13: error: `Cat` incorrectly implements field `name` of interface `Animal`, expected `string`, got `int`
|
||||||
|
9 | fn main() {
|
||||||
|
10 | mut animals := []Animal{}
|
||||||
|
11 | animals << Cat{}
|
||||||
|
| ~~~~~
|
||||||
|
12 | }
|
|
@ -0,0 +1,12 @@
|
||||||
|
interface Animal {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cat {
|
||||||
|
name int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut animals := []Animal{}
|
||||||
|
animals << Cat{}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
vlib/v/checker/tests/unimplemented_interface_j.vv:12:13: error: `Cat` incorrectly implements interface `Animal`, field `name` must be mutable
|
||||||
|
10 | fn main() {
|
||||||
|
11 | mut animals := []Animal{}
|
||||||
|
12 | animals << Cat{}
|
||||||
|
| ~~~~~
|
||||||
|
13 | }
|
|
@ -0,0 +1,13 @@
|
||||||
|
interface Animal {
|
||||||
|
mut:
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cat {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut animals := []Animal{}
|
||||||
|
animals << Cat{}
|
||||||
|
}
|
|
@ -460,17 +460,17 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||||
mut methods := []ast.FnDecl{cap: 20}
|
mut methods := []ast.FnDecl{cap: 20}
|
||||||
mut is_mut := false
|
mut is_mut := false
|
||||||
for p.tok.kind != .rcbr && p.tok.kind != .eof {
|
for p.tok.kind != .rcbr && p.tok.kind != .eof {
|
||||||
|
if p.tok.kind == .key_mut {
|
||||||
|
if is_mut {
|
||||||
|
p.error_with_pos('redefinition of `mut` section', p.tok.position())
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
p.next()
|
||||||
|
p.check(.colon)
|
||||||
|
is_mut = true
|
||||||
|
}
|
||||||
if p.peek_tok.kind == .lpar {
|
if p.peek_tok.kind == .lpar {
|
||||||
ts = p.table.get_type_symbol(typ) // removing causes memory bug visible by `v -silent test-fmt`
|
ts = p.table.get_type_symbol(typ) // removing causes memory bug visible by `v -silent test-fmt`
|
||||||
if p.tok.kind == .key_mut {
|
|
||||||
if is_mut {
|
|
||||||
p.error_with_pos('redefinition of `mut` section', p.tok.position())
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
p.next()
|
|
||||||
p.check(.colon)
|
|
||||||
is_mut = true
|
|
||||||
}
|
|
||||||
method_start_pos := p.tok.position()
|
method_start_pos := p.tok.position()
|
||||||
line_nr := p.tok.line_nr
|
line_nr := p.tok.line_nr
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
|
@ -538,11 +538,14 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||||
type_pos: type_pos
|
type_pos: type_pos
|
||||||
typ: field_typ
|
typ: field_typ
|
||||||
comments: comments
|
comments: comments
|
||||||
|
is_public: true
|
||||||
}
|
}
|
||||||
mut info := ts.info as table.Interface
|
mut info := ts.info as table.Interface
|
||||||
info.fields << table.Field{
|
info.fields << table.Field{
|
||||||
name: field_name
|
name: field_name
|
||||||
typ: field_typ
|
typ: field_typ
|
||||||
|
is_pub: true
|
||||||
|
is_mut: is_mut
|
||||||
}
|
}
|
||||||
ts.info = info
|
ts.info = info
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
interface Animal {
|
interface Animal {
|
||||||
|
mut:
|
||||||
breed string
|
breed string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue