Skip to content

Commit fd97729

Browse files
authored
Merge pull request #967 from Havvy/expr-cleanup
Editorial cleanup on expressions (part 1)
2 parents 9e24a47 + 2367297 commit fd97729

File tree

8 files changed

+155
-109
lines changed

8 files changed

+155
-109
lines changed

src/expressions.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ In this way, the structure of expressions dictates the structure of execution.
5555
Blocks are just another kind of expression, so blocks, statements, expressions,
5656
and blocks again can recursively nest inside each other to an arbitrary depth.
5757

58+
> **Note**: We give names to the operands of expressions so that we may discuss
59+
> them, but these names are not stable and may be changed.
60+
5861
## Expression precedence
5962

6063
The precedence of Rust operators and expressions is ordered as follows, going
@@ -137,7 +140,7 @@ assert_eq!(
137140
## Place Expressions and Value Expressions
138141

139142
Expressions are divided into two main categories: place expressions and
140-
value expressions. Likewise within each expression, sub-expressions may occur
143+
value expressions. Likewise within each expression, operands may occur
141144
in either place context or value context. The evaluation of an expression
142145
depends both on its own category and the context it occurs within.
143146

src/expressions/array-expr.md

+18-10
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,28 @@
1010
> &nbsp;&nbsp; &nbsp;&nbsp; [_Expression_] ( `,` [_Expression_] )<sup>\*</sup> `,`<sup>?</sup>\
1111
> &nbsp;&nbsp; | [_Expression_] `;` [_Expression_]
1212
13-
An _[array] expression_ can be written by enclosing zero or more comma-separated expressions of uniform type in square brackets.
13+
*Array expressions* construct [arrays][array].
14+
Array expressions come in two forms.
15+
16+
The first form lists out every value in the array.
17+
The syntax for this form is a comma-separated list of expressions of uniform type enclosed in square brackets.
1418
This produces an array containing each of these values in the order they are written.
1519

16-
Alternatively there can be exactly two expressions inside the brackets, separated by a semicolon.
17-
The expression after the `;` must have type `usize` and be a [constant expression], such as a [literal] or a [constant item].
18-
`[a; b]` creates an array containing `b` copies of the value of `a`.
19-
If the expression after the semicolon has a value greater than 1 then this requires that the type of `a` is [`Copy`], or `a` must be a path to a constant item.
20+
The syntax for the second form is two expressions separated by a semicolon (`;`) enclosed in square brackets.
21+
The expression before the `;` is called the *repeat operand*.
22+
The expression after the `;` is called the *length operand*.
23+
It must have type `usize` and be a [constant expression], such as a [literal] or a [constant item].
24+
An array expression of this form creates an array with the length of the value of the legnth operand with each element a copy of the repeat operand.
25+
That is, `[a; b]` creates an array containing `b` copies of the value of `a`.
26+
If the length operand has a value greater than 1 then this requires that the type of the repeat operand is [`Copy`] or that it must be a [path] to a constant item.
2027

21-
When the repeat expression `a` is a constant item, it is evaluated `b` times.
22-
If `b` is 0, the constant item is not evaluated at all.
23-
For expressions that are not a constant item, it is evaluated exactly once, and then the result is copied `b` times.
28+
When the repeat operand is a constant item, it is evaluated the length operand's value times.
29+
If that value is `0`, then the constant item is not evaluated at all.
30+
For expressions that are not a constant item, it is evaluated exactly once, and then the result is copied the length operand's value times.
2431

2532
<div class="warning">
2633

27-
Warning: In the case where `b` is 0, and `a` is a non-constant item, there is currently a bug in `rustc` where the value `a` is evaluated but not dropped, thus causing a leak.
34+
Warning: In the case where the length operand is 0, and the repeat operand is a non-constant item, there is currently a bug in `rustc` where the value `a` is evaluated but not dropped, thus causing a leak.
2835
See [issue #74836](https://github.com/rust-lang/rust/issues/74836).
2936

3037
</div>
@@ -49,7 +56,7 @@ const EMPTY: Vec<i32> = Vec::new();
4956
> _IndexExpression_ :\
5057
> &nbsp;&nbsp; [_Expression_] `[` [_Expression_] `]`
5158
52-
[Array] and [slice]-typed expressions can be indexed by writing a square-bracket-enclosed expression of type `usize` (the index) after them.
59+
[Array] and [slice]-typed values can be indexed by writing a square-bracket-enclosed expression of type `usize` (the index) after them.
5360
When the array is mutable, the resulting [memory location] can be assigned to.
5461

5562
For other types an index expression `a[b]` is equivalent to `*std::ops::Index::index(&a, b)`, or `*std::ops::IndexMut::index_mut(&mut a, b)` in a mutable place expression context.
@@ -91,4 +98,5 @@ The array index expression can be implemented for types other than arrays and sl
9198
[constant item]: ../items/constant-items.md
9299
[literal]: ../tokens.md#literals
93100
[memory location]: ../expressions.md#place-expressions-and-value-expressions
101+
[path]: path-expr.md
94102
[slice]: ../types/slice.md

src/expressions/await-expr.md

+17-19
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,32 @@
44
> _AwaitExpression_ :\
55
> &nbsp;&nbsp; [_Expression_] `.` `await`
66
7+
*Await expressions* suspend the current computation until the given future is ready to produce a value.
8+
The syntax for an await expression is an expression with a type that implements the [Future] trait, called the *future operand*, then the token `.`, and then the `await` keyword.
79
Await expressions are legal only within an [async context], like an [`async fn`] or an [`async` block].
8-
They operate on a [future].
9-
Their effect is to suspend the current computation until the given future is ready to produce a value.
1010

11-
More specifically, an `<expr>.await` expression has the following effect.
11+
More specifically, an await expression has the following effect.
1212

13-
1. Evaluate `<expr>` to a [future] `tmp`;
13+
1. Evaluate the future operand to a [future] `tmp`;
1414
2. Pin `tmp` using [`Pin::new_unchecked`];
1515
3. This pinned future is then polled by calling the [`Future::poll`] method and passing it the current [task context](#task-context);
1616
3. If the call to `poll` returns [`Poll::Pending`], then the future returns `Poll::Pending`, suspending its state so that, when the surrounding async context is re-polled,execution returns to step 2;
1717
4. Otherwise the call to `poll` must have returned [`Poll::Ready`], in which case the value contained in the [`Poll::Ready`] variant is used as the result of the `await` expression itself.
1818

19-
[`async fn`]: ../items/functions.md#async-functions
20-
[`async` block]: block-expr.md#async-blocks
21-
[future]: ../../std/future/trait.Future.html
22-
[_Expression_]: ../expressions.md
23-
[`Future::poll`]: ../../std/future/trait.Future.html#tymethod.poll
24-
[`Context`]: ../../std/task/struct.Context.html
25-
[`Pin::new_unchecked`]: ../../std/pin/struct.Pin.html#method.new_unchecked
26-
[`Poll::Pending`]: ../../std/task/enum.Poll.html#variant.Pending
27-
[`Poll::Ready`]: ../../std/task/enum.Poll.html#variant.Ready
28-
2919
> **Edition differences**: Await expressions are only available beginning with Rust 2018.
3020
3121
## Task context
3222

3323
The task context refers to the [`Context`] which was supplied to the current [async context] when the async context itself was polled.
3424
Because `await` expressions are only legal in an async context, there must be some task context available.
3525

36-
[`Context`]: ../../std/task/struct.Context.html
37-
[async context]: ../expressions/block-expr.md#async-context
38-
3926
## Approximate desugaring
4027

41-
Effectively, an `<expr>.await` expression is roughly equivalent to the following (this desugaring is not normative):
28+
Effectively, an await expression is roughly equivalent to the following non-normative desugaring:
4229

4330
<!-- ignore: example expansion -->
4431
```rust,ignore
45-
match /* <expr> */ {
32+
match future_operand {
4633
mut pinned => loop {
4734
let mut pin = unsafe { Pin::new_unchecked(&mut pinned) };
4835
match Pin::future::poll(Pin::borrow(&mut pin), &mut current_context) {
@@ -55,3 +42,14 @@ match /* <expr> */ {
5542

5643
where the `yield` pseudo-code returns `Poll::Pending` and, when re-invoked, resumes execution from that point.
5744
The variable `current_context` refers to the context taken from the async environment.
45+
46+
[_Expression_]: ../expressions.md
47+
[`async fn`]: ../items/functions.md#async-functions
48+
[`async` block]: block-expr.md#async-blocks
49+
[`context`]: ../../std/task/struct.Context.html
50+
[`future::poll`]: ../../std/future/trait.Future.html#tymethod.poll
51+
[`pin::new_unchecked`]: ../../std/pin/struct.Pin.html#method.new_unchecked
52+
[`poll::Pending`]: ../../std/task/enum.Poll.html#variant.Pending
53+
[`poll::Ready`]: ../../std/task/enum.Poll.html#variant.Ready
54+
[async context]: ../expressions/block-expr.md#async-context
55+
[future]: ../../std/future/trait.Future.html

src/expressions/block-expr.md

+38-37
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,19 @@ A *block expression*, or *block*, is a control flow expression and anonymous nam
1616
As a control flow expression, a block sequentially executes its component non-item declaration statements and then its final optional expression.
1717
As an anonymous namespace scope, item declarations are only in scope inside the block itself and variables declared by `let` statements are in scope from the next statement until the end of the block.
1818

19-
Blocks are written as `{`, then any [inner attributes], then [statements], then an optional expression, and finally a `}`.
20-
Statements are usually required to be followed by a semicolon, with two exceptions.
21-
Item declaration statements do not need to be followed by a semicolon.
22-
Expression statements usually require a following semicolon except if its outer expression is a flow control expression.
19+
The syntax for a block is `{`, then any [inner attributes], then any number of [statements], then an optional expression, called the final operand, and finally a `}`.
20+
21+
Statements are usually required to be followed by a semicolon, with two exceptions:
22+
23+
1. Item declaration statements do not need to be followed by a semicolon.
24+
2. Expression statements usually require a following semicolon except if its outer expression is a flow control expression.
25+
2326
Furthermore, extra semicolons between statements are allowed, but these semicolons do not affect semantics.
2427

2528
When evaluating a block expression, each statement, except for item declaration statements, is executed sequentially.
26-
Then the final expression is executed, if given.
29+
Then the final operand is executed, if given.
2730

28-
The type of a block is the type of the final expression, or `()` if the final expression is omitted.
31+
The type of a block is the type of the final operand, or `()` if the final operand is omitted.
2932

3033
```rust
3134
# fn fn_call() {}
@@ -43,36 +46,37 @@ assert_eq!(5, five);
4346

4447
> Note: As a control flow expression, if a block expression is the outer expression of an expression statement, the expected type is `()` unless it is followed immediately by a semicolon.
4548
46-
Blocks are always [value expressions] and evaluate the last expression in value expression context.
47-
This can be used to force moving a value if really needed.
48-
For example, the following example fails on the call to `consume_self` because the struct was moved out of `s` in the block expression.
49-
50-
```rust,compile_fail
51-
struct Struct;
52-
53-
impl Struct {
54-
fn consume_self(self) {}
55-
fn borrow_self(&self) {}
56-
}
57-
58-
fn move_by_block_expression() {
59-
let s = Struct;
60-
61-
// Move the value out of `s` in the block expression.
62-
(&{ s }).borrow_self();
49+
Blocks are always [value expressions] and evaluate the last operand in value expression context.
6350

64-
// Fails to execute because `s` is moved out of.
65-
s.consume_self();
66-
}
67-
```
51+
> **Note**: This can be used to force moving a value if really needed.
52+
> For example, the following example fails on the call to `consume_self` because the struct was moved out of `s` in the block expression.
53+
>
54+
> ```rust,compile_fail
55+
> struct Struct;
56+
>
57+
> impl Struct {
58+
> fn consume_self(self) {}
59+
> fn borrow_self(&self) {}
60+
> }
61+
>
62+
> fn move_by_block_expression() {
63+
> let s = Struct;
64+
>
65+
> // Move the value out of `s` in the block expression.
66+
> (&{ s }).borrow_self();
67+
>
68+
> // Fails to execute because `s` is moved out of.
69+
> s.consume_self();
70+
> }
71+
> ```
6872
6973
## `async` blocks
7074
7175
> **<sup>Syntax</sup>**\
7276
> _AsyncBlockExpression_ :\
7377
> &nbsp;&nbsp; `async` `move`<sup>?</sup> _BlockExpression_
7478
75-
An *async block* is a variant of a block expression which evaluates to a *future*.
79+
An *async block* is a variant of a block expression which evaluates to a future.
7680
The final expression of the block, if present, determines the result value of the future.
7781
7882
Executing an async block is similar to executing a closure expression:
@@ -84,26 +88,17 @@ The actual data format for this type is unspecified.
8488
8589
> **Edition differences**: Async blocks are only available beginning with Rust 2018.
8690
87-
[`std::ops::Fn`]: ../../std/ops/trait.Fn.html
88-
[`std::future::Future`]: ../../std/future/trait.Future.html
89-
9091
### Capture modes
9192
9293
Async blocks capture variables from their environment using the same [capture modes] as closures.
9394
Like closures, when written `async { .. }` the capture mode for each variable will be inferred from the content of the block.
9495
`async move { .. }` blocks however will move all referenced variables into the resulting future.
9596
96-
[capture modes]: ../types/closure.md#capture-modes
97-
[shared references]: ../types/pointer.md#shared-references-
98-
[mutable reference]: ../types/pointer.md#mutables-references-
99-
10097
### Async context
10198
10299
Because async blocks construct a future, they define an **async context** which can in turn contain [`await` expressions].
103100
Async contexts are established by async blocks as well as the bodies of async functions, whose semantics are defined in terms of async blocks.
104101
105-
[`await` expressions]: await-expr.md
106-
107102
### Control-flow operators
108103
109104
Async blocks act like a function boundary, much like closures.
@@ -171,16 +166,22 @@ fn is_unix_platform() -> bool {
171166
[_ExpressionWithoutBlock_]: ../expressions.md
172167
[_InnerAttribute_]: ../attributes.md
173168
[_Statement_]: ../statements.md
169+
[`await` expressions]: await-expr.md
174170
[`cfg`]: ../conditional-compilation.md
175171
[`for`]: loop-expr.md#iterator-loops
176172
[`loop`]: loop-expr.md#infinite-loops
173+
[`std::ops::Fn`]: ../../std/ops/trait.Fn.html
174+
[`std::future::Future`]: ../../std/future/trait.Future.html
177175
[`while let`]: loop-expr.md#predicate-pattern-loops
178176
[`while`]: loop-expr.md#predicate-loops
179177
[array expressions]: array-expr.md
180178
[call expressions]: call-expr.md
179+
[capture modes]: ../types/closure.md#capture-modes
181180
[function]: ../items/functions.md
182181
[inner attributes]: ../attributes.md
183182
[method]: ../items/associated-items.md#methods
183+
[mutable reference]: ../types/pointer.md#mutables-references-
184+
[shared references]: ../types/pointer.md#shared-references-
184185
[statement]: ../statements.md
185186
[statements]: ../statements.md
186187
[struct]: struct-expr.md

src/expressions/call-expr.md

+12-10
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
> _CallParams_ :\
88
> &nbsp;&nbsp; [_Expression_]&nbsp;( `,` [_Expression_] )<sup>\*</sup> `,`<sup>?</sup>
99
10-
A _call expression_ consists of an expression followed by a parenthesized expression-list.
11-
It invokes a function, providing zero or more input variables.
10+
A *call expression* calls a function.
11+
The syntax of a call expression is an expression, called the *function operand*, followed by a parenthesized comma-separated list of expression, called the *argument operands*.
1212
If the function eventually returns, then the expression completes.
13-
For [non-function types](../types/function-item.md), the expression f(...) uses the method on one of the [`std::ops::Fn`], [`std::ops::FnMut`] or [`std::ops::FnOnce`] traits, which differ in whether they take the type by reference, mutable reference, or take ownership respectively.
13+
For [non-function types], the expression `f(...)` uses the method on one of the [`std::ops::Fn`], [`std::ops::FnMut`] or [`std::ops::FnOnce`] traits, which differ in whether they take the type by reference, mutable reference, or take ownership respectively.
1414
An automatic borrow will be taken if needed.
15-
Rust will also automatically dereference `f` as required.
15+
The function operand will also be [automatically dereferenced] as required.
16+
1617
Some examples of call expressions:
1718

1819
```rust
@@ -23,13 +24,12 @@ let name: &'static str = (|| "Rust")();
2324

2425
## Disambiguating Function Calls
2526

26-
Rust treats all function calls as sugar for a more explicit, [fully-qualified syntax].
27-
Upon compilation, Rust will desugar all function calls into the explicit form.
28-
Rust may sometimes require you to qualify function calls with trait, depending on the ambiguity of a call in light of in-scope items.
27+
All function calls are sugar for a more explicit [fully-qualified syntax].
28+
Function calls may need to be fully qualified, depending on the ambiguity of a call in light of in-scope items.
2929

30-
> **Note**: In the past, the Rust community used the terms "Unambiguous Function Call Syntax", "Universal Function Call Syntax", or "UFCS", in documentation, issues, RFCs, and other community writings.
31-
> However, the term lacks descriptive power and potentially confuses the issue at hand.
32-
> We mention it here for searchability's sake.
30+
> **Note**: In the past, the terms "Unambiguous Function Call Syntax", "Universal Function Call Syntax", or "UFCS", have been used in documentation, issues, RFCs, and other community writings.
31+
> However, these terms lack descriptive power and potentially confuse the issue at hand.
32+
> We mention them here for searchability's sake.
3333
3434
Several situations often occur which result in ambiguities about the receiver or referent of method or associated function calls.
3535
These situations may include:
@@ -92,4 +92,6 @@ Refer to [RFC 132] for further details and motivations.
9292
[`std::ops::FnMut`]: ../../std/ops/trait.FnMut.html
9393
[`std::ops::FnOnce`]: ../../std/ops/trait.FnOnce.html
9494
[`std::ops::Fn`]: ../../std/ops/trait.Fn.html
95+
[automatically dereferenced]: field-expr.md#automatic-dereferencing
9596
[fully-qualified syntax]: ../paths.md#qualified-paths
97+
[non-function types]: ../types/function-item.md

0 commit comments

Comments
 (0)