From 72168cd6bc3cd5301a9812ac99bd97a0f77fd4c8 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 22 Jan 2021 08:02:28 +0000 Subject: [PATCH] parser: support `mut:` section in the interface methods, and a mut interface fn modifier (#8092) --- vlib/v/checker/tests/function_arg_mutable_err.out | 2 +- vlib/v/checker/tests/mut_int.out | 2 +- vlib/v/parser/fn.v | 5 +++-- vlib/v/parser/struct.v | 11 +++++++++++ vlib/v/tests/interface_test.v | 14 ++++++-------- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/vlib/v/checker/tests/function_arg_mutable_err.out b/vlib/v/checker/tests/function_arg_mutable_err.out index 7bc75f0892..0e33e876b1 100644 --- a/vlib/v/checker/tests/function_arg_mutable_err.out +++ b/vlib/v/checker/tests/function_arg_mutable_err.out @@ -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) { | ~~~ diff --git a/vlib/v/checker/tests/mut_int.out b/vlib/v/checker/tests/mut_int.out index de06cdb105..fa3c6cf004 100644 --- a/vlib/v/checker/tests/mut_int.out +++ b/vlib/v/checker/tests/mut_int.out @@ -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) { | ~~~ diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 17a14e1b75..4ab296ede3 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -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) } diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 8d61f89192..1dbed7b5ef 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -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 }] diff --git a/vlib/v/tests/interface_test.v b/vlib/v/tests/interface_test.v index ae9d5fcb21..c85c549d09 100644 --- a/vlib/v/tests/interface_test.v +++ b/vlib/v/tests/interface_test.v @@ -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' }