diff --git a/src/SUMMARY.md b/src/SUMMARY.md index b1ba24137..fb0e6574d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -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) diff --git a/src/attributes.md b/src/attributes.md index 9899e8a07..dfffe5ca0 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -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 @@ -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 @@ -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 \ No newline at end of file +[variadic functions]: items/external-blocks.html#variadic-functions diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md new file mode 100644 index 000000000..52bbb68f1 --- /dev/null +++ b/src/attributes/type_system.md @@ -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 diff --git a/src/glossary.md b/src/glossary.md index 6dc22b860..36c0c9314 100644 --- a/src/glossary.md +++ b/src/glossary.md @@ -65,6 +65,12 @@ For example, `2 + (3 * 4)` is an expression that returns the value 14. An [item] that is not a member of an [implementation], such as a *free function* or a *free const*. Contrast to an [associated item]. +### Inhabited + +A type is inhabited if it has constructors and therefore can be instantiated. An inhabited type is +not "empty" in the sense that there can be values of the type. Opposite of +[Uninhabited](#uninhabited). + ### Inherent implementation An [implementation] that applies to a nominal type, not to a trait-type pair. @@ -159,6 +165,13 @@ but is not limited to: process termination or corruption; improper, incorrect, or unintended computation; or platform-specific results. [More][undefined-behavior]. +### Uninhabited + +A type is uninhabited if it has no constructors and therefore can never be instantiated. An +uninhabited type is "empty" in the sense that there are no values of the type. The canonical +example of an uninhabited type is the [never type] `!`, or an enum with no variants +`enum Never { }`. Opposite of [Inhabited](#inhabited). + [alignment]: type-layout.md#size-and-alignment [associated item]: #associated-item [enums]: items/enumerations.md @@ -168,6 +181,7 @@ or unintended computation; or platform-specific results. [inherent implementation]: items/implementations.md#inherent-implementations [item]: items.md [method]: items/associated-items.md#methods +[never type]: types/never.md [object safety]: items/traits.md#object-safety [structs]: items/structs.md [trait objects]: types/trait-object.md