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";
|
||||
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
|
||||
}
|
||||
|
||||
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.
|
||||
///
|
||||
/// 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
|
||||
}
|
||||
|
||||
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_logo_url
|
||||
| sym::html_playground_url
|
||||
@ -1117,7 +1155,8 @@ fn check_doc_attrs(
|
||||
| sym::no_inline
|
||||
| sym::notable_trait
|
||||
| sym::passes
|
||||
| sym::plugins => {}
|
||||
| sym::plugins
|
||||
| sym::tuple_varadic => {}
|
||||
|
||||
sym::test => {
|
||||
if !self.check_test_attr(meta, hir_id) {
|
||||
|
@ -1439,6 +1439,7 @@
|
||||
tuple,
|
||||
tuple_from_req,
|
||||
tuple_indexing,
|
||||
tuple_varadic,
|
||||
two_phase,
|
||||
ty,
|
||||
type_alias_enum_variants,
|
||||
|
@ -2335,6 +2335,7 @@ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
|
||||
macro_rules! maybe_tuple_doc {
|
||||
($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."]
|
||||
#[$meta]
|
||||
$item
|
||||
|
@ -900,6 +900,7 @@ fn hash<S: Hasher>(&self, state: &mut S) {
|
||||
|
||||
macro_rules! maybe_tuple_doc {
|
||||
($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."]
|
||||
#[$meta]
|
||||
$item
|
||||
|
@ -916,24 +916,11 @@ mod prim_str {}
|
||||
///
|
||||
/// # Trait implementations
|
||||
///
|
||||
/// If every type inside a tuple implements one of the following traits, then a
|
||||
/// tuple itself also implements it.
|
||||
///
|
||||
/// * [`Clone`]
|
||||
/// * [`Copy`]
|
||||
/// * [`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.
|
||||
/// In this documentation the shorthand `(T, ...)` is used to represent all
|
||||
/// 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
|
||||
/// a convenience notation to avoid repetitive documentation, not valid
|
||||
/// Rust syntax.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -978,6 +965,7 @@ impl<T, U> (T, U) {}
|
||||
// Fake impl that's only really used for docs.
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(tuple_varadic)]
|
||||
/// This trait is implemented on arbitrary-length tuples.
|
||||
impl<T: Clone> Clone for (T,) {
|
||||
fn clone(&self) -> Self {
|
||||
@ -988,6 +976,7 @@ fn clone(&self) -> Self {
|
||||
// Fake impl that's only really used for docs.
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(tuple_varadic)]
|
||||
/// This trait is implemented on arbitrary-length tuples.
|
||||
impl<T: Copy> Copy for (T,) {
|
||||
// empty
|
||||
|
@ -105,6 +105,7 @@ fn default() -> ($($T,)+) {
|
||||
|
||||
macro_rules! maybe_tuple_doc {
|
||||
($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."]
|
||||
#[$meta]
|
||||
$item
|
||||
|
@ -916,24 +916,11 @@ mod prim_str {}
|
||||
///
|
||||
/// # Trait implementations
|
||||
///
|
||||
/// If every type inside a tuple implements one of the following traits, then a
|
||||
/// tuple itself also implements it.
|
||||
///
|
||||
/// * [`Clone`]
|
||||
/// * [`Copy`]
|
||||
/// * [`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.
|
||||
/// In this documentation the shorthand `(T, ...)` is used to represent all
|
||||
/// 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
|
||||
/// a convenience notation to avoid repetitive documentation, not valid
|
||||
/// Rust syntax.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -978,6 +965,7 @@ impl<T, U> (T, U) {}
|
||||
// Fake impl that's only really used for docs.
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(tuple_varadic)]
|
||||
/// This trait is implemented on arbitrary-length tuples.
|
||||
impl<T: Clone> Clone for (T,) {
|
||||
fn clone(&self) -> Self {
|
||||
@ -988,6 +976,7 @@ fn clone(&self) -> Self {
|
||||
// Fake impl that's only really used for docs.
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(tuple_varadic)]
|
||||
/// This trait is implemented on arbitrary-length tuples.
|
||||
impl<T: Copy> Copy for (T,) {
|
||||
// empty
|
||||
|
@ -500,7 +500,11 @@ pub(crate) fn build_impl(
|
||||
for_,
|
||||
items: trait_items,
|
||||
polarity,
|
||||
kind: ImplKind::Normal,
|
||||
kind: if utils::has_doc_flag(tcx, did, sym::tuple_varadic) {
|
||||
ImplKind::TupleVaradic
|
||||
} else {
|
||||
ImplKind::Normal
|
||||
},
|
||||
}),
|
||||
box merged_attrs,
|
||||
cx,
|
||||
|
@ -1999,7 +1999,11 @@ fn clean_impl<'tcx>(
|
||||
for_,
|
||||
items,
|
||||
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)
|
||||
};
|
||||
|
@ -2394,6 +2394,7 @@ pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol
|
||||
pub(crate) enum ImplKind {
|
||||
Normal,
|
||||
Auto,
|
||||
TupleVaradic,
|
||||
Blanket(Box<Type>),
|
||||
}
|
||||
|
||||
@ -2406,6 +2407,10 @@ pub(crate) fn is_blanket(&self) -> bool {
|
||||
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> {
|
||||
match self {
|
||||
ImplKind::Blanket(ty) => Some(ty),
|
||||
|
@ -713,6 +713,16 @@ fn primitive_link(
|
||||
prim: clean::PrimitiveType,
|
||||
name: &str,
|
||||
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 {
|
||||
let m = &cx.cache();
|
||||
let mut needs_termination = false;
|
||||
@ -723,7 +733,7 @@ fn primitive_link(
|
||||
let len = if len == 0 { 0 } else { len - 1 };
|
||||
write!(
|
||||
f,
|
||||
"<a class=\"primitive\" href=\"{}primitive.{}.html\">",
|
||||
"<a class=\"primitive\" href=\"{}primitive.{}.html{fragment}\">",
|
||||
"../".repeat(len),
|
||||
prim.as_sym()
|
||||
)?;
|
||||
@ -754,7 +764,7 @@ fn primitive_link(
|
||||
};
|
||||
if let Some(mut loc) = loc {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1064,7 +1074,11 @@ pub(crate) fn print<'a, 'tcx: 'a>(
|
||||
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)?;
|
||||
} else {
|
||||
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));
|
||||
// FIXME: use something like ImplKind in JSON?
|
||||
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::Blanket(ty) => (false, Some(*ty)),
|
||||
};
|
||||
|
@ -2,4 +2,9 @@
|
||||
/// wonderful
|
||||
mod foo {}
|
||||
|
||||
trait Mine {}
|
||||
|
||||
#[doc(tuple_varadic)] //~ ERROR: `#[doc(tuple_varadic)]` is meant for internal use only
|
||||
impl<T> Mine for (T,) {}
|
||||
|
||||
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
|
||||
= 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`.
|
||||
|
Loading…
Reference in New Issue
Block a user