Compare commits

...

41 Commits

Author SHA1 Message Date
Anselm Schüler b339e82717
Merge dbd2370a29 into 8e7887c8b7 2024-05-02 15:24:42 -07:00
Eric Huss 8e7887c8b7
Merge pull request #3622 from RalfJung/rfc-process-pr-number
both the RFC file name and link in the file should be updated
2024-05-02 06:11:14 -07:00
Ralf Jung 865c00519b both the RFC file name and link in the file should be updated 2024-05-02 13:37:00 +02:00
Eric Huss 930f5ab59b
Merge pull request #3620 from rust-lang/renovate/actions-checkout-digest
Update actions/checkout digest to 0ad4b8f
2024-05-01 12:01:20 -07:00
Eric Huss 793ffd107d
Add patch version for actions/checkout
This will make it so that renovatebot will update the comment with the full patch version.
2024-05-01 12:01:06 -07:00
renovate[bot] ddd8298de2
Update actions/checkout digest to 0ad4b8f 2024-05-01 00:31:21 +00:00
Anselm Schüler dbd2370a29 explicit-move-binding-mode: change ditto symbol to " 2023-05-17 13:01:50 +02:00
Anselm Schüler 1ccc69e8cb explicit-move-binding-mode: add copy as a possible keyword 2023-04-14 19:49:15 +02:00
Anselm Schüler 06a7313b9a
explicit-move-binding-mode: add divider 2023-04-13 00:48:12 +02:00
Anselm Schüler e9b7bbf6e5 explicit-move-binding-mode: list some keyword ideas 2023-04-12 22:18:23 +02:00
Anselm Schüler cf38c64dff explicit-move-binding-mode: note the other definition of reference patterns 2023-04-12 22:15:41 +02:00
Anselm Schüler bf16a67d48
explicit-move-binding-mode: refined symbols 2023-04-11 16:33:14 +02:00
Anselm Schüler d910629fb5 explicit-move-binding-mode: slight adjustment of the text 2023-04-11 16:00:07 +02:00
Anselm Schüler 0fe609d08d explicit-move-binding-mode: add future possibility 2023-04-11 00:10:55 +02:00
Anselm Schüler c014c2d614 explicit-move-binding-mode: small adjustments 2023-04-10 20:06:16 +02:00
Anselm Schüler ac8cf43b74 explicit-move-binding-mode: add drawbacks 2023-04-10 18:29:59 +02:00
Anselm Schüler a9cb256573 explicit-move-binding-mode: Revert "explicit-move-binding-mode: explain that the move is part of a copy" as I need to think about this
This reverts commit aa1143d085.
2023-04-10 18:10:42 +02:00
Anselm Schüler 7dfb3e9ce6 explicit-move-binding-mode: clarify 2023-04-10 17:25:43 +02:00
Anselm Schüler aa1143d085 explicit-move-binding-mode: explain that the move is part of a copy 2023-04-10 17:14:15 +02:00
Anselm Schüler 4b4245878e explicit-move-binding-mode: various small adjustments 2023-04-10 12:36:12 +02:00
Anselm Schüler 17522df675 explicit-move-binding-mode: fix & explain warning example 2023-04-10 11:47:49 +02:00
Anselm Schüler 7166c59e67 explicit-move-binding-mode: add more warning ideas & small updates 2023-04-10 11:47:49 +02:00
Anselm Schüler 9d67c67fb3 explicit-move-binding-mode: remove a “the” 2023-04-10 11:47:49 +02:00
Anselm Schüler dd51981217 explicit-move-binding-mode: make wording clearer 2023-04-10 11:47:49 +02:00
Anselm Schüler 5e4067be1c explicit-move-binding-mode: remove superfluous “then” 2023-04-10 11:47:49 +02:00
Anselm Schüler 2a345b3dd4 explicit-move-binding-mode: fix syntax highlighting 2023-04-10 11:47:49 +02:00
Anselm Schüler 4efd856399 explicit-move-binding-mode: better explaination for why this is already kind of possible 2023-04-10 11:47:49 +02:00
Anselm Schüler 8df5b7dc44 explicit-move-binding-mode: give alternate keyword possibilities 2023-04-10 11:47:49 +02:00
Anselm Schüler 5d2a1d35b0 explicit-move-binding-mode: +slightly 2023-04-10 11:47:49 +02:00
Anselm Schüler 45c34d8e71 explicit-move-binding-mode: fix two mistakes 2023-04-10 11:47:35 +02:00
Anselm Schüler f0c81b50d8 explicit-move-binding-mode: elaborate on alternatives & fix future possibilities 2023-04-08 18:57:34 +02:00
Anselm Schüler c6a79e0b5a explicit-move-binding-mode: add newline 2023-04-08 13:19:03 +02:00
Anselm Schüler eb58dc60da explicit-move-binding-mode: clarify lint and provide examples for alternative 2023-04-08 13:09:18 +02:00
Anselm Schüler 38aee062eb explicit-move-binding-mode: fix error example 2023-04-08 01:03:03 +02:00
Anselm Schüler cf0b9155ac explicit-move-binding-mode: mark example warning code blocks as language=none and turn one into an error 2023-04-08 01:00:51 +02:00
Anselm Schüler 454409080b explicit-move-binding-mode: fix mistake in table description 2023-04-08 00:03:41 +02:00
Anselm Schüler 2926ee13c5 explicit-move-binding-mode: fix header 2023-04-07 23:49:26 +02:00
Anselm Schüler 94a3482926 explicit-move-binding-mode: clarify 2023-04-07 23:46:58 +02:00
Anselm Schüler b5c800fb55 explicit-move-binding-mode: move `move mut` into unresolved questions 2023-04-07 23:43:35 +02:00
Anselm Schüler 72c9b30ce9 explicit-move-binding-mode: move RFC to match PR number 2023-04-07 23:33:52 +02:00
Anselm Schüler f4bfed3d44 explicit-move-binding-mode: write RFC 2023-04-07 23:27:19 +02:00
3 changed files with 275 additions and 2 deletions

