Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add identifier syntax to statements.md #1611

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/statements-and-expressions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Statements and expressions

r[stmt-expr]

Rust is _primarily_ an expression language.
This means that most forms of value-producing or effect-causing evaluation are directed by the uniform syntax category of _expressions_.
Each kind of expression can typically _nest_ within each other kind of expression, and rules for evaluation of expressions involve specifying both the value produced by the expression and the order in which its sub-expressions are themselves evaluated.
Expand Down
36 changes: 35 additions & 1 deletion src/statements.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Statements

r[statement]

r[statement.syntax]
> **<sup>Syntax</sup>**\
> _Statement_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; `;`\
Expand All @@ -8,26 +11,37 @@
> &nbsp;&nbsp; | [_ExpressionStatement_]\
> &nbsp;&nbsp; | [_MacroInvocationSemi_]


r[statement.intro]
A *statement* is a component of a [block], which is in turn a component of an outer [expression] or [function].

r[statement.kind]
Rust has two kinds of statement: [declaration statements](#declaration-statements) and [expression statements](#expression-statements).

## Declaration statements

r[statement.decl]

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.

### Item declarations

r[statement.item]

r[statement.item.intro]
An *item declaration statement* has a syntactic form identical to an [item declaration][item] within a [module].

r[statement.item.scope]
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.

r[statement.item.associated-scope]
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.

r[statement.item.outer-generics]
There is no implicit capture of the containing function's generic parameters, parameters, and local variables.
For example, `inner` may not access `outer_var`.

Expand All @@ -43,6 +57,9 @@ fn outer() {

### `let` statements

r[statement.let]

r[statement.let.syntax]
> **<sup>Syntax</sup>**\
> _LetStatement_ :\
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> `let` [_PatternNoTopAlt_]
Expand All @@ -52,13 +69,21 @@ fn outer() {
> <span id="let-else-restriction">† When an `else` block is specified, the
> _Expression_ must not be a [_LazyBooleanExpression_], or end with a `}`.</span>

r[statement.let.intro]
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.

r[statement.let.inference]
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.

r[statement.let.scope]
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.

r[statement.let.constraint]
If an `else` block is not present, the pattern must be irrefutable.
If an `else` block is present, the pattern may be refutable.

r[statement.let.behavior]
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]).

Expand All @@ -75,17 +100,24 @@ let [u, v] = [v[0], v[1]] else { // This pattern is irrefutable, so the compiler

## Expression statements

r[statement.expr]

r[statement.expr.syntax]
> **<sup>Syntax</sup>**\
> _ExpressionStatement_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; [_ExpressionWithoutBlock_][expression] `;`\
> &nbsp;&nbsp; | [_ExpressionWithBlock_][expression] `;`<sup>?</sup>

r[statement.expr.intro]
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.

r[statement.expr.restriction-semicolon]
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.

r[statement.expr.constraint-block]
The type of [_ExpressionWithBlock_][expression] expressions when used as statements must be the unit type.

```rust
Expand Down Expand Up @@ -118,6 +150,8 @@ if true {

## Attributes on Statements

r[statement.attribute]

Statements accept [outer attributes].
The attributes that have meaning on a statement are [`cfg`], and [the lint check attributes].

Expand Down