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

Improve the tuple and unit trait docs #97842

Merged
merged 19 commits into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
let msg = "`#[doc(keyword)]` is meant for internal use only";
gate_feature_post!(self, rustdoc_internals, attr.span, msg);
}

if nested_meta.has_name(sym::tuple_variadic) {
let msg = "`#[doc(tuple_variadic)]` is meant for internal use only";
gate_feature_post!(self, rustdoc_internals, attr.span, msg);
}
}
}

Expand Down
41 changes: 40 additions & 1 deletion compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,37 @@ impl CheckAttrVisitor<'_> {
true
}

fn check_doc_tuple_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
match self.tcx.hir().find(hir_id).and_then(|node| match node {
hir::Node::Item(item) => Some(&item.kind),
_ => None,
}) {
Some(ItemKind::Impl(ref i)) => {
if !matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) {
self.tcx
.sess
.struct_span_err(
meta.span(),
"`#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity",
)
.emit();
return false;
}
}
_ => {
self.tcx
.sess
.struct_span_err(
meta.span(),
"`#[doc(keyword = \"...\")]` can only be used on impl blocks",
)
.emit();
return false;
}
}
true
}

/// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes. Returns `true` if valid.
///
/// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
Expand Down Expand Up @@ -1064,6 +1095,13 @@ impl CheckAttrVisitor<'_> {
is_valid = false
}

sym::tuple_variadic
if !self.check_attr_not_crate_level(meta, hir_id, "tuple_variadic")
|| !self.check_doc_tuple_variadic(meta, hir_id) =>
{
is_valid = false
}

sym::html_favicon_url
| sym::html_logo_url
| sym::html_playground_url
Expand Down Expand Up @@ -1117,7 +1155,8 @@ impl CheckAttrVisitor<'_> {
| sym::no_inline
| sym::notable_trait
| sym::passes
| sym::plugins => {}
| sym::plugins
| sym::tuple_variadic => {}