View File

@ -12,7 +12,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
fetch-depth: 0
- name: Install mdbook

View File

@ -115,7 +115,8 @@ merged into the RFC repository as a markdown file. At that point the RFC is
feedback from the larger community, and the author should be prepared to
revise it in response.
- Now that your RFC has an open pull request, use the issue number of the PR
to update your `0000-` prefix to that number.
to rename the file: update your `0000-` prefix to that number. Also
update the "RFC PR" link at the top of the file.
- Each pull request will be labeled with the most relevant [sub-team], which
will lead to its being triaged by that team in a future meeting and assigned
to a member of the subteam.

View File

@ -0,0 +1,272 @@
- Feature Name: explicit_move_binding_mode
- Start Date: 2023-04-07
- RFC PR: [rust-lang/rfcs#3410](https://github.com/rust-lang/rfcs/pull/3410)
# Summary
[summary]: #summary
Enable the use of the `move` keyword to explicitly specify the moving binding
mode in patterns. This allows users to opt out of match ergonomics for some but not all bindings.
Warn about unnecessary keywords that specify binding mode (called “specifiers” in this document).
# Motivation
[motivation]: #motivation
Currently, there are multiple binding modes in patterns, but only some are explicitly specifiable.
This is an obvious inconsistency, as match ergonomics permit changing the
default binding mode of a pattern. Changing it back is only natural, as changing it
to the non-default mutable move is possible—that is, writing `mut` overrides match ergonomics
and performs a move after the dereference, although the resulting binding is mutable.
Specifically, when most bindings of a large pattern should be of one binding mode,
but some should be moves, it is inconvenient to forgo match ergonomics entirely
and repeatedly use `ref` or `ref mut` specifiers.
# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation
## Expert explanation
The `move` keyword resets the binding mode for an individual identifier pattern
to the moving mode. The meaning of `mut` remains the same.
The matching still dereferences by match ergonomics rules.
## Beginner explanation
When deconstructing a value, it is sometimes desirable to get a reference to the
element bound to a variable instead of moving that value into the variable. To do
this, you can set the _binding mode_ of an identifier pattern by prefixing it with
`ref`, `ref mut` (or `move`, but this is the default). You can also use this syntax
to make a plain move mutable, by prefixing with just `mut`.
```rust
let mut possibly_x: Option<i32> = Some(37);
if let Some(ref mut x) = possibly_x {
*x += 2;
} // Here we use `ref mut` to get a mutable
// reference to the value contained in `possibly_x`
match possibly_x {
None => {
println!("No value found!");
println!("Cant work with non-existant value.")
}
Some(mut x) => {
println!("The value is {x}.");
x += 2;
println!("That value plus two is {x}.");
} // Here we use `mut` to mark the binding
// as mutable, allowing us to modify it
// Note that this does not change the value
// inside `possibly_x`, as we did not use `ref mut`
}
```
_Match ergonomics_ allow you to more easily get references to bindings in patterns.
When a pattern that is not a reference pattern or a pattern that can match anything (`_` or identifier patterns)
is matched against a value that is a reference, the value is automatically dereferenced,
as though the pattern had been written `&<pattern>` or `&mut <pattern>`, and the default
binding mode is set to `ref` or `ref mut`.
All identifier patterns (`x` and the like) that dont have an explicit binding mode
instead bind with binding mode `ref` or `ref mut`.
This means that `let (x, y) = &a` is the same as `let &(ref x, ref y) = &a`.
We can rewrite the above example as follows:
```rust
let mut possibly_x: Option<i32> = Some(37);
if let Some(x) = &mut possibly_x {
*x += 2
} // Here, `x` has the type `&mut i32`
```
You can opt out of this behaviour for individual identifier patterns by prefixing
them with `move` or `mut`. Note that you cannot create a mutable reference from an
immutable one, and this is not what `mut` does—it sets the binding mode to a mutable move.
```rust
let mut x_and_y: (i32, i32) = (25, -4);
let (x, mut y) = &mut x_and_y;
// The type of `x` is `&mut i32` and
// the type of `y` is `i32` (and the binding is mutable)
*x += 2; // `x_and_y` is modified
y += 2; // `x_and_y` is not modified
let (move x, y) = &x_and_y;
// The type of `x` is `i32` and
// the type of `y` is `&i32`
```
You can also switch to an immutable reference binding mode by using the `ref` keyword.
```rust
let mut x_y_z: (i32, i32, i32) = (400, 1, -99);
let (x, ref y, move z) = &mut x_y_z;
// The type of `x` is `&mut i32`,
// the type of `y` is `&i32` and
// the type of `z` is `i32`
```
# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation
The syntax for _IdentifierPattern_ is updated as follows:
> _IdentifierPattern_:
>
> (`ref` | `move`)? `mut`? IDENTIFIER (`@` _PatternNoTopAlt_)?
The binding mode of a binding depends on the default mode and
the binding mode specifier (`mut`, `move`, `ref`, or `ref mut`)
and is described by the following table. If the entry into the table is
followed by an exclamation mark in parentheses (“(!)”), a lint is triggered.
The symbol “"” indicates that the entry is the same as the entry to the left,
excluding whether it triggers the lint.
| ↓specifier | →default = move | reference | mutable reference |
|------------|-----------------------|-----------|-------------------|
| `mut` | move mutable | " | " |
| `ref mut` | mutable reference | " | " (!) |
| `ref` | reference | " (!) | " |
| `move` | move (!) | " | " |
| _none_ | move | reference | mutable reference |
The lint is controlled by `unnecessary_binding_mode`. It is warn-by-default.
# Drawbacks
[drawbacks]: #drawbacks
- It can be argued that use of the `move` keyword should be replaced with
use of the `ref` keyword and not using match ergonomics at all.
- This further entrenches the unintuitive fact that `mut` sets the binding
mode to a mutable move and disables referencing.
- This means that either the grammar gets more complicated or an additional
sequence is allowed by the grammar but disallowed by the compiler.
- The `move` keyword can be confusing here because a copy may happen instead.
# Rationale and alternatives
[rationale-and-alternatives]: #rationale-and-alternatives
I believe the `move` keyword is an excellent candidate for syntax here,
as it already exists and is also used by the match ergonomics RFC.
Alternative keywords would be `const` or `let`.
Alternatively, a new keyword could be added, although this would need to be
a soft keyword or happen over an edition boundary.
Possible keywords are `copy`, `bind`, `value`, `free`, `new`, `just`, `get`, `fresh`, `set`, `var`.
---
An alternative to this proposal is to update match ergonomics such that a non-reference
pattern matched against a reference does not update the binding mode, but instead
matches the subpatterns against borrowed subvalues. This would allow writing this:
```rust
let x_and_y: (i32, i32) = (-9, 2);
let (x, &y) = &x_and_y;
// `x` is of type `&i32`, while
// `y` is of type `i32`
```
Then, the `mut` keyword could be used to make the binding itself
mutable instead of the reference the binding binds.
```rust
let mut a = 3;
let mut x_and_y: (i32, i32) = (77, 0);
let (mut x, y) = &mut x_and_y;
*x += 2; // `x_and_y` is modified
x = &mut a;
*x += 2; // `a` is modified
```
Note that this proposal likely requires an edition boundary unless
complicated backwards-compatibility measures are employed.
---
A similar possibility for the current proposal: The combination `mut ref` could
be added distinctly from `ref mut` to make the binding mutable, not the reference.
# Prior art
[prior-art]: #prior-art
None that I know of. Other languages dont have match ergonomics as far as I know.
# Unresolved questions
[unresolved-questions]: #unresolved-questions
How should the combination `move mut` be handled? Should it generate an error or be warned against, working as if it was bare `mut`?
I believe having the combination of `move` vs `ref` and `mut` vs nothing be as simple as concatenation
could be useful for macros.
It is also possible to change the preferred way of indicating a mutable move to `move mut`
and warn against plain `mut` instead, as plain `mut` switching to moves is unintuitive.
---
What should the warnings/errors look like?
Here are some ideas:
### Error for `move mut`:
```none
error: move semantics can't be specified here, use bare `mut` instead
--> src/main.rs:4:10
|
4 | (move mut x, y, z) => {
| ----
| |
| help: remove this `move`
|
```
### Unnecessary `move`:
```none
error: unnecessary binding mode specifier
--> src/main.rs:4:10
|
4 | (move x, y, z) => {
| ^^^^
| |
| `move` not required here because it's implied
|
= note: `#[warn(unnecessary_binding_mode)]` on by default
```
(inspired by E0449)
### Unnecessary `ref`:
```none
warning: ref semantics don't need to be specified here because you're matching against a reference
--> src/main.rs:4:10
|
3 | match &(a, b, c) {
| ^---------
| |
| reference originates here
|
4 | (ref x, y, z) => {
| ---
| |
| help: remove this `ref`
|
= note: `#[warn(unnecessary_binding_mode)]` on by default
```
Note that the author is not intimately familiar with the style of `rustc` error messages, so these likely need adjustment.
# Future possibilities
[future-possibilities]: #future-possibilities
It is somewhat unintuitive that the `mut` specifier sets the binding mode to a mutable move.
It would be possible to update match ergonomics in a future edition of Rust to have specifiers
_modify_ the binding mode instead of setting them, or require `move mut` instead of
just `mut` for mutable moves (see also the alternatives section).
It would also be possible to demote `mut` from the status of binding mode specifier and instead
have it be completely orthogonal to binding mode.