|
| 1 | +- Start Date: 2014-12-03 |
| 2 | +- RFC PR: (leave this empty) |
| 3 | +- Rust Issue: (leave this empty) |
| 4 | + |
| 5 | +Summary |
| 6 | +======= |
| 7 | + |
| 8 | +Change array/slice patterns in the following ways: |
| 9 | + |
| 10 | +- Make them only match on arrays (`[T, ..n]` and `[T]`), not slices; |
| 11 | +- Make subslice matching yield a value of type `[T, ..n]` or `[T]`, not `&[T]` |
| 12 | + or `&mut [T]`; |
| 13 | +- Allow multiple mutable references to be made to different parts of the same |
| 14 | + array or slice in array patterns (resolving rust-lang/rust [issue |
| 15 | + #8636](https://github.com/rust-lang/rust/issues/8636)). |
| 16 | + |
| 17 | +Motivation |
| 18 | +========== |
| 19 | + |
| 20 | +Before DST (and after the removal of `~[T]`), there were only two types based on |
| 21 | +`[T]`: `&[T]` and `&mut [T]`. With DST, we can have many more types based on |
| 22 | +`[T]`, `Box<[T]>` in particular, but theoretically any pointer type around a |
| 23 | +`[T]` could be used. However, array patterns still match on `&[T]`, `&mut [T]`, |
| 24 | +and `[T, ..n]` only, meaning that to match on a `Box<[T]>`, one must first |
| 25 | +convert it to a slice, which disallows moves. This may prove to significantly |
| 26 | +limit the amount of useful code that can be written using array patterns. |
| 27 | + |
| 28 | +Another problem with today’s array patterns is in subslice matching, which |
| 29 | +specifies that the rest of a slice not matched on already in the pattern should |
| 30 | +be put into a variable: |
| 31 | + |
| 32 | +```rust |
| 33 | +let foo = [1i, 2, 3]; |
| 34 | +match foo { |
| 35 | + [head, tail..] => { |
| 36 | + assert_eq!(head, 1); |
| 37 | + assert_eq!(tail, &[2, 3]); |
| 38 | + }, |
| 39 | + _ => {}, |
| 40 | +} |
| 41 | +``` |
| 42 | + |
| 43 | +This makes sense, but still has a few problems. In particular, `tail` is a |
| 44 | +`&[int]`, even though the compiler can always assert that it will have a length |
| 45 | +of `2`, so there is no way to treat it like a fixed-length array. Also, all |
| 46 | +other bindings in array patterns are by-value, whereas bindings using subslice |
| 47 | +matching are by-reference (even though they don’t use `ref`). This can create |
| 48 | +confusing errors because of the fact that the `..` syntax is the only way of |
| 49 | +taking a reference to something within a pattern without using the `ref` |
| 50 | +keyword. |
| 51 | + |
| 52 | +Finally, the compiler currently complains when one tries to take multiple |
| 53 | +mutable references to different values within the same array in a slice pattern: |
| 54 | + |
| 55 | +```rust |
| 56 | +let foo: &mut [int] = &mut [1, 2, 3]; |
| 57 | +match foo { |
| 58 | + [ref mut a, ref mut b] => ..., |
| 59 | + ... |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +This fails to compile, because the compiler thinks that this would allow |
| 64 | +multiple mutable borrows to the same value (which is not the case). |
| 65 | + |
| 66 | +Detailed design |
| 67 | +=============== |
| 68 | + |
| 69 | +- Make array patterns match only on arrays (`[T, ..n]` and `[T]`). For example, |
| 70 | + the following code: |
| 71 | + |
| 72 | + ```rust |
| 73 | + let foo: &[u8] = &[1, 2, 3]; |
| 74 | + match foo { |
| 75 | + [a, b, c] => ..., |
| 76 | + ... |
| 77 | + } |
| 78 | + ``` |
| 79 | + |
| 80 | + Would have to be changed to this: |
| 81 | + |
| 82 | + ```rust |
| 83 | + let foo: &[u8] = &[1, 2, 3]; |
| 84 | + match foo { |
| 85 | + &[a, b, c] => ..., |
| 86 | + ... |
| 87 | + } |
| 88 | + ``` |
| 89 | + |
| 90 | + This change makes slice patterns mirror slice expressions much more closely. |
| 91 | + |
| 92 | +- Make subslice matching in array patterns yield a value of type `[T, ..n]` (if |
| 93 | + the array is of fixed size) or `[T]` (if not). This means changing most code |
| 94 | + that looks like this: |
| 95 | + |
| 96 | + ```rust |
| 97 | + let foo: &[u8] = &[1, 2, 3]; |
| 98 | + match foo { |
| 99 | + [a, b, c..] => ..., |
| 100 | + ... |
| 101 | + } |
| 102 | + ``` |
| 103 | + |
| 104 | + To this: |
| 105 | + |
| 106 | + ```rust |
| 107 | + let foo: &[u8] = &[1, 2, 3]; |
| 108 | + match foo { |
| 109 | + &[a, b, ref c..] => ..., |
| 110 | + ... |
| 111 | + } |
| 112 | + ``` |
| 113 | + |
| 114 | + It should be noted that if a fixed-size array is matched on using subslice |
| 115 | + matching, and `ref` is used, the type of the binding will be `&[T, ..n]`, |
| 116 | + *not* `&[T]`. |
| 117 | + |
| 118 | +- Improve the compiler’s analysis of multiple mutable references to the same |
| 119 | + value within array patterns. This would be done by allowing multiple mutable |
| 120 | + references to different elements of the same array (including bindings from |
| 121 | + subslice matching): |
| 122 | + |
| 123 | + ```rust |
| 124 | + let foo: &mut [u8] = &mut [1, 2, 3, 4]; |
| 125 | + match foo { |
| 126 | + &[ref mut a, ref mut b, ref c, ref mut d..] => ..., |
| 127 | + ... |
| 128 | + } |
| 129 | + ``` |
| 130 | + |
| 131 | +Drawbacks |
| 132 | +========= |
| 133 | + |
| 134 | +- This will break a non-negligible amount of code, requiring people to add `&`s |
| 135 | + and `ref`s to their code. |
| 136 | + |
| 137 | +- The modifications to subslice matching will require `ref` or `ref mut` to be |
| 138 | + used in almost all cases. This could be seen as unnecessary. |
| 139 | + |
| 140 | +Alternatives |
| 141 | +============ |
| 142 | + |
| 143 | +- Do a subset of this proposal; for example, the modifications to subslice |
| 144 | + matching in patterns could be removed. |
| 145 | + |
| 146 | +Unresolved questions |
| 147 | +==================== |
| 148 | + |
| 149 | +- What are the precise implications to the borrow checker of the change to |
| 150 | + multiple mutable borrows in the same array pattern? Since it is a |
| 151 | + backwards-compatible change, it can be implemented after 1.0 if it turns out |
| 152 | + to be difficult to implement. |
0 commit comments