@@ -10,6 +10,61 @@ r[attributes.type-system.non_exhaustive.intro]
1010The * ` non_exhaustive ` attribute* indicates that a type or variant may have
1111more fields or variants added in the future.
1212
13+ > [ !EXAMPLE]
14+ > The following non-exhaustive definitions will be used in the examples that follow.
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 struct Token ;
25+ >
26+ > #[non_exhaustive]
27+ > pub struct Id (pub u64 );
28+ >
29+ > #[non_exhaustive]
30+ > pub enum Error {
31+ > Message (String ),
32+ > Other ,
33+ > }
34+ >
35+ > pub enum Message {
36+ > #[non_exhaustive] Send { from : u32 , to : u32 , contents : String },
37+ > #[non_exhaustive] Reaction (u32 ),
38+ > #[non_exhaustive] Quit ,
39+ > }
40+ >
41+ > // Non-exhaustive structs can be constructed as normal within the defining crate.
42+ > let config = Config { window_width : 640 , window_height : 480 };
43+ > let token = Token ;
44+ > let id = Id (4 );
45+ >
46+ > // Non-exhaustive structs can be matched on exhaustively within the defining crate.
47+ > let Config { window_width , window_height } = config ;
48+ > let Token = token ;
49+ > let Id (id_number ) = id ;
50+ >
51+ > let error = Error :: Other ;
52+ > let message = Message :: Reaction (3 );
53+ >
54+ > // Non-exhaustive enums can be matched on exhaustively within the defining crate.
55+ > match error {
56+ > Error :: Message (ref s ) => { },
57+ > Error :: Other => { },
58+ > }
59+ >
60+ > match message {
61+ > // Non-exhaustive variants can be matched on exhaustively within the defining crate.
62+ > Message :: Send { from , to , contents } => { },
63+ > Message :: Reaction (id ) => { },
64+ > Message :: Quit => { },
65+ > }
66+ > ```
67+
1368r [attributes . type - system . non_exhaustive. allowed- positions ]
1469It can be applied to [`struct `s ][struct ], [`enum `s ][enum ], and `enum ` variants .
1570
@@ -20,58 +75,6 @@ take any inputs.
2075r [attributes . type - system . non_exhaustive. same- crate ]
2176Within the defining crate , `non_exhaustive ` has no effect .
2277
23- ``` rust
24- #[non_exhaustive]
25- pub struct Config {
26- pub window_width : u16 ,
27- pub window_height : u16 ,
28- }
29-
30- #[non_exhaustive]
31- pub struct Token ;
32-
33- #[non_exhaustive]
34- pub struct Id (pub u64 );
35-
36- #[non_exhaustive]
37- pub enum Error {
38- Message (String ),
39- Other ,
40- }
41-
42- pub enum Message {
43- #[non_exhaustive] Send { from : u32 , to : u32 , contents : String },
44- #[non_exhaustive] Reaction (u32 ),
45- #[non_exhaustive] Quit ,
46- }
47-
48- // Non-exhaustive structs can be constructed as normal within the defining crate.
49- let config = Config { window_width : 640 , window_height : 480 };
50- let token = Token ;
51- let id = Id (4 );
52-
53- // Non-exhaustive structs can be matched on exhaustively within the defining crate.
54- let Config { window_width , window_height } = config ;
55- let Token = token ;
56- let Id (id_number ) = id ;
57-
58- let error = Error :: Other ;
59- let message = Message :: Reaction (3 );
60-
61- // Non-exhaustive enums can be matched on exhaustively within the defining crate.
62- match error {
63- Error :: Message (ref s ) => { },
64- Error :: Other => { },
65- }
66-
67- match message {
68- // Non-exhaustive variants can be matched on exhaustively within the defining crate.
69- Message :: Send { from , to , contents } => { },
70- Message :: Reaction (id ) => { },
71- Message :: Quit => { },
72- }
73- ```
74-
7578r [attributes . type - system . non_exhaustive. external- crate ]
7679Outside of the defining crate , types annotated with `non_exhaustive ` have limitations that
7780preserve backwards compatibility when new fields or variants are added .
@@ -89,115 +92,123 @@ Non-exhaustive types cannot be constructed outside of the defining crate:
8992 (as is the case without `#[non_exhaustive]`).
9093- [`enum `][enum ] instances can be constructed .
9194
92- The following examples of construction do not compile when outside the defining crate:
93-
94- <!-- ignore: requires external crates -->
95- ``` rust,ignore
96- // These are types defined in an upstream crate that have been annotated as
97- // `#[non_exhaustive]`.
98- use upstream::{Config, Token, Id, Error, Message};
99-
100- // Cannot construct an instance of `Config`; if new fields were added in
101- // a new version of `upstream` then this would fail to compile, so it is
102- // disallowed.
103- let config = Config { window_width: 640, window_height: 480 };
104-
105- // Cannot construct an instance of `Token`; if new fields were added, then
106- // it would not be a unit-like struct any more, so the same-named constant
107- // created by it being a unit-like struct is not public outside the crate;
108- // this code fails to compile.
109- let token = Token;
110-
111- // Cannot construct an instance of `Id`; if new fields were added, then
112- // its constructor function signature would change, so its constructor
113- // function is not public outside the crate; this code fails to compile.
114- let id = Id(5);
115-
116- // Can construct an instance of `Error`; new variants being introduced would
117- // not result in this failing to compile.
118- let error = Error::Message("foo".to_string());
119-
120- // Cannot construct an instance of `Message::Send` or `Message::Reaction`;
121- // if new fields were added in a new version of `upstream` then this would
122- // fail to compile, so it is disallowed.
123- let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), };
124- let message = Message::Reaction(0);
125-
126- // Cannot construct an instance of `Message::Quit`; if this were converted to
127- // a tuple enum variant `upstream`, this would fail to compile.
128- let message = Message::Quit;
129- ```
95+ > [! EXAMPLE ]
96+ > Using the definitions from [above ][attributes . type - system . non_exhaustive. intro], the following examples of construction do not compile when outside the defining crate :
97+ >
98+ > <! -- ignore : requires external crates - ->
99+ > ```rust ,ignore
100+ > // These are types defined in an upstream crate that have been annotated as
101+ > // `#[non_exhaustive]`.
102+ > use upstream :: {Config , Token , Id , Error , Message };
103+ >
104+ > // Cannot construct an instance of `Config`; if new fields were added in
105+ > // a new version of `upstream` then this would fail to compile, so it is
106+ > // disallowed.
107+ > let config = Config { window_width : 640 , window_height : 480 };
108+ >
109+ > // Cannot construct an instance of `Token`; if new fields were added, then
110+ > // it would not be a unit-like struct any more, so the same-named constant
111+ > // created by it being a unit-like struct is not public outside the crate;
112+ > // this code fails to compile.
113+ > let token = Token ;
114+ >
115+ > // Cannot construct an instance of `Id`; if new fields were added, then
116+ > // its constructor function signature would change, so its constructor
117+ > // function is not public outside the crate; this code fails to compile.
118+ > let id = Id (5 );
119+ >
120+ > // Can construct an instance of `Error`; new variants being introduced would
121+ > // not result in this failing to compile.
122+ > let error = Error :: Message (" foo" . to_string ());
123+ >
124+ > // Cannot construct an instance of `Message::Send` or `Message::Reaction`;
125+ > // if new fields were added in a new version of `upstream` then this would
126+ > // fail to compile, so it is disallowed.
127+ > let message = Message :: Send { from : 0 , to : 1 , contents : " foo" . to_string (), };
128+ > let message = Message :: Reaction (0 );
129+ >
130+ > // Cannot construct an instance of `Message::Quit`; if this were converted to
131+ > // a tuple enum variant `upstream`, this would fail to compile.
132+ > let message = Message :: Quit ;
133+ > ```
130134
131135r [attributes . type - system . non_exhaustive. match ]
132136There are limitations when matching on non - exhaustive types outside of the defining crate :
133137
134- - When pattern matching on a non-exhaustive variant ([ ` struct ` ] [ struct ] or [ ` enum ` variant] [ enum ] ), a [ StructPattern] must be used which must include a ` .. ` . A tuple enum variant's constructor's [ visibility] is reduced to be no greater than ` pub(crate) ` .
135- - When pattern matching on a non-exhaustive [ ` enum ` ] [ enum ] , matching on a variant does not contribute towards the exhaustiveness of the arms. The following examples of matching do not compile when outside the defining crate:
136-
137- <!-- ignore: requires external crates -->
138- ``` rust, ignore
139- // These are types defined in an upstream crate that have been annotated as
140- // `#[non_exhaustive]`.
141- use upstream::{Config, Token, Id, Error, Message};
142-
143- // Cannot match on a non-exhaustive enum without including a wildcard arm.
144- match error {
145- Error::Message(ref s) => { },
146- Error::Other => { },
147- // would compile with: `_ => {},`
148- }
149-
150- // Cannot match on a non-exhaustive struct without a wildcard.
151- if let Ok(Config { window_width, window_height }) = config {
152- // would compile with: `..`
153- }
154-
155- // Cannot match a non-exhaustive unit-like or tuple struct except by using
156- // braced struct syntax with a wildcard.
157- // This would compile as `let Token { .. } = token;`
158- let Token = token;
159- // This would compile as `let Id { 0: id_number, .. } = id;`
160- let Id(id_number) = id;
161-
162- match message {
163- // Cannot match on a non-exhaustive struct enum variant without including a wildcard.
164- Message::Send { from, to, contents } => { },
165- // Cannot match on a non-exhaustive tuple or unit enum variant.
166- Message::Reaction(type) => { },
167- Message::Quit => { },
168- }
169- ```
138+ - When pattern matching on a non - exhaustive variant ([`struct `][struct ] or [`enum ` variant ][enum ]),
139+ a [StructPattern ] must be used which must include a `.. `. A tuple enum variant 's constructor 's
140+ [visibility ] is reduced to be no greater than `pub (crate )`.
141+ - When pattern matching on a non - exhaustive [`enum `][enum ], matching on a variant does not
142+ contribute towards the exhaustiveness of the arms .
143+
144+ > [! EXAMPLE ]
145+ > Using the definitions from [above ][attributes . type - system . non_exhaustive. intro], the following examples of matching do not compile when outside the defining crate :
146+ >
147+ > <! -- ignore : requires external crates - ->
148+ > ```rust , ignore
149+ > // These are types defined in an upstream crate that have been annotated as
150+ > // `#[non_exhaustive]`.
151+ > use upstream :: {Config , Token , Id , Error , Message };
152+ >
153+ > // Cannot match on a non-exhaustive enum without including a wildcard arm.
154+ > match error {
155+ > Error :: Message (ref s ) => { },
156+ > Error :: Other => { },
157+ > // would compile with: `_ => {},`
158+ > }
159+ >
160+ > // Cannot match on a non-exhaustive struct without a wildcard.
161+ > if let Ok (Config { window_width , window_height }) = config {
162+ > // would compile with: `..`
163+ > }
164+ >
165+ > // Cannot match a non-exhaustive unit-like or tuple struct except by using
166+ > // braced struct syntax with a wildcard.
167+ > // This would compile as `let Token { .. } = token;`
168+ > let Token = token ;
169+ > // This would compile as `let Id { 0: id_number, .. } = id;`
170+ > let Id (id_number ) = id ;
171+ >
172+ > match message {
173+ > // Cannot match on a non-exhaustive struct enum variant without including a wildcard.
174+ > Message :: Send { from , to , contents } => { },
175+ > // Cannot match on a non-exhaustive tuple or unit enum variant.
176+ > Message :: Reaction (type ) => { },
177+ > Message :: Quit => { },
178+ > }
179+ > ```
170180
171181It 's also not allowed to use numeric casts (`as `) on enums that contain any non- exhaustive variants.
172182
173- For example, the following enum can be cast because it doesn't contain any non-exhaustive variants:
174-
175- ``` rust
176- #[non_exhaustive]
177- pub enum Example {
178- First ,
179- Second
180- }
181- ```
182-
183- However, if the enum contains even a single non-exhaustive variant, casting will result in an error. Consider this modified version of the same enum:
184-
185- ``` rust
186- #[non_exhaustive]
187- pub enum EnumWithNonExhaustiveVariants {
188- First ,
189- #[non_exhaustive]
190- Second
191- }
192- ```
193-
194- <!-- ignore: needs multiple crates -->
195- ``` rust,ignore
196- use othercrate::EnumWithNonExhaustiveVariants;
197-
198- // Error: cannot cast an enum with a non-exhaustive variant when it's defined in another crate
199- let _ = EnumWithNonExhaustiveVariants::First as u8;
200- ```
183+ > [! EXAMPLE ]
184+ > The following enum can be cast because it doesn't contain any non- exhaustive variants:
185+ >
186+ > ```rust
187+ > #[non_exhaustive]
188+ > pub enum Example {
189+ > First ,
190+ > Second
191+ > }
192+ > ```
193+ >
194+ > However , if the enum contains even a single non- exhaustive variant, casting will result in an error. Consider this modified version of the same enum :
195+ >
196+ > ```rust
197+ > #[non_exhaustive]
198+ > pub enum EnumWithNonExhaustiveVariants {
199+ > First ,
200+ > #[non_exhaustive]
201+ > Second
202+ > }
203+ > ```
204+ >
205+ > <! -- ignore: needs multiple crates - ->
206+ > ```rust,ignore
207+ > use othercrate :: EnumWithNonExhaustiveVariants ;
208+ >
209+ > // Error: cannot cast an enum with a non-exhaustive variant when it's defined in another crate
210+ > let _ = EnumWithNonExhaustiveVariants :: First as u8 ;
211+ > ```
201212
202213Non - exhaustive types are always considered inhabited in downstream crates .
203214
0 commit comments