Skip to content

Commit

Permalink
Add docs for never primitive
Browse files Browse the repository at this point in the history
  • Loading branch information
canndrew committed Nov 24, 2017
1 parent 45594d5 commit 6612590
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1783,6 +1783,7 @@ pub enum PrimitiveType {
RawPointer,
Reference,
Fn,
Never,
}

#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
Expand Down Expand Up @@ -1824,6 +1825,7 @@ impl Type {
RawPointer(..) => Some(PrimitiveType::RawPointer),
BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
BareFunction(..) => Some(PrimitiveType::Fn),
Never => Some(PrimitiveType::Never),
_ => None,
}
}
Expand Down Expand Up @@ -1872,6 +1874,7 @@ impl GetDefId for Type {
Primitive(PrimitiveType::Tuple).def_id()
},
BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
Never => Primitive(PrimitiveType::Never).def_id(),
Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
Array(..) => Primitive(PrimitiveType::Array).def_id(),
RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
Expand Down Expand Up @@ -1908,6 +1911,7 @@ impl PrimitiveType {
"pointer" => Some(PrimitiveType::RawPointer),
"reference" => Some(PrimitiveType::Reference),
"fn" => Some(PrimitiveType::Fn),
"never" => Some(PrimitiveType::Never),
_ => None,
}
}
Expand Down Expand Up @@ -1939,6 +1943,7 @@ impl PrimitiveType {
RawPointer => "pointer",
Reference => "reference",
Fn => "fn",
Never => "never",
}
}

Expand Down Expand Up @@ -2873,6 +2878,7 @@ fn build_deref_target_impls(cx: &DocContext,
RawPointer => tcx.lang_items().const_ptr_impl(),
Reference => None,
Fn => None,
Never => None,
};
if let Some(did) = did {
if !did.is_local() {
Expand Down
104 changes: 104 additions & 0 deletions src/libstd/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,110 @@
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_bool { }

#[doc(primitive = "never")]
//
/// The `!` type, also called "never".
///
/// `!` represents the type of computations which never resolve to any value at all. For example,
/// the [`exit`] function `fn exit(code: i32) -> !` exits the process without ever returning, and
/// so returns `!`.
///
/// `break`, `continue` and `return` expressions also have type `!`. For example we are allowed to
/// write
///
/// ```
/// let x: ! = {
/// return 123;
/// };
/// ```
///
/// Although the `let` is pointless here, it illustrates the meaning of `!`. Since `x` is never
/// assigned a value (because `return` returns from the entire function), `x` can be given type
/// `!`. We could also replace `return 123` with a `panic!` or a never-ending `loop` and this code
/// would still be valid.
///
/// A more realistic usage of `!` is in this code:
///
/// ```
/// let num: u32 = match get_a_number() {
/// Some(num) => num,
/// None => break,
/// }
/// ```
///
/// Both match arms must produce values of type `u32`, but since `break` never produces a value at
/// all we know it can never produce a value which isn't a `u32`. This illustrates another
/// behaviour of the `!` type - expressions with type `!` will coerce into any other type.
///
/// [`exit`]: process/fn.exit.html
///
/// # `!` and generics
///
/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`]
/// trait:
///
/// ```
/// trait FromStr {
/// type Error;
/// fn from_str(s: &str) -> Result<Self, Self::Error>;
/// }
/// ```
///
/// When implementing this trait for `String` we need to pick a type for `Error`. And since
/// converting a string into a string will never result in an error, the appropriate type is `!`.
/// If we have to call `String::from_str` for some reason, the result will be a
/// `Result<String, !>`, which we can unpack like this:
///
/// ```
/// let Ok(s) = String::from_str("hello");
/// ```
///
/// Since the `Err` variant contains a `!`, it can never occur. So we can exhaustively match on
/// `Result<T, !>` by just taking the `Ok` variant. This illustrates another behaviour of `!` - it
/// can be used to "delete" certain enum variants from generic types like `Result`.
///
/// [`FromStr`]: str/trait.FromStr.html
///
/// # `!` and traits
///
/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
/// which doesn't `panic!`. As is turns out, most traits can have an `impl` for `!`. Take [`Debug`]
/// for example:
///
/// ```
/// impl Debug for ! {
/// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
/// *self
/// }
/// }
/// ```
///
/// Once again we're using `!`'s ability to coerce into any other type, in this case `fmt::Result`.
/// Since this method takes a `&!` as an argument we know that it can never be called (because
/// there is no value of type `!` for it to be called with). Writing `*self` essentially tells the
/// compiler "We know that this code can never be run, so just treat the entire function body has
/// having type `fmt::Result`". This pattern can be used a lot when implementing traits for `!`.
/// Generally, any trait which only has methods which take a `self` parameter should have such as
/// impl.
///
/// On the other hand, one trait which would not be appropriate to implement is [`Default`]:
///
/// ```
/// trait Default {
/// fn default() -> Self;
/// }
/// ```
///
/// Since `!` has no values, it has no default value either. It's true that we could write an
/// `impl` for this which simply panics, but the same is true for any type (we could `impl
/// Default` for (eg.) `File` by just making `default()` panic.)
///
/// [`Debug`]: fmt/trait.Debug.html
/// [`Default`]: default/trait.Default.html
///
#[stable(feature = "rust1", since = "1.23.0")]
mod prim_never { }

#[doc(primitive = "char")]
//
/// A character type.
Expand Down

0 comments on commit 6612590

Please sign in to comment.