summaryrefslogtreecommitdiffstats
path: root/src/doc/reference/src/statements.md
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc/reference/src/statements.md')
-rw-r--r--src/doc/reference/src/statements.md86
1 files changed, 47 insertions, 39 deletions
diff --git a/src/doc/reference/src/statements.md b/src/doc/reference/src/statements.md
index 8d9c21d7d..c2ae585a0 100644
--- a/src/doc/reference/src/statements.md
+++ b/src/doc/reference/src/statements.md
@@ -9,35 +9,27 @@
>    | [_MacroInvocationSemi_]
-A *statement* is a component of a [block], which is in turn a component of an
-outer [expression] or [function].
+A *statement* is a component of a [block], which is in turn a component of an outer [expression] or [function].
-Rust has two kinds of statement: [declaration
-statements](#declaration-statements) and [expression
-statements](#expression-statements).
+Rust has two kinds of statement: [declaration statements](#declaration-statements) and [expression statements](#expression-statements).
## Declaration statements
-A *declaration statement* is one that introduces one or more *names* into the
-enclosing statement block. The declared names may denote new variables or new
-[items][item].
+A *declaration statement* is one that introduces one or more *names* into the enclosing statement block.
+The declared names may denote new variables or new [items][item].
-The two kinds of declaration statements are item declarations and `let`
-statements.
+The two kinds of declaration statements are item declarations and `let` statements.
### Item declarations
-An *item declaration statement* has a syntactic form identical to an
-[item declaration][item] within a [module]. Declaring an item within a statement
-block restricts its scope to the block containing the statement. The item is not
-given a [canonical path] nor are any sub-items it may declare. The exception to
-this is that associated items defined by [implementations] are still accessible
-in outer scopes as long as the item and, if applicable, trait are accessible.
+An *item declaration statement* has a syntactic form identical to an [item declaration][item] within a [module].
+Declaring an item within a statement block restricts its scope to the block containing the statement.
+The item is not given a [canonical path] nor are any sub-items it may declare.
+The exception to this is that associated items defined by [implementations] are still accessible in outer scopes as long as the item and, if applicable, trait are accessible.
It is otherwise identical in meaning to declaring the item inside a module.
-There is no implicit capture of the containing function's generic parameters,
-parameters, and local variables. For example, `inner` may not access
-`outer_var`.
+There is no implicit capture of the containing function's generic parameters, parameters, and local variables.
+For example, `inner` may not access `outer_var`.
```rust
fn outer() {
@@ -54,16 +46,32 @@ fn outer() {
> **<sup>Syntax</sup>**\
> _LetStatement_ :\
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> `let` [_PatternNoTopAlt_]
-> ( `:` [_Type_] )<sup>?</sup> (`=` [_Expression_] )<sup>?</sup> `;`
+> ( `:` [_Type_] )<sup>?</sup> (`=` [_Expression_] [†](#let-else-restriction)
+> ( `else` [_BlockExpression_]) <sup>?</sup> ) <sup>?</sup> `;`
+>
+> <span id="let-else-restriction">† When an `else` block is specified, the
+> _Expression_ must not be a [_LazyBooleanExpression_], or end with a `}`.</span>
+
+A *`let` statement* introduces a new set of [variables], given by a [pattern].
+The pattern is followed optionally by a type annotation and then either ends, or is followed by an initializer expression plus an optional `else` block.
+When no type annotation is given, the compiler will infer the type, or signal an error if insufficient type information is available for definite inference.
+Any variables introduced by a variable declaration are visible from the point of declaration until the end of the enclosing block scope, except when they are shadowed by another variable declaration.
+
+If an `else` block is not present, the pattern must be irrefutable.
+If an `else` block is present, the pattern may be refutable.
+If the pattern does not match (this requires it to be refutable), the `else` block is executed.
+The `else` block must always diverge (evaluate to the [never type]).
-A *`let` statement* introduces a new set of [variables], given by an
-irrefutable [pattern]. The pattern is followed optionally by a type
-annotation and then optionally by an initializer expression. When no
-type annotation is given, the compiler will infer the type, or signal
-an error if insufficient type information is available for definite
-inference. Any variables introduced by a variable declaration are visible
-from the point of declaration until the end of the enclosing block scope,
-except when they are shadowed by another variable declaration.
+```rust
+let (mut v, w) = (vec![1, 2, 3], 42); // The bindings may be mut or const
+let Some(t) = v.pop() else { // Refutable patterns require an else block
+ panic!(); // The else block must diverge
+};
+let [u, v] = [v[0], v[1]] else { // This pattern is irrefutable, so the compiler
+ // will lint as the else block is redundant.
+ panic!();
+};
+```
## Expression statements
@@ -72,16 +80,13 @@ except when they are shadowed by another variable declaration.
> &nbsp;&nbsp; &nbsp;&nbsp; [_ExpressionWithoutBlock_][expression] `;`\
> &nbsp;&nbsp; | [_ExpressionWithBlock_][expression] `;`<sup>?</sup>
-An *expression statement* is one that evaluates an [expression] and ignores its
-result. As a rule, an expression statement's purpose is to trigger the effects
-of evaluating its expression.
+An *expression statement* is one that evaluates an [expression] and ignores its result.
+As a rule, an expression statement's purpose is to trigger the effects of evaluating its expression.
-An expression that consists of only a [block expression][block] or control flow
-expression, if used in a context where a statement is permitted, can omit the
-trailing semicolon. This can cause an ambiguity between it being parsed as a
-standalone statement and as a part of another expression; in this case, it is
-parsed as a statement. The type of [_ExpressionWithBlock_][expression]
-expressions when used as statements must be the unit type.
+An expression that consists of only a [block expression][block] or control flow expression, if used in a context where a statement is permitted, can omit the trailing semicolon.
+This can cause an ambiguity between it being parsed as a standalone statement and as a part of another expression;
+in this case, it is parsed as a statement.
+The type of [_ExpressionWithBlock_][expression] expressions when used as statements must be the unit type.
```rust
# let mut v = vec![1, 2, 3];
@@ -113,14 +118,15 @@ if true {
## Attributes on Statements
-Statements accept [outer attributes]. The attributes that have meaning on a
-statement are [`cfg`], and [the lint check attributes].
+Statements accept [outer attributes].
+The attributes that have meaning on a statement are [`cfg`], and [the lint check attributes].
[block]: expressions/block-expr.md
[expression]: expressions.md
[function]: items/functions.md
[item]: items.md
[module]: items/modules.md
+[never type]: types/never.md
[canonical path]: paths.md#canonical-paths
[implementations]: items/implementations.md
[variables]: variables.md
@@ -128,9 +134,11 @@ statement are [`cfg`], and [the lint check attributes].
[`cfg`]: conditional-compilation.md
[the lint check attributes]: attributes/diagnostics.md#lint-check-attributes
[pattern]: patterns.md
+[_BlockExpression_]: expressions/block-expr.md
[_ExpressionStatement_]: #expression-statements
[_Expression_]: expressions.md
[_Item_]: items.md
+[_LazyBooleanExpression_]: expressions/operator-expr.md#lazy-boolean-operators
[_LetStatement_]: #let-statements
[_MacroInvocationSemi_]: macros.md#macro-invocation
[_OuterAttribute_]: attributes.md