Skip to content

Commit 363a64a

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

File tree

3 files changed

+146
-1
lines changed

3 files changed

+146
-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

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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+
- Non-exhaustive variants ([`struct`][struct] or [`enum` variant][enum]) cannot be constructed
66+
with a [_StructExpression_] \(including with [functional update syntax]).
67+
- [`enum`][enum] instances can be constructed in an [_EnumerationVariantExpression_].
68+
69+
```rust,ignore (requires multiple crates)
70+
// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been
71+
// annotated as `#[non_exhaustive]`.
72+
use upstream::{Config, Error, Message};
73+
74+
// Cannot construct an instance of `Config`, if new fields were added in
75+
// a new version of `upstream` then this would fail to compile, so it is
76+
// disallowed.
77+
let config = Config { window_width: 640, window_height: 480 };
78+
79+
// Can construct an instance of `Error`, new variants being introduced would
80+
// not result in this failing to compile.
81+
let error = Error::Message("foo".to_string());
82+
83+
// Cannot construct an instance of `Message::Send` or `Message::Reaction`,
84+
// if new fields were added in a new version of `upstream` then this would
85+
// fail to compile, so it is disallowed.
86+
let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), };
87+
let message = Message::Reaction(0);
88+
89+
// Cannot construct an instance of `Message::Quit`, if this were converted to
90+
// a tuple-variant `upstream` then this would fail to compile.
91+
let message = Message::Quit;
92+
```
93+
94+
There are limitations when matching on non-exhaustive types outside of the defining crate:
95+
96+
- When pattern matching on a non-exhaustive variant ([`struct`][struct] or [`enum` variant][enum]),
97+
a [_StructPattern_] must be used which must include a `..`. Tuple variant constructor visibility
98+
is lowered to `min($vis, pub(crate))`.
99+
- When pattern matching on a non-exhaustive [`enum`][enum], matching on a variant does not
100+
contribute towards the exhaustiveness of the arms.
101+
102+
```rust, ignore (requires multiple crates)
103+
// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been
104+
// annotated as `#[non_exhaustive]`.
105+
use upstream::{Config, Error, Message};
106+
107+
// Cannot match on a non-exhaustive enum without including a wildcard arm.
108+
match error {
109+
Error::Message(ref s) => { },
110+
Error::Other => { },
111+
// would compile with: `_ => {},`
112+
}
113+
114+
// Cannot match on a non-exhaustive struct without a wildcard.
115+
if let Ok(Config { window_width, window_height }) = config {
116+
// would compile with: `..`
117+
}
118+
119+
match message {
120+
// Cannot match on a non-exhaustive struct enum variant without including a wildcard.
121+
Message::Send { from, to, contents } => { },
122+
// Cannot match on a non-exhaustive tuple or unit enum variant.
123+
Message::Reaction(type) => { },
124+
Message::Quit => { },
125+
}
126+
```
127+
128+
Non-exhaustive types are always considered inhabited in downstream crates.
129+
130+
[_EnumerationVariantExpression_]: ../expressions/enum-variant-expr.md
131+
[_MetaWord_]: ../attributes.md#meta-item-attribute-syntax
132+
[_StructExpression_]: ../expressions/struct-expr.md
133+
[_StructPattern_]: ../patterns.md#struct-patterns
134+
[_TupleStructPattern_]: ../patterns.md#tuple-struct-patterns
135+
[`if let`]: ../expressions/if-expr.md#if-let-expressions
136+
[`match`]: ../expressions/match-expr.md
137+
[attributes]: ../attributes.md
138+
[enum]: ../items/enumerations.md
139+
[functional update syntax]: ../expressions/struct-expr.md#functional-update-syntax
140+
[struct]: ../items/structs.md

0 commit comments

Comments
 (0)