From 87494fad1d92913d8c7889c95198fb3888529d54 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 26 Mar 2021 13:38:16 +0200 Subject: [PATCH] parser: allow passing `mut a AliasOfPointerType` --- vlib/v/parser/fn.v | 20 +++++++---- .../tests/type_alias_of_pointer_types_test.v | 35 +++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 0e8e68626d..af755c50fd 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -824,13 +824,21 @@ 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, .interface_, .map, .placeholder, .struct_, .sum_type] - && !typ.is_ptr() && !typ.is_pointer() { - 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) + if sym.kind in [.array, .array_fixed, .interface_, .map, .placeholder, .struct_, .sum_type] { + return } + if typ.is_ptr() || typ.is_pointer() { + return + } + if sym.kind == .alias { + atyp := (sym.info as table.Alias).parent_type + p.check_fn_mutable_arguments(atyp, pos) + return + } + p.error_with_pos( + 'mutable arguments are only allowed for arrays, interfaces, maps, pointers, structs or their aliases\n' + + 'return values instead: `fn foo(mut n $sym.name) {` => `fn foo(n $sym.name) $sym.name {`', + pos) } fn (mut p Parser) check_fn_shared_arguments(typ table.Type, pos token.Position) { diff --git a/vlib/v/tests/type_alias_of_pointer_types_test.v b/vlib/v/tests/type_alias_of_pointer_types_test.v index 0ae00ec9f8..1dcabd9af0 100644 --- a/vlib/v/tests/type_alias_of_pointer_types_test.v +++ b/vlib/v/tests/type_alias_of_pointer_types_test.v @@ -37,3 +37,38 @@ fn test_alias_of_pointer_types() { assert sizeof(PPZZInt) == sizeof(voidptr) assert sizeof(PPZZMyStructInt) == sizeof(voidptr) } + +fn test_calling_a_function_expecting_a_mut_alias() { + eprintln('------------------------') + mut s := &MyStructInt{456} + mut ps := PZZMyStructInt(s) + dump(voidptr(s)) + dump(voidptr(ps)) + eprintln('------------------------') + dump(&MyStructInt(ps)) + res := mut_alias(mut ps) + dump(&MyStructInt(ps)) + // the alias `ps` is now changed and points to another object + assert res == 123 + assert s.x == 456 // should remain the same + assert (&MyStructInt(ps)).x == 789 + assert u64(voidptr(s)) != u64(voidptr(ps)) + dump(voidptr(s)) + dump(voidptr(ps)) + eprintln('------------------------') +} + +// do not delete this, its generated code eases comparisons with mut_alias +fn mut_struct(mut p ZZMyStructInt) int { + dump(ptr_str(voidptr(p))) + return 999 +} + +fn mut_alias(mut ps PZZMyStructInt) int { + // dump(ptr_str(voidptr(ps))) + another := &MyStructInt{789} + // dump(ptr_str(voidptr(another))) + ps = PZZMyStructInt(another) + // dump(ptr_str(voidptr(ps))) + return 123 +}