diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index fbbd43673..82d70d043 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -66,6 +66,7 @@
- [Match expressions](expressions/match-expr.md)
- [Return expressions](expressions/return-expr.md)
- [Await expressions](expressions/await-expr.md)
+ - [Underscore expressions](expressions/underscore-expr.md)
- [Patterns](patterns.md)
diff --git a/src/expressions.md b/src/expressions.md
index 88f7fbac9..5b4092984 100644
--- a/src/expressions.md
+++ b/src/expressions.md
@@ -26,6 +26,7 @@
> | [_BreakExpression_]\
> | [_RangeExpression_]\
> | [_ReturnExpression_]\
+> | [_UnderscoreExpression_]\
> | [_MacroInvocation_]\
> )
>
@@ -139,10 +140,11 @@ assert_eq!(
## Place Expressions and Value Expressions
-Expressions are divided into two main categories: place expressions and
-value expressions. Likewise, within each expression, operands may occur
-in either place context or value context. The evaluation of an expression
-depends both on its own category and the context it occurs within.
+Expressions are divided into two main categories: place expressions and value
+expressions; there is also a third, minor category of expressions called
+assignee expressions. Within each expression, operands may likewise occur in
+either place context or value context. The evaluation of an expression depends
+both on its own category and the context it occurs within.
A *place expression* is an expression that represents a memory location. These
expressions are [paths] which refer to local variables, [static variables],
@@ -154,8 +156,7 @@ A *value expression* is an expression that represents an actual value.
The following contexts are *place expression* contexts:
-* The left operand of an [assignment][assign] or [compound assignment]
- expression.
+* The left operand of a [compound assignment] expression.
* The operand of a unary [borrow] or [dereference][deref] operator.
* The operand of a field expression.
* The indexed operand of an array indexing expression.
@@ -168,6 +169,20 @@ The following contexts are *place expression* contexts:
> Note: Historically, place expressions were called *lvalues* and value
> expressions were called *rvalues*.
+An *assignee expression* is an expression that appears in the left operand of an
+[assignment][assign] expression. Explicitly, the assignee expressions are:
+
+- Place expressions.
+- [Underscores][_UnderscoreExpression_].
+- [Tuples][_TupleExpression_] of assignee expressions.
+- [Slices][_ArrayExpression_] of assingee expressions.
+- [Tuple structs][_StructExpression_] of assignee expressions.
+- [Structs][_StructExpression_] of assignee expressions (with optionally named
+ fields).
+- [Unit structs][_StructExpression_].
+
+Arbitrary parenthesisation is permitted inside assignee expressions.
+
### Moved and copied types
When a place expression is evaluated in a value expression context, or is bound
@@ -349,4 +364,5 @@ They are never allowed before:
[_TupleExpression_]: expressions/tuple-expr.md
[_TupleIndexingExpression_]: expressions/tuple-expr.md#tuple-indexing-expressions
[_TypeCastExpression_]: expressions/operator-expr.md#type-cast-expressions
+[_UnderscoreExpression_]: expressions/underscore-expr.md
[_UnsafeBlockExpression_]: expressions/block-expr.md#unsafe-blocks
diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md
index 61df3bd64..d6fa4c23a 100644
--- a/src/expressions/operator-expr.md
+++ b/src/expressions/operator-expr.md
@@ -428,13 +428,15 @@ assert_eq!(values[1], 3);
An *assignment expression* moves a value into a specified place.
-An assignment expression consists of a [mutable] [place expression], the *assigned place operand*, followed by an equals sign (`=`) and a [value expression], the *assigned value operand*.
+An assignment expression consists of a [mutable] [assignee expression], the *assignee operand*, followed by an equals sign (`=`) and a [value expression], the *assigned value operand*.
+In its most basic form, an assignee expression is a [place expression], and we discuss this case first.
+The more general case of destructuring assignment is discussed below, but this case always decomposes into sequential assignments to place expressions, which may be considered the more fundamental case.
-Unlike other place operands, the assigned place operand must be a place expression.
-Attempting to use a value expression is a compiler error rather than promoting it to a temporary.
+### Basic assignments
Evaluating assignment expressions begins by evaluating its operands.
-The assigned value operand is evaluated first, followed by the assigned place operand.
+The assigned value operand is evaluated first, followed by the assignee expression.
+For destructuring assignment, subexpressions of the assignee expression are evaluated left-to-right.
> **Note**: This is different than other expressions in that the right operand is evaluated before the left one.
@@ -451,6 +453,60 @@ let y = 0;
x = y;
```
+### Destructuring assignments
+
+Destructuring assignment is a counterpart to destructuring pattern matches for variable declaration, permitting assignment to complex values, such as tuples or structs.
+For instance, we may swap two mutable variables:
+
+```rust
+let (mut a, mut b) = (0, 1);
+// Swap `a` and `b` using destructuring assignment.
+(b, a) = (a, b);
+```
+
+In contrast to destructuring declarations using `let`, patterns may not appear on the left-hand side of an assignment due to syntactic ambiguities.
+Instead, a group of expressions that correspond to patterns are designated to be [assignee expressions][assignee expression], and permitted on the left-hand side of an assignment.
+Assignee expressions are then desugared to pattern matches followed by sequential assignment.
+The desugared patterns must be irrefutable: in particular, this means that only slice patterns whose length is known at compile-time, and the trivial slice `[..]`, are permitted for destructuring assignment.
+
+The desugaring method is straightforward, and is illustrated best by example.
+
+```rust
+# struct Struct { x: u32, y: u32 }
+# let (mut a, mut b) = (0, 0);
+(a, b) = (3, 4);
+
+[a, b] = [3, 4];
+
+Struct { x: a, y: b } = Struct { x: 3, y: 4};
+
+// desugars to:
+
+{
+ let (_a, _b) = (3, 4);
+ a = _a;
+ b = _b;
+}
+
+{
+ let [_a, _b] = [3, 4];
+ a = _a;
+ b = _b;
+}
+
+{
+ let Struct { x: _a, y: _b } = Struct { x: 3, y: 4};
+ a = _a;
+ b = _b;
+}
+```
+
+Identifiers are not forbidden from being used multiple times in a single assignee expression.
+
+[Underscore expressions][_UnderscoreExpression_] and empty [range expressions][_RangeExpression_] may be used to ignore certain values, without binding them.
+
+Note that default binding modes do not apply for the desugared expression.
+
## Compound assignment expressions
> **Syntax**\
@@ -530,6 +586,7 @@ See [this test] for an example of using this dependency.
[logical xor]: ../types/boolean.md#logical-xor
[mutable]: ../expressions.md#mutability
[place expression]: ../expressions.md#place-expressions-and-value-expressions
+[assignee expression]: ../expressions.md#place-expressions-and-value-expressions
[undefined behavior]: ../behavior-considered-undefined.md
[unit]: ../types/tuple.md
[value expression]: ../expressions.md#place-expressions-and-value-expressions
@@ -552,3 +609,5 @@ See [this test] for an example of using this dependency.
[_Expression_]: ../expressions.md
[_TypeNoBounds_]: ../types.md#type-expressions
+[_RangeExpression_]: ./range-expr.md
+[_UnderscoreExpression_]: ./underscore-expr.md
diff --git a/src/expressions/underscore-expr.md b/src/expressions/underscore-expr.md
new file mode 100644
index 000000000..069f227e9
--- /dev/null
+++ b/src/expressions/underscore-expr.md
@@ -0,0 +1,17 @@
+# `_` expressions
+
+> **Syntax**\
+> _UnderscoreExpression_ :\
+> `_`
+
+Underscore expressions, denoted with the symbol `_`, are used to signify a
+placeholder in a destructuring assignment. They may only appear in the left-hand
+side of an assignment.
+
+An example of an `_` expression:
+
+```rust
+let p = (1, 2);
+let mut a = 0;
+(_, a) = p;
+```
diff --git a/src/macros-by-example.md b/src/macros-by-example.md
index f7e0ed4dd..da286a672 100644
--- a/src/macros-by-example.md
+++ b/src/macros-by-example.md
@@ -140,6 +140,11 @@ the syntax element that matched them. The keyword metavariable `$crate` can be
used to refer to the current crate; see [Hygiene] below. Metavariables can be
transcribed more than once or not at all.
+For reasons of backwards compatibility, though `_` [is also an
+expression][_UnderscoreExpression_], a standalone underscore is not matched by
+the `expr` fragment specifier. However, `_` is matched by the `expr` fragment
+specifier when it appears as a subexpression.
+
> **Edition Differences**: Starting with the 2021 edition, `pat` fragment-specifiers match top-level or-patterns (that is, they accept [_Pattern_]).
>
> Before the 2021 edition, they match exactly the same fragments as `pat_param` (that is, they accept [_PatternNoTopAlt_]).
@@ -506,6 +511,7 @@ For more detail, see the [formal specification].
[_Token_]: tokens.md
[_TypePath_]: paths.md#paths-in-types
[_Type_]: types.md#type-expressions
+[_UnderscoreExpression_]: expressions/underscore-expr.md
[_Visibility_]: visibility-and-privacy.md
[formal specification]: macro-ambiguity.md
[token]: tokens.md
diff --git a/src/tokens.md b/src/tokens.md
index 88a6d7252..5516fb7b3 100644
--- a/src/tokens.md
+++ b/src/tokens.md
@@ -582,7 +582,7 @@ usages and meanings are defined in the linked pages.
| `>=` | Ge | [Greater than or equal to][comparison], [Generics]
| `<=` | Le | [Less than or equal to][comparison]
| `@` | At | [Subpattern binding]
-| `_` | Underscore | [Wildcard patterns], [Inferred types], Unnamed items in [constants], [extern crates], and [use declarations]
+| `_` | Underscore | [Wildcard patterns], [Inferred types], Unnamed items in [constants], [extern crates], [use declarations], and [destructuring assignment]
| `.` | Dot | [Field access][field], [Tuple index]
| `..` | DotDot | [Range][range], [Struct expressions], [Patterns], [Range Patterns][rangepat]
| `...` | DotDotDot | [Variadic functions][extern], [Range patterns]
@@ -625,6 +625,7 @@ them are referred to as "token trees" in [macros]. The three types of brackets
[compound]: expressions/operator-expr.md#compound-assignment-expressions
[constants]: items/constant-items.md
[dereference]: expressions/operator-expr.md#the-dereference-operator
+[destructuring assignment]: expressions/underscore-expr.md
[extern crates]: items/extern-crates.md
[extern]: items/external-blocks.md
[field]: expressions/field-expr.md