Skip to content

Commit c01aff7

Browse files
committed
Add non_exhaustive to reference.
1 parent a763694 commit c01aff7

File tree

3 files changed

+143
-1
lines changed

3 files changed

+143
-1
lines changed

src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
- [Diagnostics](attributes/diagnostics.md)
4646
- [Code generation](attributes/codegen.md)
4747
- [Limits](attributes/limits.md)
48+
- [Type System](attributes/type_system.md)
4849

4950
- [Statements and expressions](statements-and-expressions.md)
5051
- [Statements](statements.md)

src/attributes.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ The following is an index of all built-in attributes.
238238
- Features
239239
- `feature` — Used to enable unstable or experimental compiler features. See
240240
[The Unstable Book] for features implemented in `rustc`.
241+
- Type System
242+
- [`non_exhaustive`] — Indicate that a type will have more fields/variants
243+
added in future.
241244

242245
[Doc comments]: comments.md#doc-comments
243246
[ECMA-334]: https://www.ecma-international.org/publications/standards/Ecma-334.htm
@@ -277,6 +280,7 @@ The following is an index of all built-in attributes.
277280
[`no_main`]: crates-and-source-files.md#the-no_main-attribute
278281
[`no_mangle`]: abi.md#the-no_mangle-attribute
279282
[`no_std`]: crates-and-source-files.md#preludes-and-no_std
283+
[`non_exhaustive`]: attributes/type_system.md#the-non_exhaustive-attribute
280284
[`panic_handler`]: runtime.md#the-panic_handler-attribute
281285
[`path`]: items/modules.md#the-path-attribute
282286
[`proc_macro_attribute`]: procedural-macros.md#attribute-macros
@@ -309,4 +313,4 @@ The following is an index of all built-in attributes.
309313
[union]: items/unions.md
310314
[closure]: expressions/closure-expr.md
311315
[function pointer]: types/function-pointer.md
312-
[variadic functions]: items/external-blocks.html#variadic-functions
316+
[variadic functions]: items/external-blocks.html#variadic-functions

src/attributes/type_system.md

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Type system attributes
2+
3+
The following [attributes] are used for changing how a type can be used.
4+
5+
## The `non_exhaustive` attribute
6+
7+
The *`non_exhaustive` attribute* indicates that a type or variant may have
8+
more fields or variants added in the future. It can be applied to
9+
[`struct`s][struct], [`enum`s][enum] and, `enum` variants.
10+
11+
The `non_exhaustive` attribute uses the [_MetaWord_] syntax and thus does not
12+
take any inputs.
13+
14+
Within the defining crate, `non_exhaustive` has no effect.
15+
16+
```rust
17+
#[non_exhaustive]
18+
pub struct Config {
19+
pub window_width: u16,
20+
pub window_height: u16,
21+
}
22+
23+
#[non_exhaustive]
24+
pub enum Error {
25+
Message(String),
26+
Other,
27+
}
28+
29+
pub enum Message {
30+
#[non_exhaustive] Send { from: u32, to: u32, contents: String },
31+
#[non_exhaustive] Reaction(u32),
32+
#[non_exhaustive] Quit,
33+
}
34+
35+
// Non-exhaustive structs can be constructed as normal within the defining crate.
36+
let config = Config { window_width: 640, window_height: 480 };
37+
38+
// Non-exhaustive structs can be matched on exhaustively within the defining crate.
39+
if let Config { window_width, window_height } = config {
40+
// ...
41+
}
42+
43+
let error = Error::Other;
44+
let message = Message::Reaction(3);
45+
46+
// Non-exhaustive enums can be matched on exhaustively within the defining crate.
47+
match error {
48+
Error::Message(ref s) => { },
49+
Error::Other => { },
50+
}
51+
52+
match message {
53+
// Non-exhaustive variants can be matched on exhaustively within the defining crate.
54+
Message::Send { from, to, contents } => { },
55+
Message::Reaction(id) => { },
56+
Message::Quit => { },
57+
}
58+
```
59+
60+
Outside of the defining crate, types annotated with `non_exhaustive` have limitations that
61+
preserve backwards compatibility when new fields or variants are added.
62+
63+
Non-exhaustive types cannot be constructed outside of the defining crate:
64+
65+
- [`struct`s][struct] cannot be constructed with a [struct expression].
66+
- [`enum`][enum] instances can be constructed in an [enumeration variant expression].
67+
68+
```rust,ignore (requires multiple crates)
69+
// `Config`, `Error` and `Message` are types defined in an upstream crate that have been
70+
// annotated as `#[non_exhaustive]`.
71+
use upstream::{Config, Error, Message};
72+
73+
// Cannot construct an instance of `Config`, if new fields were added in
74+
// a new version of `upstream` then this would fail to compile, so it is
75+
// disallowed.
76+
let config = Config { window_width: 640, window_height: 480 };
77+
78+
// Can construct an instance of `Error`, new variants being introduced would
79+
// not result in this failing to compile.
80+
let error = Error::Message("foo".to_string());
81+
82+
// Cannot construct an instance of `Message::Send` or `Message::Reaction`,
83+
// if new fields were added in a new version of `upstream` then this would
84+
// fail to compile, so it is disallowed.
85+
let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), };
86+
let message = Message::Reaction(0);
87+
88+
// Cannot construct an instance of `Message::Quit`, if this were converted to
89+
// a tuple-variant `upstream` then this would fail to compile.
90+
let message = Message::Quit;
91+
```
92+
93+
There are limitations when matching on non-exhaustive types outside of the defining crate:
94+
95+
- When pattern matching on a non-exhaustive variant ([`struct`][struct] or [`enum` variant][enum]),
96+
a [_StructPattern_] or [_TupleStructPattern_] must be used which must include a `..`.
97+
- When pattern matching on a non-exhaustive [`enum`][enum], matching on a variant does not
98+
contribute towards the exhaustiveness of the arms.
99+
100+
```rust, ignore (requires multiple crates)
101+
// `Config`, `Error` and `Message` are types defined in an upstream crate that have been
102+
// annotated as `#[non_exhaustive]`.
103+
use upstream::{Config, Error, Message};
104+
105+
// Cannot match on a non-exhaustive enum without including a wildcard arm.
106+
match error {
107+
Error::Message(ref s) => { },
108+
Error::Other => { },
109+
// would compile with: `_ => {},`
110+
}
111+
112+
// Cannot match on a non-exhaustive struct without a wildcard.
113+
if let Ok(Config { window_width, window_height }) = config {
114+
// would compile with: `..`
115+
}
116+
117+
match message {
118+
// Cannot match on a non-exhaustive struct enum variant without including a wildcard.
119+
Message::Send { from, to, contents } => { },
120+
// Cannot match on a non-exhaustive tuple or unit enum variant.
121+
Message::Reaction(type) => { },
122+
Message::Quit => { },
123+
}
124+
```
125+
126+
Non-exhaustive types are always considered inhabited in downstream crates.
127+
128+
[attributes]: ../attributes.md
129+
[_MetaWord_]: ../attributes.md#meta-item-attribute-syntax
130+
[enum]: ../items/enumerations.md
131+
[`if let`]: ../expressions/if-expr.md#if-let-expressions
132+
[`match`]: ../expressions/match-expr.md
133+
[struct]: ../items/structs.md
134+
[struct expression]: ../expressions/struct-expr.md
135+
[enumeration variant expression]: ../expressions/enum-variant-expr.md
136+
[_StructPattern_]: ../patterns.md#struct-patterns
137+
[_TupleStructPattern_]: ../patterns.md#tuple-struct-patterns

0 commit comments

Comments
 (0)