Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add docs for never primitive #46232

Merged
merged 6 commits into from
Dec 10, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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")]
//
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this line?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why it was there in the first place, but it does match the other primitive docs.

Copy link
Member

@GuillaumeGomez GuillaumeGomez Nov 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove them then!

@rust-lang/cleanup-team

/// The `!` type, also called "never".
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This "introduction" sounds strange. I expected to have something after directly but just a dot. So strange.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This kind of introduction line matches the other primitives. Compare with "Raw, unsafe pointers, *const T, and *mut T", "References, both shared and mutable", "A finite heterogeneous sequence, (T, U, ..)", all of which appear in the current docs. Do you have a better suggestion?

///
/// `!` 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
Copy link
Member

@GuillaumeGomez GuillaumeGomez Nov 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add :.

///
/// ```
/// 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL for u32.

/// all we know it can never produce a value which isn't a `u32`. This illustrates another
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL for u32.

/// 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");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know these ignore blocks get a little info tooltip and callout border now, but i'd prefer it if we had a comment in here along the lines of "NOTE: This does not work today!", just to sate my paranoia about people blindly copy/pasting examples from docs.

/// ```
///
/// Since the `Err` variant contains a `!`, it can never occur. So we can exhaustively match on
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL for Err.

/// `Result<T, !>` by just taking the `Ok` variant. This illustrates another behaviour of `!` - it
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URLs for Result and Ok.

/// 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`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL for 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 `!`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL for fmt::Result.

/// 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.)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URLs for File and default().

///
/// [`Debug`]: fmt/trait.Debug.html
/// [`Default`]: default/trait.Default.html
///
#[stable(feature = "rust1", since = "1.23.0")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be attached to rust1, or would it be attached to never_type? I would assume the latter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's also the reason why tidy errors:

[00:03:19] tidy error: /checkout/src/libstd/primitive_docs.rs:171: mismatches to previous in: ["since"]
[00:03:19] tidy error: /checkout/src/libstd/primitive_docs.rs:247: mismatches to previous in: ["since"]

because rust1 has been defined elsewhere already (probably with a since field of "1.0.0") and the since field that @canndrew specified "1.23.0" mismatches.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to #[unstable(feature = "never_type_impls", issue = "35121")] since that's what's used in other places in libstd/libcore.

mod prim_never { }

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