Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
- [Diagnostics](attributes/diagnostics.md)
- [Code generation](attributes/codegen.md)
- [Limits](attributes/limits.md)
- [Type System](attributes/type_system.md)

- [Statements and expressions](statements-and-expressions.md)
- [Statements](statements.md)
Expand Down
6 changes: 5 additions & 1 deletion src/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ The following is an index of all built-in attributes.
- Features
- `feature` — Used to enable unstable or experimental compiler features. See
[The Unstable Book] for features implemented in `rustc`.
- Type System
- [`non_exhaustive`] — Indicate that a type will have more fields/variants
added in future.

[Doc comments]: comments.md#doc-comments
[ECMA-334]: https://www.ecma-international.org/publications/standards/Ecma-334.htm
Expand Down Expand Up @@ -277,6 +280,7 @@ The following is an index of all built-in attributes.
[`no_main`]: crates-and-source-files.md#the-no_main-attribute
[`no_mangle`]: abi.md#the-no_mangle-attribute
[`no_std`]: crates-and-source-files.md#preludes-and-no_std
[`non_exhaustive`]: attributes/type_system.md#the-non_exhaustive-attribute
[`panic_handler`]: runtime.md#the-panic_handler-attribute
[`path`]: items/modules.md#the-path-attribute
[`proc_macro_attribute`]: procedural-macros.md#attribute-macros
Expand Down Expand Up @@ -309,4 +313,4 @@ The following is an index of all built-in attributes.
[union]: items/unions.md
[closure]: expressions/closure-expr.md
[function pointer]: types/function-pointer.md
[variadic functions]: items/external-blocks.html#variadic-functions
[variadic functions]: items/external-blocks.html#variadic-functions
140 changes: 140 additions & 0 deletions src/attributes/type_system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Type system attributes

The following [attributes] are used for changing how a type can be used.

## The `non_exhaustive` attribute

The *`non_exhaustive` attribute* indicates that a type or variant may have
more fields or variants added in the future. It can be applied to
[`struct`s][struct], [`enum`s][enum], and `enum` variants.

The `non_exhaustive` attribute uses the [_MetaWord_] syntax and thus does not
take any inputs.

Within the defining crate, `non_exhaustive` has no effect.

```rust
#[non_exhaustive]
pub struct Config {
pub window_width: u16,
pub window_height: u16,
}

#[non_exhaustive]
pub enum Error {
Message(String),
Other,
}

pub enum Message {
#[non_exhaustive] Send { from: u32, to: u32, contents: String },
#[non_exhaustive] Reaction(u32),
#[non_exhaustive] Quit,
}

// Non-exhaustive structs can be constructed as normal within the defining crate.
let config = Config { window_width: 640, window_height: 480 };

// Non-exhaustive structs can be matched on exhaustively within the defining crate.
if let Config { window_width, window_height } = config {
// ...
}

let error = Error::Other;
let message = Message::Reaction(3);

// Non-exhaustive enums can be matched on exhaustively within the defining crate.
match error {
Error::Message(ref s) => { },
Error::Other => { },
}

match message {
// Non-exhaustive variants can be matched on exhaustively within the defining crate.
Message::Send { from, to, contents } => { },
Message::Reaction(id) => { },
Message::Quit => { },
}
```

Outside of the defining crate, types annotated with `non_exhaustive` have limitations that
preserve backwards compatibility when new fields or variants are added.

Non-exhaustive types cannot be constructed outside of the defining crate:

- Non-exhaustive variants ([`struct`][struct] or [`enum` variant][enum]) cannot be constructed
with a [_StructExpression_] \(including with [functional update syntax]).
- [`enum`][enum] instances can be constructed in an [_EnumerationVariantExpression_].

```rust,ignore (requires multiple crates)
// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been
// annotated as `#[non_exhaustive]`.
use upstream::{Config, Error, Message};

// Cannot construct an instance of `Config`, if new fields were added in
// a new version of `upstream` then this would fail to compile, so it is
// disallowed.
let config = Config { window_width: 640, window_height: 480 };

// Can construct an instance of `Error`, new variants being introduced would
// not result in this failing to compile.
let error = Error::Message("foo".to_string());

// Cannot construct an instance of `Message::Send` or `Message::Reaction`,
// if new fields were added in a new version of `upstream` then this would
// fail to compile, so it is disallowed.
let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), };
let message = Message::Reaction(0);

// Cannot construct an instance of `Message::Quit`, if this were converted to
// a tuple-variant `upstream` then this would fail to compile.
let message = Message::Quit;
```

There are limitations when matching on non-exhaustive types outside of the defining crate:

- When pattern matching on a non-exhaustive variant ([`struct`][struct] or [`enum` variant][enum]),
a [_StructPattern_] must be used which must include a `..`. Tuple variant constructor visibility
is lowered to `min($vis, pub(crate))`.
- When pattern matching on a non-exhaustive [`enum`][enum], matching on a variant does not
contribute towards the exhaustiveness of the arms.

```rust, ignore (requires multiple crates)
// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been
// annotated as `#[non_exhaustive]`.
use upstream::{Config, Error, Message};

// Cannot match on a non-exhaustive enum without including a wildcard arm.
match error {
Error::Message(ref s) => { },
Error::Other => { },
// would compile with: `_ => {},`
}

// Cannot match on a non-exhaustive struct without a wildcard.
if let Ok(Config { window_width, window_height }) = config {
// would compile with: `..`
}

match message {
// Cannot match on a non-exhaustive struct enum variant without including a wildcard.
Message::Send { from, to, contents } => { },
// Cannot match on a non-exhaustive tuple or unit enum variant.
Message::Reaction(type) => { },
Message::Quit => { },
}
```

Non-exhaustive types are always considered inhabited in downstream crates.

[_EnumerationVariantExpression_]: ../expressions/enum-variant-expr.md
[_MetaWord_]: ../attributes.md#meta-item-attribute-syntax
[_StructExpression_]: ../expressions/struct-expr.md
[_StructPattern_]: ../patterns.md#struct-patterns
[_TupleStructPattern_]: ../patterns.md#tuple-struct-patterns
[`if let`]: ../expressions/if-expr.md#if-let-expressions
[`match`]: ../expressions/match-expr.md
[attributes]: ../attributes.md
[enum]: ../items/enumerations.md
[functional update syntax]: ../expressions/struct-expr.md#functional-update-syntax
[struct]: ../items/structs.md