parser: support `mut:` section in the interface methods, and a mut interface fn modifier (#8092)

pull/8269/head
Nick Treleaven 2021-01-22 08:02:28 +00:00 committed by GitHub
parent 1b09954622
commit 72168cd6bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 22 additions and 12 deletions

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/function_arg_mutable_err.vv:1:18: error: mutable arguments are only allowed for arrays, maps, structs and pointers
vlib/v/checker/tests/function_arg_mutable_err.vv:1:18: error: mutable arguments are only allowed for arrays, interfaces, maps, pointers and structs
return values instead: `fn foo(mut n int) {` => `fn foo(n int) int {`
1 | fn mod_ptr(mut a int) {
| ~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mut_int.vv:1:14: error: mutable arguments are only allowed for arrays, maps, structs and pointers
vlib/v/checker/tests/mut_int.vv:1:14: error: mutable arguments are only allowed for arrays, interfaces, maps, pointers and structs
return values instead: `fn foo(mut n int) {` => `fn foo(n int) int {`
1 | fn foo(mut x int) {
| ~~~

View File

@ -700,10 +700,11 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) {
fn (mut p Parser) check_fn_mutable_arguments(typ table.Type, pos token.Position) {
sym := p.table.get_type_symbol(typ)
if sym.kind !in [.array, .array_fixed, .struct_, .map, .placeholder, .sum_type] &&
if sym.kind !in
[.array, .array_fixed, .interface_, .map, .placeholder, .struct_, .sum_type] &&
!typ.is_ptr() && !typ.is_pointer()
{
p.error_with_pos('mutable arguments are only allowed for arrays, maps, structs and pointers\n' +
p.error_with_pos('mutable arguments are only allowed for arrays, interfaces, maps, pointers and structs\n' +
'return values instead: `fn foo(mut n $sym.name) {` => `fn foo(n $sym.name) $sym.name {`',
pos)
}

View File

@ -462,8 +462,18 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
ts.methods = []table.Fn{cap: 20}
// Parse methods
mut methods := []ast.FnDecl{cap: 20}
mut is_mut := false
for p.tok.kind != .rcbr && p.tok.kind != .eof {
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()
line_nr := p.tok.line_nr
name := p.check_name()
@ -479,6 +489,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
args2, _, is_variadic := p.fn_args() // TODO merge table.Param and ast.Arg to avoid this
mut args := [table.Param{
name: 'x'
is_mut: is_mut
typ: typ
is_hidden: true
}]

View File

@ -7,7 +7,7 @@ mut:
breed string
}
fn (mut c Cat) name() string {
fn (c &Cat) name() string {
if c.breed != '' {
assert c.breed == 'Persian'
}
@ -113,7 +113,7 @@ fn test_perform_speak() {
*/
}
fn change_animal_breed(a &Animal, new string) {
fn change_animal_breed(mut a Animal, new string) {
a.set_breed(new)
}
@ -122,7 +122,7 @@ fn test_interface_ptr_modification() {
breed: 'Persian'
}
// TODO Should fail and require `mut cat`
change_animal_breed(cat, 'Siamese')
change_animal_breed(mut cat, 'Siamese')
assert cat.breed == 'Siamese'
}
@ -218,11 +218,9 @@ fn (mut b Boss) return_speaker2() ?Speaker2 {
return b
}
fn return_speaker2(sp Speaker2) Speaker2 {
fn return_speaker2(mut sp Speaker2) Speaker2 {
s := sp.return_speaker()
s2 := sp.return_speaker2() or {
return sp
}
s2 := sp.return_speaker2() or { return *sp }
s.speak()
s2.speak()
return s2
@ -231,7 +229,7 @@ fn return_speaker2(sp Speaker2) Speaker2 {
fn test_interface_returning_interface() {
mut b := Boss{'bob'}
assert b.name == 'bob'
s2 := return_speaker2(b)
s2 := return_speaker2(mut b)
if s2 is Boss {
assert s2.name == 'boss'
}