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 Spec Identifier Syntax to expressions.md and subchapters #1591

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 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
58 changes: 57 additions & 1 deletion src/expressions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Expressions

r[expr]

r[expr.syntax]
> **<sup>Syntax</sup>**\
> _Expression_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; _ExpressionWithoutBlock_\
Expand Down Expand Up @@ -43,22 +46,32 @@
> &nbsp;&nbsp; &nbsp;&nbsp; | [_MatchExpression_]\
> &nbsp;&nbsp; )

r[expr.intro]
An expression may have two roles: it always produces a *value*, and it may have *effects* (otherwise known as "side effects").

r[expr.evaluation]
An expression *evaluates to* a value, and has effects during *evaluation*.

r[expr.operands]
Many expressions contain sub-expressions, called the *operands* of the expression.

r[expr.behaviour]
traviscross marked this conversation as resolved.
Show resolved Hide resolved
The meaning of each kind of expression dictates several things:

* Whether or not to evaluate the operands when evaluating the expression
* The order in which to evaluate the operands
* How to combine the operands' values to obtain the value of the expression

r[expr.structure]
In this way, the structure of expressions dictates the structure of execution.
Blocks are just another kind of expression, so blocks, statements, expressions, and blocks again can recursively nest inside each other to an arbitrary depth.

> **Note**: We give names to the operands of expressions so that we may discuss them, but these names are not stable and may be changed.

## Expression precedence

r[expr.precedence]

The precedence of Rust operators and expressions is ordered as follows, going from strong to weak.
Binary Operators at the same precedence level are grouped in the order given by their associativity.

Expand Down Expand Up @@ -86,6 +99,9 @@ Binary Operators at the same precedence level are grouped in the order given by

## Evaluation order of operands

r[expr.operand-order]

r[expr.operand-order.default]
The following list of expressions all evaluate their operands the same way, as described after the list.
Other expressions either don't take operands or evaluate them conditionally as described on their respective pages.

Expand All @@ -109,6 +125,7 @@ Other expressions either don't take operands or evaluate them conditionally as d
* Range expression
* Return expression

r[expr.operand-order.operands-before-primary]
The operands of these expressions are evaluated prior to applying the effects of the expression.
Expressions taking multiple operands are evaluated left to right as written in the source code.

Expand All @@ -132,17 +149,27 @@ assert_eq!(

## Place Expressions and Value Expressions

r[expr.place-value]

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

r[expr.place-value.place-memory-location]
A *place expression* is an expression that represents a memory location.

r[expr.place-value.place-expr-kinds]
These expressions are [paths] which refer to local variables, [static variables], [dereferences][deref] (`*expr`), [array indexing] expressions (`expr[expr]`), [field] references (`expr.f`) and parenthesized place expressions.

r[expr.place-value.value-expr-kinds]
All other expressions are value expressions.

r[expr.place-value.value-result]
A *value expression* is an expression that represents an actual value.

r[expr.place-value.place-context]
The following contexts are *place expression* contexts:

* The left operand of a [compound assignment] expression.
Expand All @@ -157,6 +184,7 @@ The following contexts are *place expression* contexts:

> Note: Historically, place expressions were called *lvalues* and value expressions were called *rvalues*.

r[expr.place-value.assignee]
An *assignee expression* is an expression that appears in the left operand of an [assignment][assign] expression.
Explicitly, the assignee expressions are:

Expand All @@ -169,29 +197,46 @@ Explicitly, the assignee expressions are:
fields).
- [Unit structs][_StructExpression_].

r[expr.place-value.parentehesis]
Arbitrary parenthesisation is permitted inside assignee expressions.

### Moved and copied types

r[expr.move]

r[expr.move.intro]
When a place expression is evaluated in a value expression context, or is bound by value in a pattern, it denotes the value held _in_ that memory location.

r[expr.move.copy]
If the type of that value implements [`Copy`], then the value will be copied.

