map: add `move` method (#8660)

pull/8692/head
Nick Treleaven 2021-02-12 00:02:33 +00:00 committed by GitHub
parent 65f2420516
commit 84a16d8684
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 58 additions and 27 deletions

View File

@ -207,7 +207,7 @@ pub struct map {
mut:
// Highest even index in the hashtable
even_index u32
// Number of cached hashbits left for rehasing
// Number of cached hashbits left for rehashing
cached_hashbits byte
// Used for right-shifting out used hashbits
shift byte
@ -346,6 +346,14 @@ fn new_map_init_2(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, fre
return out
}
pub fn (mut m map) move() map {
r := *m
unsafe {
C.memset(m, 0, sizeof(map))
}
return r
}
[inline]
fn (m &map) key_to_index(pkey voidptr) (u32, u32) {
hash := m.hash_fn(pkey)

View File

@ -1442,10 +1442,13 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
call_expr.return_type = table.int_type
}
return call_expr.return_type
} else if left_type_sym.kind == .map && method_name in ['clone', 'keys'] {
} else if left_type_sym.kind == .map && method_name in ['clone', 'keys', 'move'] {
mut ret_type := table.void_type
match method_name {
'clone' {
'clone', 'move' {
if method_name[0] == `m` {
c.fail_if_immutable(call_expr.left)
}
ret_type = left_type
}
'keys' {
@ -2737,9 +2740,9 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
if left_sym.kind == .map && !c.inside_unsafe && assign_stmt.op in [.assign, .decl_assign]
&& right_sym.kind == .map && (left is ast.Ident && !left.is_blank_ident())
&& right is ast.Ident {
// Do not allow `a = b`, only `a = b.clone()`
c.error('use `map2 $assign_stmt.op.str() map1.clone()` instead of `map2 $assign_stmt.op.str() map1` (or use `unsafe`)',
assign_stmt.pos)
// Do not allow `a = b`
c.error('cannot copy map: call `move` or `clone` method first (or use `unsafe`)',
right.position())
}
left_is_ptr := left_type.is_ptr() || left_sym.is_pointer()
if left_is_ptr && c.for_in_mut_val_name != left.str() && left.str() !in c.fn_mut_arg_names {

View File

@ -10,18 +10,19 @@ vlib/v/checker/tests/array_or_map_assign_err.vv:5:5: error: use `array2 = array1
4 | mut a3 := []int{}
5 | a3 = a1
| ^
6 |
6 |
7 | m1 := {'one': 1}
vlib/v/checker/tests/array_or_map_assign_err.vv:8:5: error: use `map2 := map1.clone()` instead of `map2 := map1` (or use `unsafe`)
6 |
vlib/v/checker/tests/array_or_map_assign_err.vv:8:8: error: cannot copy map: call `move` or `clone` method first (or use `unsafe`)
6 |
7 | m1 := {'one': 1}
8 | m2 := m1
| ~~
| ~~
9 | mut m3 := map[string]int{}
10 | m3 = m1
vlib/v/checker/tests/array_or_map_assign_err.vv:10:5: error: use `map2 = map1.clone()` instead of `map2 = map1` (or use `unsafe`)
vlib/v/checker/tests/array_or_map_assign_err.vv:10:7: error: cannot copy map: call `move` or `clone` method first (or use `unsafe`)
8 | m2 := m1
9 | mut m3 := map[string]int{}
10 | m3 = m1
| ^
11 | }
| ~~
11 |
12 | _ = a2

View File

@ -8,4 +8,7 @@ fn main() {
m2 := m1
mut m3 := map[string]int{}
m3 = m1
_ = a2
_ = m2
}

View File

@ -0,0 +1,27 @@
vlib/v/checker/tests/immutable_map.vv:3:2: error: `m` is immutable, declare it with `mut` to make it mutable
1 | fn main() {
2 | m := map[string]int
3 | m['test']++
| ^
4 | m['test']--
5 | _ = m.move()
vlib/v/checker/tests/immutable_map.vv:4:2: error: `m` is immutable, declare it with `mut` to make it mutable
2 | m := map[string]int
3 | m['test']++
4 | m['test']--
| ^
5 | _ = m.move()
6 | m.delete('s')
vlib/v/checker/tests/immutable_map.vv:5:6: error: `m` is immutable, declare it with `mut` to make it mutable
3 | m['test']++
4 | m['test']--
5 | _ = m.move()
| ^
6 | m.delete('s')
7 | }
vlib/v/checker/tests/immutable_map.vv:6:2: error: `m` is immutable, declare it with `mut` to make it mutable
4 | m['test']--
5 | _ = m.move()
6 | m.delete('s')
| ^
7 | }

View File

@ -2,4 +2,6 @@ fn main() {
m := map[string]int
m['test']++
m['test']--
_ = m.move()
m.delete('s')
}

View File

@ -1,13 +0,0 @@
vlib/v/checker/tests/immutable_map_postfix.vv:3:2: error: `m` is immutable, declare it with `mut` to make it mutable
1 | fn main() {
2 | m := map[string]int
3 | m['test']++
| ^
4 | m['test']--
5 | }
vlib/v/checker/tests/immutable_map_postfix.vv:4:2: error: `m` is immutable, declare it with `mut` to make it mutable
2 | m := map[string]int
3 | m['test']++
4 | m['test']--
| ^
5 | }

View File

@ -479,7 +479,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
g.gen_str_for_type(node.receiver_type)
}
mut has_cast := false
if left_sym.kind == .map && node.name == 'clone' {
if left_sym.kind == .map && node.name in ['clone', 'move'] {
receiver_type_name = 'map'
}
// TODO performance, detect `array` method differently