sym::test => {
if !self.check_test_attr(meta, hir_id) {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,7 @@ symbols! {
tuple,
tuple_from_req,
tuple_indexing,
tuple_variadic,
two_phase,
ty,
type_alias_enum_variants,
Expand Down
1 change: 0 additions & 1 deletion library/core/src/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ use crate::marker::Destruct;
///
/// * Function item types (i.e., the distinct types defined for each function)
/// * Function pointer types (e.g., `fn() -> i32`)
/// * Tuple types, if each component also implements `Clone` (e.g., `()`, `(i32, bool)`)
jsha marked this conversation as resolved.
Show resolved Hide resolved
/// * Closure types, if they capture no value from the environment
/// or if all such captured values implement `Clone` themselves.
/// Note that variables captured by shared reference always implement `Clone`
Expand Down
41 changes: 29 additions & 12 deletions library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2313,29 +2313,46 @@ macro_rules! peel {
macro_rules! tuple {
() => ();
( $($name:ident,)+ ) => (
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($name:Debug),+> Debug for ($($name,)+) where last_type!($($name,)+): ?Sized {
#[allow(non_snake_case, unused_assignments)]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let mut builder = f.debug_tuple("");
let ($(ref $name,)+) = *self;
$(
builder.field(&$name);
)+

builder.finish()
maybe_tuple_doc! {
$($name)+ @
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($name:Debug),+> Debug for ($($name,)+) where last_type!($($name,)+): ?Sized {
#[allow(non_snake_case, unused_assignments)]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let mut builder = f.debug_tuple("");
let ($(ref $name,)+) = *self;
$(
builder.field(&$name);
)+

builder.finish()
}
}
}
peel! { $($name,)+ }
)
}

macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
#[cfg_attr(not(bootstrap), doc(tuple_variadic))]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
};
($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
#[doc(hidden)]
#[$meta]
$item
};
}

macro_rules! last_type {
($a:ident,) => { $a };
($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
}

tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
tuple! { E, D, C, B, A, Z, Y, X, W, V, U, T, }

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for [T] {
Expand Down
55 changes: 36 additions & 19 deletions library/core/src/hash/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,36 +883,53 @@ mod impls {
);

( $($name:ident)+) => (
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
#[allow(non_snake_case)]
#[inline]
fn hash<S: Hasher>(&self, state: &mut S) {
let ($(ref $name,)+) = *self;
$($name.hash(state);)+
maybe_tuple_doc! {
$($name)+ @
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
#[allow(non_snake_case)]
#[inline]
fn hash<S: Hasher>(&self, state: &mut S) {
let ($(ref $name,)+) = *self;
$($name.hash(state);)+
}
}
}
);
}

macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
#[cfg_attr(not(bootstrap), doc(tuple_variadic))]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
};
($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
#[doc(hidden)]
#[$meta]
$item
};
}

macro_rules! last_type {
($a:ident,) => { $a };
($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
}

impl_hash_tuple! {}
impl_hash_tuple! { A }
impl_hash_tuple! { A B }
impl_hash_tuple! { A B C }
impl_hash_tuple! { A B C D }
impl_hash_tuple! { A B C D E }
impl_hash_tuple! { A B C D E F }
impl_hash_tuple! { A B C D E F G }
impl_hash_tuple! { A B C D E F G H }
impl_hash_tuple! { A B C D E F G H I }
impl_hash_tuple! { A B C D E F G H I J }
impl_hash_tuple! { A B C D E F G H I J K }
impl_hash_tuple! { A B C D E F G H I J K L }
impl_hash_tuple! { T }
impl_hash_tuple! { T B }
impl_hash_tuple! { T B C }
impl_hash_tuple! { T B C D }
impl_hash_tuple! { T B C D E }
impl_hash_tuple! { T B C D E F }
impl_hash_tuple! { T B C D E F G }
impl_hash_tuple! { T B C D E F G H }
impl_hash_tuple! { T B C D E F G H I }
impl_hash_tuple! { T B C D E F G H I J }
impl_hash_tuple! { T B C D E F G H I J K }
impl_hash_tuple! { T B C D E F G H I J K L }

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for [T] {
Expand Down
1 change: 0 additions & 1 deletion library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,6 @@ pub trait StructuralEq {
///
/// * Function item types (i.e., the distinct types defined for each function)
/// * Function pointer types (e.g., `fn() -> i32`)
/// * Tuple types, if each component also implements `Copy` (e.g., `()`, `(i32, bool)`)
/// * Closure types, if they capture no value from the environment
/// or if all such captured values implement `Copy` themselves.
/// Note that variables captured by shared reference always implement `Copy`
Expand Down
76 changes: 70 additions & 6 deletions library/core/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,27 @@ mod prim_char {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_unit {}

// Required to make auto trait impls render.
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
#[doc(hidden)]
impl () {}

// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for () {
fn clone(&self) -> Self {
loop {}
}
}

// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
impl Copy for () {
// empty
}

#[doc(primitive = "pointer")]
#[doc(alias = "ptr")]
#[doc(alias = "*")]
Expand Down Expand Up @@ -893,13 +914,18 @@ mod prim_str {}
///
/// For more about tuples, see [the book](../book/ch03-02-data-types.html#the-tuple-type).
///
// Hardcoded anchor in src/librustdoc/html/format.rs
// linked to as `#trait-implementations-1`
/// # Trait implementations
///
/// If every type inside a tuple implements one of the following traits, then a
/// tuple itself also implements it.
/// In this documentation the shorthand `(T₁, T₂, …, Tₙ)` is used to represent tuples of varying
/// length. When that is used, any trait bound expressed on `T` applies to each element of the
/// tuple independently. Note that this is a convenience notation to avoid repetitive
/// documentation, not valid Rust syntax.
///
/// Due to a temporary restriction in Rust’s type system, the following traits are only
/// implemented on tuples of arity 12 or less. In the future, this may change:
///
/// * [`Clone`]
/// * [`Copy`]
/// * [`PartialEq`]
/// * [`Eq`]
/// * [`PartialOrd`]
Expand All @@ -911,8 +937,21 @@ mod prim_str {}
/// [`Debug`]: fmt::Debug
/// [`Hash`]: hash::Hash
///
/// Due to a temporary restriction in Rust's type system, these traits are only
/// implemented on tuples of arity 12 or less. In the future, this may change.
/// The following traits are implemented for tuples of any length. These traits have
/// implementations that are automatically generated by the compiler, so are not limited by
/// missing language features.
///
/// * [`Clone`]
/// * [`Copy`]
/// * [`Send`]
/// * [`Sync`]
/// * [`Unpin`]
/// * [`UnwindSafe`]
/// * [`RefUnwindSafe`]
///
/// [`Unpin`]: marker::Unpin
/// [`UnwindSafe`]: panic::UnwindSafe
/// [`RefUnwindSafe`]: panic::RefUnwindSafe
///
/// # Examples
///
Expand Down Expand Up @@ -949,6 +988,31 @@ mod prim_str {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_tuple {}

// Required to make auto trait impls render.
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
#[doc(hidden)]
impl<T> (T,) {}

// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(bootstrap), doc(tuple_variadic))]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Clone> Clone for (T,) {
fn clone(&self) -> Self {
loop {}
}
}

// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(bootstrap), doc(tuple_variadic))]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Copy> Copy for (T,) {
// empty
}

#[doc(primitive = "f32")]
/// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
///
Expand Down
Loading