r[expr.move.requires-sized]
In the remaining situations, if that type is [`Sized`], then it may be possible to move the value.

r[expr.move.movable-place]
Only the following place expressions may be moved out of:

* [Variables] which are not currently borrowed.
* [Temporary values](#temporaries).
* [Fields][field] of a place expression which can be moved out of and don't implement [`Drop`].
* The result of [dereferencing][deref] an expression with type [`Box<T>`] and that can also be moved out of.

r[expr.move.deinitialization]
After moving out of a place expression that evaluates to a local variable, the location is deinitialized and cannot be read from again until it is reinitialized.

r[expr.move.place-invalid]
In all other cases, trying to use a place expression in a value expression context is an error.

### Mutability

r[expr.mut]

r[expr.mut.intro]
For a place expression to be [assigned][assign] to, mutably [borrowed][borrow], [implicitly mutably borrowed], or bound to a pattern containing `ref mut`, it must be _mutable_.
We call these *mutable place expressions*.
In contrast, other place expressions are called *immutable place expressions*.

r[expr.mut.valid-places]
The following expressions can be mutable place expression contexts:

* Mutable [variables] which are not currently borrowed.
Expand All @@ -208,12 +253,17 @@ The following expressions can be mutable place expression contexts:

### Temporaries

r[expr.temporary]

When using a value expression in most place expression contexts, a temporary unnamed memory location is created and initialized to that value.
The expression evaluates to that location instead, except if [promoted] to a `static`.
The [drop scope] of the temporary is usually the end of the enclosing statement.

### Implicit Borrows

r[expr.implicit-borrow]

r[expr.implicit-borrow-intro]
Certain expressions will treat an expression as a place expression by implicitly borrowing it.
For example, it is possible to compare two unsized [slices][slice] for equality directly, because the `==` operator implicitly borrows its operands:

Expand All @@ -230,6 +280,7 @@ let b: &[i32];
::std::cmp::PartialEq::eq(&*a, &*b);
```

r[expr.implicit-borrow.application]
Implicit borrows may be taken in the following expressions:

* Left operand in [method-call] expressions.
Expand All @@ -242,23 +293,28 @@ Implicit borrows may be taken in the following expressions:

## Overloading Traits

r[expr.overload]

Many of the following operators and expressions can also be overloaded for other types using traits in `std::ops` or `std::cmp`.
These traits also exist in `core::ops` and `core::cmp` with the same names.

## Expression Attributes

r[expr.attr]

r[expr.attr.restriction]
[Outer attributes][_OuterAttribute_] before an expression are allowed only in a few specific cases:

* Before an expression used as a [statement].
* Elements of [array expressions], [tuple expressions], [call expressions], and tuple-style [struct] expressions.
* The tail expression of [block expressions].
<!-- Keep list in sync with block-expr.md -->

r[expr.attr.never-before]
They are never allowed before:
* [Range][_RangeExpression_] expressions.
* Binary operator expressions ([_ArithmeticOrLogicalExpression_], [_ComparisonExpression_], [_LazyBooleanExpression_], [_TypeCastExpression_], [_AssignmentExpression_], [_CompoundAssignmentExpression_]).


[block expressions]: expressions/block-expr.md
[call expressions]: expressions/call-expr.md
[field]: expressions/field-expr.md
Expand Down
33 changes: 33 additions & 0 deletions src/expressions/array-expr.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Array and array index expressions

r[expr.array]

## Array expressions

r[expr.array.syntax]
> **<sup>Syntax</sup>**\
> _ArrayExpression_ :\
> &nbsp;&nbsp; `[` _ArrayElements_<sup>?</sup> `]`
Expand All @@ -10,23 +13,45 @@
> &nbsp;&nbsp; &nbsp;&nbsp; [_Expression_] ( `,` [_Expression_] )<sup>\*</sup> `,`<sup>?</sup>\
> &nbsp;&nbsp; | [_Expression_] `;` [_Expression_]

r[expr.array.constructor]
*Array expressions* construct [arrays][array].
Array expressions come in two forms.

r[expr.array.array]
The first form lists out every value in the array.

r[expr.array.array-syntax]
The syntax for this form is a comma-separated list of expressions of uniform type enclosed in square brackets.

r[expr.array.array-behaviour]
This produces an array containing each of these values in the order they are written.

r[expr.array.repeat]
The syntax for the second form is two expressions separated by a semicolon (`;`) enclosed in square brackets.

r[expr.array.repeat-operand]
The expression before the `;` is called the *repeat operand*.

r[expr.array.length-operand]
The expression after the `;` is called the *length operand*.

r[expr.array.length-restriction]
It must have type `usize` and be a [constant expression], such as a [literal] or a [constant item].

r[expr.array.repeat-behaviour]
An array expression of this form creates an array with the length of the value of the length operand with each element being a copy of the repeat operand.
That is, `[a; b]` creates an array containing `b` copies of the value of `a`.

r[expr.array.repeat-copy]
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.

r[expr.array.repeat-const-item]
When the repeat operand is a constant item, it is evaluated the length operand's value times.

r[expr.array.repeat-evaluation-zero]
If that value is `0`, then the constant item is not evaluated at all.

r[expr.array.repeat-non-const]
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.

```rust
Expand All @@ -41,17 +66,24 @@ const EMPTY: Vec<i32> = Vec::new();

## Array and slice indexing expressions

r[expr.array.index]

> **<sup>Syntax</sup>**\
> _IndexExpression_ :\
> &nbsp;&nbsp; [_Expression_] `[` [_Expression_] `]`

r[expr.array.index.array]
[Array] and [slice]-typed values can be indexed by writing a square-bracket-enclosed expression of type `usize` (the index) after them.
When the array is mutable, the resulting [memory location] can be assigned to.

r[expr.array.index.trait]
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.
Just as with methods, Rust will also insert dereference operations on `a` repeatedly to find an implementation.

r[expr.array.index.zero-index]
Indices are zero-based for arrays and slices.

r[expr.array.index.const]
Array access is a [constant expression], so bounds can be checked at compile-time with a constant index value.
Otherwise a check will be performed at run-time that will put the thread in a _panicked state_ if it fails.

Expand All @@ -73,6 +105,7 @@ let arr = ["a", "b"];
arr[10]; // warning: index out of bounds
```

r[expr.array.index.trait-impl]
The array index expression can be implemented for types other than arrays and slices by implementing the [Index] and [IndexMut] traits.

[`Copy`]: ../special-types-and-traits.md#copy
Expand Down
13 changes: 13 additions & 0 deletions src/expressions/await-expr.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
# Await expressions

r[expr.await]

r[expr.await.syntax]
> **<sup>Syntax</sup>**\
> _AwaitExpression_ :\
> &nbsp;&nbsp; [_Expression_] `.` `await`

r[expr.await.intro]
An `await` expression is a syntactic construct for suspending a computation
provided by an implementation of `std::future::IntoFuture` until the given
future is ready to produce a value.

r[expr.await.construct]
The syntax for an await expression is an expression with a type that implements the [`IntoFuture`] trait, called the *future operand*, then the token `.`, and then the `await` keyword.

r[expr.await.constraints]
Await expressions are legal only within an [async context], like an [`async fn`] or an [`async` block].

r[expr.await.effects]
More specifically, an await expression has the following effect.

1. Create a future by calling [`IntoFuture::into_future`] on the future operand.
Expand All @@ -23,11 +32,15 @@ More specifically, an await expression has the following effect.

## Task context

r[expr.await.task]

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

## Approximate desugaring

r[expr.await.desugar]

Effectively, an await expression is roughly equivalent to the following non-normative desugaring:

<!-- ignore: example expansion -->
Expand Down
Loading
Loading