Skip to content

Commit

Permalink
Merge pull request #1618 from chorman0773/spec-add-identifiers-types
Browse files Browse the repository at this point in the history
Add identifier syntax to types and subchapters.
  • Loading branch information
traviscross authored Oct 17, 2024
2 parents fb5c26a + e5028f7 commit 0a0c9e7
Show file tree
Hide file tree
Showing 19 changed files with 311 additions and 21 deletions.
42 changes: 39 additions & 3 deletions src/types.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
{{#include types-redirect.html}}
# Types

r[type]

r[type.intro]
Every variable, item, and value in a Rust program has a type. The _type_ of a
*value* defines the interpretation of the memory holding it and the operations
that may be performed on the value.

r[type.builtin]
Built-in types are tightly integrated into the language, in nontrivial ways
that are not possible to emulate in user-defined types. User-defined types have
limited capabilities.
that are not possible to emulate in user-defined types.

r[type.user-defined]
User-defined types have limited capabilities.

r[type.kinds]
The list of types is:

* Primitive types:
Expand Down Expand Up @@ -37,6 +44,9 @@ The list of types is:

## Type expressions

r[type.name]

r[type.name.syntax]
> **<sup>Syntax</sup>**\
> _Type_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; _TypeNoBounds_\
Expand All @@ -59,27 +69,47 @@ The list of types is:
> &nbsp;&nbsp; | [_BareFunctionType_]\
> &nbsp;&nbsp; | [_MacroInvocation_]
r[type.name.intro]
A _type expression_ as defined in the _Type_ grammar rule above is the syntax
for referring to a type. It may refer to:

r[type.name.sequence]
* Sequence types ([tuple], [array], [slice]).

r[type.name.path]
* [Type paths] which can reference:
* Primitive types ([boolean], [numeric], [textual]).
* Paths to an [item] ([struct], [enum], [union], [type alias], [trait]).
* [`Self` path] where `Self` is the implementing type.
* Generic [type parameters].

r[type.name.pointer]
* Pointer types ([reference], [raw pointer], [function pointer]).

r[type.name.inference]
* The [inferred type] which asks the compiler to determine the type.

r[type.name.grouped]
* [Parentheses] which are used for disambiguation.

r[type.name.trait]
* Trait types: [Trait objects] and [impl trait].

r[type.name.never]
* The [never] type.

r[type.name.macro-expansion]
* [Macros] which expand to a type expression.

### Parenthesized types

r[type.name.parenthesized]

r[type.name.parenthesized.syntax]
> _ParenthesizedType_ :\
> &nbsp;&nbsp; `(` [_Type_] `)`
r[type.name.parenthesized.intro]
In some situations the combination of types may be ambiguous. Use parentheses
around a type to avoid ambiguity. For example, the `+` operator for [type
boundaries] within a [reference type] is unclear where the
Expand All @@ -94,10 +124,16 @@ type T<'a> = &'a (dyn Any + Send);

## Recursive types

r[type.recursive]

r[type.recursive.intro]
Nominal types &mdash; [structs], [enumerations], and [unions] &mdash; may be
recursive. That is, each `enum` variant or `struct` or `union` field may
refer, directly or indirectly, to the enclosing `enum` or `struct` type
itself. Such recursion has restrictions:
itself.

r[type.recursive.constraint]
Such recursion has restrictions:

* Recursive types must include a nominal type in the recursion (not mere [type
aliases], or other structural types such as [arrays] or [tuples]). So `type
Expand Down
11 changes: 9 additions & 2 deletions src/types/array.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
# Array types

r[type.array]

r[type.array.syntax]
> **<sup>Syntax</sup>**\
> _ArrayType_ :\
> &nbsp;&nbsp; `[` [_Type_] `;` [_Expression_] `]`
r[type.array.intro]
An array is a fixed-size sequence of `N` elements of type `T`. The array type
is written as `[T; N]`. The size is a [constant expression] that evaluates to a
[`usize`].
is written as `[T; N]`.

r[type.array.constraint]
The size is a [constant expression] that evaluates to a [`usize`].

Examples:

Expand All @@ -18,6 +24,7 @@ let array: [i32; 3] = [1, 2, 3];
let boxed_array: Box<[i32]> = Box::new([1, 2, 3]);
```

r[type.array.index]
All elements of arrays are always initialized, and access to an array is
always bounds-checked in safe methods and operators.

Expand Down
40 changes: 38 additions & 2 deletions src/types/boolean.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,44 @@
# Boolean type

r[type.bool]

```rust
let b: bool = true;
```

r[type.bool.intro]
The *boolean type* or *bool* is a primitive data type that can take on one of
two values, called *true* and *false*.

r[type.bool.literal]
Values of this type may be created using a [literal expression] using the
keywords `true` and `false` corresponding to the value of the same name.

r[type.bool.namespace]
This type is a part of the [language prelude] with the [name] `bool`.

An object with the boolean type has a [size and alignment] of 1 each. The
value false has the bit pattern `0x00` and the value true has the bit pattern
r[type.bool.layout]
An object with the boolean type has a [size and alignment] of 1 each.

r[type.bool.repr]
The value false has the bit pattern `0x00` and the value true has the bit pattern
`0x01`. It is [undefined behavior] for an object with the boolean type to have
any other bit pattern.

r[type.bool.usage]
The boolean type is the type of many operands in various [expressions]:

r[type.bool.usage-condition]
* The condition operand in [if expressions] and [while expressions]

r[type.bool.usage-lazy-operator]
* The operands in [lazy boolean operator expressions][lazy]

> **Note**: The boolean type acts similarly to but is not an [enumerated type].
In practice, this mostly means that constructors are not associated to the type
(e.g. `bool::true`).

r[type.bool.traits]
Like all primitives, the boolean type [implements][p-impl] the
[traits][p-traits] [`Clone`][p-clone], [`Copy`][p-copy], [`Sized`][p-sized],
[`Send`][p-send], and [`Sync`][p-sync].
Expand All @@ -34,18 +47,24 @@ Like all primitives, the boolean type [implements][p-impl] the
## Operations on boolean values

r[type.bool.expr]

<!-- This is washy wording --> When using certain operator expressions with a
boolean type for its operands, they evaluate using the rules of [boolean logic].

### Logical not

r[type.bool.expr.not]

| `b` | [`!b`][op-not] |
|- | - |
| `true` | `false` |
| `false` | `true` |

### Logical or

r[type.bool.expr.or]

| `a` | `b` | [<code>a &#124; b</code>][op-or] |
|- | - | - |
| `true` | `true` | `true` |
Expand All @@ -55,6 +74,8 @@ boolean type for its operands, they evaluate using the rules of [boolean logic].

### Logical and

r[type.bool.expr.and]

| `a` | `b` | [`a & b`][op-and] |
|- | - | - |
| `true` | `true` | `true` |
Expand All @@ -64,6 +85,8 @@ boolean type for its operands, they evaluate using the rules of [boolean logic].

### Logical xor

r[type.bool.expr.xor]

| `a` | `b` | [`a ^ b`][op-xor] |
|- | - | - |
| `true` | `true` | `false` |
Expand All @@ -73,27 +96,40 @@ boolean type for its operands, they evaluate using the rules of [boolean logic].

### Comparisons

r[type.bool.expr.cmp]

r[type.bool.expr.cmp.eq]
| `a` | `b` | [`a == b`][op-compare] |
|- | - | - |
| `true` | `true` | `true` |
| `true` | `false` | `false` |
| `false` | `true` | `false` |
| `false` | `false` | `true` |

r[type.bool.expr.cmp.greater]
| `a` | `b` | [`a > b`][op-compare] |
|- | - | - |
| `true` | `true` | `false` |
| `true` | `false` | `true` |
| `false` | `true` | `false` |
| `false` | `false` | `false` |

r[type.bool.expr.cmp.not-eq]
* `a != b` is the same as `!(a == b)`

r[type.bool.expr.cmp.greater-eq]
* `a >= b` is the same as `a == b | a > b`

r[type.bool.expr.cmp.less]
* `a < b` is the same as `!(a >= b)`

r[type.bool.expr.cmp.less-eq]
* `a <= b` is the same as `a == b | a < b`

## Bit validity

r[type.bool.validity]

The single byte of a `bool` is guaranteed to be initialized (in other words,
`transmute::<bool, u8>(...)` is always sound -- but since some bit patterns
are invalid `bool`s, the inverse is not always sound).
Expand Down
20 changes: 20 additions & 0 deletions src/types/closure.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Closure types

r[type.closure]

A [closure expression] produces a closure value with a unique, anonymous type
that cannot be written out. A closure type is approximately equivalent to a
struct which contains the captured variables. For instance, the following
Expand Down Expand Up @@ -47,21 +49,27 @@ f(Closure{s: s, t: &t});

## Capture modes

r[type.closure.capture]

r[type.closure.capture.order]
The compiler prefers to capture a closed-over variable by immutable borrow,
followed by unique immutable borrow (see below), by mutable borrow, and finally
by move. It will pick the first choice of these that is compatible with how the
captured variable is used inside the closure body. The compiler does not take
surrounding code into account, such as the lifetimes of involved variables, or
of the closure itself.

r[type.closure.capture.move]
If the `move` keyword is used, then all captures are by move or, for `Copy`
types, by copy, regardless of whether a borrow would work. The `move` keyword is
usually used to allow the closure to outlive the captured values, such as if the
closure is being returned or used to spawn a new thread.

r[type.closure.capture.composite]
Composite types such as structs, tuples, and enums are always captured entirely,
not by individual fields. It may be necessary to borrow into a local variable in
order to capture a single field:
<!-- editor note, not true in Edition 2021 -->

```rust
# use std::collections::HashSet;
Expand All @@ -87,6 +95,8 @@ borrowed to iterate over, the code would not compile.

## Unique immutable borrows in captures

r[type.closure.unique-immutable]

Captures can occur by a special kind of borrow called a _unique immutable
borrow_, which cannot be used anywhere else in the language and cannot be
written out explicitly. It occurs when modifying the referent of a mutable
Expand Down Expand Up @@ -115,13 +125,18 @@ the closure's lifetime has expired at the end of the block, releasing the borrow

## Call traits and coercions

r[type.closure.call]

r[type.closure.call.intro]
Closure types all implement [`FnOnce`], indicating that they can be called once
by consuming ownership of the closure. Additionally, some closures implement
more specific call traits:

r[type.closure.call.fn-mut]
* A closure which does not move out of any captured variables implements
[`FnMut`], indicating that it can be called by mutable reference.

r[type.closure.call.fn]
* A closure which does not mutate or move out of any captured variables
implements [`Fn`], indicating that it can be called by shared reference.

Expand All @@ -130,6 +145,7 @@ more specific call traits:
> closure type are determined by what the closure does with captured values,
> not how it captures them.
r[type.closure.non-capturing]
*Non-capturing closures* are closures that don't capture anything from their
environment. They can be coerced to function pointers (e.g., `fn()`)
with the matching signature.
Expand All @@ -146,6 +162,9 @@ x = bo(5,7);

## Other traits

r[type.closure.traits]

r[type.closure.traits.intro]
All closure types implement [`Sized`]. Additionally, closure types implement the
following traits if allowed to do so by the types of the captures it stores:

Expand All @@ -154,6 +173,7 @@ following traits if allowed to do so by the types of the captures it stores:
* [`Sync`]
* [`Send`]

r[type.closure.traits.behavior]
The rules for [`Send`] and [`Sync`] match those for normal struct types, while
[`Clone`] and [`Copy`] behave as if [derived]. For [`Clone`], the order of
cloning of the captured variables is left unspecified.
Expand Down
7 changes: 7 additions & 0 deletions src/types/enum.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
# Enumerated types

r[type.enum]

r[type.enum.intro]
An *enumerated type* is a nominal, heterogeneous disjoint union type, denoted
by the name of an [`enum` item]. [^enumtype]

r[type.enum.declaration]
An [`enum` item] declares both the type and a number of *variants*, each of
which is independently named and has the syntax of a struct, tuple struct or
unit-like struct.

r[type.enum.constructor]
New instances of an `enum` can be constructed with a [struct expression].

r[type.enum.value]
Any `enum` value consumes as much memory as the largest variant for its
corresponding `enum` type, as well as the size needed to store a discriminant.

r[type.enum.name]
Enum types cannot be denoted *structurally* as types, but must be denoted by
named reference to an [`enum` item].

Expand Down
Loading

0 comments on commit 0a0c9e7

Please sign in to comment.