From 577542859786376bf14eeb75b42e5ed75df4ab75 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 11 Dec 2021 18:45:27 +0000 Subject: [PATCH 1/4] Document destructuring assignment --- src/SUMMARY.md | 1 + src/expressions.md | 28 ++++++++--- src/expressions/operator-expr.md | 81 ++++++++++++++++++++++++++++-- src/expressions/underscore-expr.md | 19 +++++++ 4 files changed, 118 insertions(+), 11 deletions(-) create mode 100644 src/expressions/underscore-expr.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index fbbd43673..2468d74a3 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 expression](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..a60f7a98e 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -428,13 +428,20 @@ 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. +Evaluating assignment expressions begins by evaluating its operands. 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 +458,67 @@ 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,ignore +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,ignore +(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 +598,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 +621,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..7886d34d0 --- /dev/null +++ b/src/expressions/underscore-expr.md @@ -0,0 +1,19 @@ +# `_` expression + +> **Syntax**\ +> _UnderscoreExpression_ :\ +>    `_` + +The underscore expression, denoted with the symbol `_`, is used to signify a +placeholder in a destructuring assignment. It may only appear in the left-hand +side of an assignment. + +An example of an `_` expression: + +```rust,ignore +let p = (1, 2); +let mut a = 0; +(_, a) = p; +``` + +[_Expression_]: ../expressions.md From 4115c9a3c2bd91f29445999891de4e8d26d60dc8 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 25 Dec 2021 13:34:29 +0000 Subject: [PATCH 2/4] Address comments --- src/SUMMARY.md | 2 +- src/expressions/operator-expr.md | 48 +++++++++++------------------- src/expressions/underscore-expr.md | 10 +++---- 3 files changed, 23 insertions(+), 37 deletions(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 2468d74a3..82d70d043 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -66,7 +66,7 @@ - [Match expressions](expressions/match-expr.md) - [Return expressions](expressions/return-expr.md) - [Await expressions](expressions/await-expr.md) - - [Underscore expression](expressions/underscore-expr.md) + - [Underscore expressions](expressions/underscore-expr.md) - [Patterns](patterns.md) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index a60f7a98e..d6fa4c23a 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -428,20 +428,15 @@ assert_eq!(values[1], 3); An *assignment expression* moves a value into a specified place. -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. +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. ### Basic assignments -Evaluating assignment expressions begins by evaluating its operands. 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.) +Evaluating assignment expressions begins by evaluating its operands. +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. @@ -460,29 +455,25 @@ 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: +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,ignore +```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. +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,ignore +```rust +# struct Struct { x: u32, y: u32 } +# let (mut a, mut b) = (0, 0); (a, b) = (3, 4); [a, b] = [3, 4]; @@ -510,12 +501,9 @@ Struct { x: a, y: b } = Struct { x: 3, y: 4}; } ``` -Identifiers are not forbidden from being used multiple times in a single -assignee expression. +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. +[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. diff --git a/src/expressions/underscore-expr.md b/src/expressions/underscore-expr.md index 7886d34d0..069f227e9 100644 --- a/src/expressions/underscore-expr.md +++ b/src/expressions/underscore-expr.md @@ -1,19 +1,17 @@ -# `_` expression +# `_` expressions > **Syntax**\ > _UnderscoreExpression_ :\ >    `_` -The underscore expression, denoted with the symbol `_`, is used to signify a -placeholder in a destructuring assignment. It may only appear in the left-hand +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,ignore +```rust let p = (1, 2); let mut a = 0; (_, a) = p; ``` - -[_Expression_]: ../expressions.md From 21239a9c264945e21dec60ddb8f741603e98563f Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 25 Dec 2021 13:41:31 +0000 Subject: [PATCH 3/4] Mention special matching behaviour of `_` for `macro_rules!` --- src/macros-by-example.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index f7e0ed4dd..2d4fefd31 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -140,6 +140,12 @@ 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, although `_` is a (keyword) identifier, +it is not matched by the `ident` fragment specifier. Similarly, 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 +512,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 From 9b91e9b82500bd782b31883197613983a5372272 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 17 Jan 2022 13:02:00 +0100 Subject: [PATCH 4/4] Address comments --- src/macros-by-example.md | 9 ++++----- src/tokens.md | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 2d4fefd31..da286a672 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -140,11 +140,10 @@ 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, although `_` is a (keyword) identifier, -it is not matched by the `ident` fragment specifier. Similarly, 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. +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_]). > 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