rustdoc: show tuple impls as impl Trait for (T, ...)
This commit adds a new unstable attribute, `#[doc(tuple_varadic)]`, that shows a 1-tuple as `(T, ...)` instead of just `(T,)`, and links to a section in the tuple primitive docs that talks about these.
This commit is contained in:
parent
7a93567005
commit
6950f144cf
@ -401,6 +401,11 @@ macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
|
|||||||
let msg = "`#[doc(keyword)]` is meant for internal use only";
|
let msg = "`#[doc(keyword)]` is meant for internal use only";
|
||||||
gate_feature_post!(self, rustdoc_internals, attr.span, msg);
|
gate_feature_post!(self, rustdoc_internals, attr.span, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if nested_meta.has_name(sym::tuple_varadic) {
|
||||||
|
let msg = "`#[doc(tuple_varadic)]` is meant for internal use only";
|
||||||
|
gate_feature_post!(self, rustdoc_internals, attr.span, msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -804,6 +804,37 @@ fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_doc_tuple_varadic(&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_varadic)]` can only be used on unary tuples",
|
||||||
|
)
|
||||||
|
.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.
|
/// 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
|
/// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
|
||||||
@ -1064,6 +1095,13 @@ fn check_doc_attrs(
|
|||||||
is_valid = false
|
is_valid = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sym::tuple_varadic
|
||||||
|
if !self.check_attr_not_crate_level(meta, hir_id, "tuple_varadic")
|
||||||
|
|| !self.check_doc_tuple_varadic(meta, hir_id) =>
|
||||||
|
{
|
||||||
|
is_valid = false
|
||||||
|
}
|
||||||
|
|
||||||
sym::html_favicon_url
|
sym::html_favicon_url
|
||||||
| sym::html_logo_url
|
| sym::html_logo_url
|
||||||
| sym::html_playground_url
|
| sym::html_playground_url
|
||||||
@ -1117,7 +1155,8 @@ fn check_doc_attrs(
|
|||||||
| sym::no_inline
|
| sym::no_inline
|
||||||
| sym::notable_trait
|
| sym::notable_trait
|
||||||
| sym::passes
|
| sym::passes
|
||||||
| sym::plugins => {}
|
| sym::plugins
|
||||||
|
| sym::tuple_varadic => {}
|
||||||
|
|
||||||
sym::test => {
|
sym::test => {
|
||||||
if !self.check_test_attr(meta, hir_id) {
|
if !self.check_test_attr(meta, hir_id) {
|
||||||
|
@ -1439,6 +1439,7 @@
|
|||||||
tuple,
|
tuple,
|
||||||
tuple_from_req,
|
tuple_from_req,
|
||||||
tuple_indexing,
|
tuple_indexing,
|
||||||
|
tuple_varadic,
|
||||||
two_phase,
|
two_phase,
|
||||||
ty,
|
ty,
|
||||||
type_alias_enum_variants,
|
type_alias_enum_variants,
|
||||||
|
@ -2335,6 +2335,7 @@ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|||||||
|
|
||||||
macro_rules! maybe_tuple_doc {
|
macro_rules! maybe_tuple_doc {
|
||||||
($a:ident @ #[$meta:meta] $item:item) => {
|
($a:ident @ #[$meta:meta] $item:item) => {
|
||||||
|
#[cfg_attr(not(bootstrap), doc(tuple_varadic))]
|
||||||
#[doc = "This trait is implemented for tuples up to twelve items long."]
|
#[doc = "This trait is implemented for tuples up to twelve items long."]
|
||||||
#[$meta]
|
#[$meta]
|
||||||
$item
|
$item
|
||||||
|
@ -900,6 +900,7 @@ fn hash<S: Hasher>(&self, state: &mut S) {
|
|||||||
|
|
||||||
macro_rules! maybe_tuple_doc {
|
macro_rules! maybe_tuple_doc {
|
||||||
($a:ident @ #[$meta:meta] $item:item) => {
|
($a:ident @ #[$meta:meta] $item:item) => {
|
||||||
|
#[cfg_attr(not(bootstrap), doc(tuple_varadic))]
|
||||||
#[doc = "This trait is implemented for tuples up to twelve items long."]
|
#[doc = "This trait is implemented for tuples up to twelve items long."]
|
||||||
#[$meta]
|
#[$meta]
|
||||||
$item
|
$item
|
||||||
|
@ -916,24 +916,11 @@ mod prim_str {}
|
|||||||
///
|
///
|
||||||
/// # Trait implementations
|
/// # Trait implementations
|
||||||
///
|
///
|
||||||
/// If every type inside a tuple implements one of the following traits, then a
|
/// In this documentation the shorthand `(T, ...)` is used to represent all
|
||||||
/// tuple itself also implements it.
|
/// tuples up to length twelve. When that is used, any trait bounds expressed
|
||||||
///
|
/// on `T` applies to each field of the tuple independently. Note that this is
|
||||||
/// * [`Clone`]
|
/// a convenience notation to avoid repetitive documentation, not valid
|
||||||
/// * [`Copy`]
|
/// Rust syntax.
|
||||||
/// * [`PartialEq`]
|
|
||||||
/// * [`Eq`]
|
|
||||||
/// * [`PartialOrd`]
|
|
||||||
/// * [`Ord`]
|
|
||||||
/// * [`Debug`]
|
|
||||||
/// * [`Default`]
|
|
||||||
/// * [`Hash`]
|
|
||||||
///
|
|
||||||
/// [`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.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -978,6 +965,7 @@ impl<T, U> (T, U) {}
|
|||||||
// Fake impl that's only really used for docs.
|
// Fake impl that's only really used for docs.
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[doc(tuple_varadic)]
|
||||||
/// This trait is implemented on arbitrary-length tuples.
|
/// This trait is implemented on arbitrary-length tuples.
|
||||||
impl<T: Clone> Clone for (T,) {
|
impl<T: Clone> Clone for (T,) {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
@ -988,6 +976,7 @@ fn clone(&self) -> Self {
|
|||||||
// Fake impl that's only really used for docs.
|
// Fake impl that's only really used for docs.
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[doc(tuple_varadic)]
|
||||||
/// This trait is implemented on arbitrary-length tuples.
|
/// This trait is implemented on arbitrary-length tuples.
|
||||||
impl<T: Copy> Copy for (T,) {
|
impl<T: Copy> Copy for (T,) {
|
||||||
// empty
|
// empty
|
||||||
|
@ -105,6 +105,7 @@ fn default() -> ($($T,)+) {
|
|||||||
|
|
||||||
macro_rules! maybe_tuple_doc {
|
macro_rules! maybe_tuple_doc {
|
||||||
($a:ident @ #[$meta:meta] $item:item) => {
|
($a:ident @ #[$meta:meta] $item:item) => {
|
||||||
|
#[cfg_attr(not(bootstrap), doc(tuple_varadic))]
|
||||||
#[doc = "This trait is implemented for tuples up to twelve items long."]
|
#[doc = "This trait is implemented for tuples up to twelve items long."]
|
||||||
#[$meta]
|
#[$meta]
|
||||||
$item
|
$item
|
||||||
|
@ -916,24 +916,11 @@ mod prim_str {}
|
|||||||
///
|
///
|
||||||
/// # Trait implementations
|
/// # Trait implementations
|
||||||
///
|
///
|
||||||
/// If every type inside a tuple implements one of the following traits, then a
|
/// In this documentation the shorthand `(T, ...)` is used to represent all
|
||||||
/// tuple itself also implements it.
|
/// tuples up to length twelve. When that is used, any trait bounds expressed
|
||||||
///
|
/// on `T` applies to each field of the tuple independently. Note that this is
|
||||||
/// * [`Clone`]
|
/// a convenience notation to avoid repetitive documentation, not valid
|
||||||
/// * [`Copy`]
|
/// Rust syntax.
|
||||||
/// * [`PartialEq`]
|
|
||||||
/// * [`Eq`]
|
|
||||||
/// * [`PartialOrd`]
|
|
||||||
/// * [`Ord`]
|
|
||||||
/// * [`Debug`]
|
|
||||||
/// * [`Default`]
|
|
||||||
/// * [`Hash`]
|
|
||||||
///
|
|
||||||
/// [`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.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -978,6 +965,7 @@ impl<T, U> (T, U) {}
|
|||||||
// Fake impl that's only really used for docs.
|
// Fake impl that's only really used for docs.
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[doc(tuple_varadic)]
|
||||||
/// This trait is implemented on arbitrary-length tuples.
|
/// This trait is implemented on arbitrary-length tuples.
|
||||||
impl<T: Clone> Clone for (T,) {
|
impl<T: Clone> Clone for (T,) {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
@ -988,6 +976,7 @@ fn clone(&self) -> Self {
|
|||||||
// Fake impl that's only really used for docs.
|
// Fake impl that's only really used for docs.
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[doc(tuple_varadic)]
|
||||||
/// This trait is implemented on arbitrary-length tuples.
|
/// This trait is implemented on arbitrary-length tuples.
|
||||||
impl<T: Copy> Copy for (T,) {
|
impl<T: Copy> Copy for (T,) {
|
||||||
// empty
|
// empty
|
||||||
|
@ -500,7 +500,11 @@ pub(crate) fn build_impl(
|
|||||||
for_,
|
for_,
|
||||||
items: trait_items,
|
items: trait_items,
|
||||||
polarity,
|
polarity,
|
||||||
kind: ImplKind::Normal,
|
kind: if utils::has_doc_flag(tcx, did, sym::tuple_varadic) {
|
||||||
|
ImplKind::TupleVaradic
|
||||||
|
} else {
|
||||||
|
ImplKind::Normal
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
box merged_attrs,
|
box merged_attrs,
|
||||||
cx,
|
cx,
|
||||||
|
@ -1999,7 +1999,11 @@ fn clean_impl<'tcx>(
|
|||||||
for_,
|
for_,
|
||||||
items,
|
items,
|
||||||
polarity: tcx.impl_polarity(def_id),
|
polarity: tcx.impl_polarity(def_id),
|
||||||
kind: ImplKind::Normal,
|
kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), sym::tuple_varadic) {
|
||||||
|
ImplKind::TupleVaradic
|
||||||
|
} else {
|
||||||
|
ImplKind::Normal
|
||||||
|
},
|
||||||
});
|
});
|
||||||
Item::from_hir_id_and_parts(hir_id, None, kind, cx)
|
Item::from_hir_id_and_parts(hir_id, None, kind, cx)
|
||||||
};
|
};
|
||||||
|
@ -2394,6 +2394,7 @@ pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol
|
|||||||
pub(crate) enum ImplKind {
|
pub(crate) enum ImplKind {
|
||||||
Normal,
|
Normal,
|
||||||
Auto,
|
Auto,
|
||||||
|
TupleVaradic,
|
||||||
Blanket(Box<Type>),
|
Blanket(Box<Type>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2406,6 +2407,10 @@ pub(crate) fn is_blanket(&self) -> bool {
|
|||||||
matches!(self, ImplKind::Blanket(_))
|
matches!(self, ImplKind::Blanket(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_tuple_varadic(&self) -> bool {
|
||||||
|
matches!(self, ImplKind::TupleVaradic)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
|
pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
|
||||||
match self {
|
match self {
|
||||||
ImplKind::Blanket(ty) => Some(ty),
|
ImplKind::Blanket(ty) => Some(ty),
|
||||||
|
@ -713,6 +713,16 @@ fn primitive_link(
|
|||||||
prim: clean::PrimitiveType,
|
prim: clean::PrimitiveType,
|
||||||
name: &str,
|
name: &str,
|
||||||
cx: &Context<'_>,
|
cx: &Context<'_>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
primitive_link_fragment(f, prim, name, "", cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn primitive_link_fragment(
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
prim: clean::PrimitiveType,
|
||||||
|
name: &str,
|
||||||
|
fragment: &str,
|
||||||
|
cx: &Context<'_>,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
let m = &cx.cache();
|
let m = &cx.cache();
|
||||||
let mut needs_termination = false;
|
let mut needs_termination = false;
|
||||||
@ -723,7 +733,7 @@ fn primitive_link(
|
|||||||
let len = if len == 0 { 0 } else { len - 1 };
|
let len = if len == 0 { 0 } else { len - 1 };
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"<a class=\"primitive\" href=\"{}primitive.{}.html\">",
|
"<a class=\"primitive\" href=\"{}primitive.{}.html{fragment}\">",
|
||||||
"../".repeat(len),
|
"../".repeat(len),
|
||||||
prim.as_sym()
|
prim.as_sym()
|
||||||
)?;
|
)?;
|
||||||
@ -754,7 +764,7 @@ fn primitive_link(
|
|||||||
};
|
};
|
||||||
if let Some(mut loc) = loc {
|
if let Some(mut loc) = loc {
|
||||||
loc.push_fmt(format_args!("primitive.{}.html", prim.as_sym()));
|
loc.push_fmt(format_args!("primitive.{}.html", prim.as_sym()));
|
||||||
write!(f, "<a class=\"primitive\" href=\"{}\">", loc.finish())?;
|
write!(f, "<a class=\"primitive\" href=\"{}{fragment}\">", loc.finish())?;
|
||||||
needs_termination = true;
|
needs_termination = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1064,7 +1074,11 @@ pub(crate) fn print<'a, 'tcx: 'a>(
|
|||||||
write!(f, " for ")?;
|
write!(f, " for ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ty) = self.kind.as_blanket_ty() {
|
if let clean::Type::Tuple(types) = &self.for_ &&
|
||||||
|
let [clean::Type::Generic(name)] = &types[..] &&
|
||||||
|
(self.kind.is_tuple_varadic() || self.kind.is_auto()) {
|
||||||
|
primitive_link_fragment(f, PrimitiveType::Tuple, &format!("({name}, ...)"), "#trait-implementations-1", cx)?;
|
||||||
|
} else if let Some(ty) = self.kind.as_blanket_ty() {
|
||||||
fmt_type(ty, f, use_absolute, cx)?;
|
fmt_type(ty, f, use_absolute, cx)?;
|
||||||
} else {
|
} else {
|
||||||
fmt_type(&self.for_, f, use_absolute, cx)?;
|
fmt_type(&self.for_, f, use_absolute, cx)?;
|
||||||
|
@ -552,7 +552,7 @@ fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
|
|||||||
let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
|
let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
|
||||||
// FIXME: use something like ImplKind in JSON?
|
// FIXME: use something like ImplKind in JSON?
|
||||||
let (synthetic, blanket_impl) = match kind {
|
let (synthetic, blanket_impl) = match kind {
|
||||||
clean::ImplKind::Normal => (false, None),
|
clean::ImplKind::Normal | clean::ImplKind::TupleVaradic => (false, None),
|
||||||
clean::ImplKind::Auto => (true, None),
|
clean::ImplKind::Auto => (true, None),
|
||||||
clean::ImplKind::Blanket(ty) => (false, Some(*ty)),
|
clean::ImplKind::Blanket(ty) => (false, Some(*ty)),
|
||||||
};
|
};
|
||||||
|
@ -2,4 +2,9 @@
|
|||||||
/// wonderful
|
/// wonderful
|
||||||
mod foo {}
|
mod foo {}
|
||||||
|
|
||||||
|
trait Mine {}
|
||||||
|
|
||||||
|
#[doc(tuple_varadic)] //~ ERROR: `#[doc(tuple_varadic)]` is meant for internal use only
|
||||||
|
impl<T> Mine for (T,) {}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -7,6 +7,15 @@ LL | #[doc(keyword = "match")]
|
|||||||
= note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
|
= note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
|
||||||
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
|
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0658]: `#[doc(tuple_varadic)]` is meant for internal use only
|
||||||
|
--> $DIR/feature-gate-rustdoc_internals.rs:7:1
|
||||||
|
|
|
||||||
|
LL | #[doc(tuple_varadic)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
|
||||||
|
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0658`.
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
Loading…
Reference in New Issue
Block a user