Rollup merge of #139943 - fmease:rustdoc-ixcre-trait-aliases, r=GuillaumeGomez

rustdoc: Support inlined cross-crate re-exported trait aliases

Previously we'd just drop them. As a result of this PR, [`core::ptr::Thin`](https://doc.rust-lang.org/nightly/core/ptr/traitalias.Thin.html) will be admitted into the `std` façade!

Also, render the where clause *after* the bounds / the `=`, not before them, as it should be.

r? rustdoc
This commit is contained in:
Matthias Krüger 2025-04-17 17:40:30 +02:00 committed by GitHub
commit 7a4525c883
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 122 additions and 64 deletions

View file

@ -67,9 +67,13 @@ pub(crate) fn try_inline(
record_extern_fqn(cx, did, ItemType::Trait);
cx.with_param_env(did, |cx| {
build_impls(cx, did, attrs_without_docs, &mut ret);
clean::TraitItem(Box::new(build_external_trait(cx, did)))
clean::TraitItem(Box::new(build_trait(cx, did)))
})
}
Res::Def(DefKind::TraitAlias, did) => {
record_extern_fqn(cx, did, ItemType::TraitAlias);
cx.with_param_env(did, |cx| clean::TraitAliasItem(build_trait_alias(cx, did)))
}
Res::Def(DefKind::Fn, did) => {
record_extern_fqn(cx, did, ItemType::Function);
cx.with_param_env(did, |cx| {
@ -251,7 +255,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT
}
}
pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
pub(crate) fn build_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
let trait_items = cx
.tcx
.associated_items(did)
@ -263,11 +267,18 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
let predicates = cx.tcx.predicates_of(did);
let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
let generics = filter_non_trait_generics(did, generics);
let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
let (generics, supertrait_bounds) = separate_self_bounds(generics);
clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
}
pub(crate) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box<clean::Function> {
fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias {
let predicates = cx.tcx.predicates_of(did);
let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
let (generics, bounds) = separate_self_bounds(generics);
clean::TraitAlias { generics, bounds }
}
pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box<clean::Function> {
let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
// The generics need to be cleaned before the signature.
let mut generics =
@ -788,12 +799,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
g
}
/// Supertrait bounds for a trait are also listed in the generics coming from
/// the metadata for a crate, so we want to separate those out and create a new
/// list of explicit supertrait bounds to render nicely.
fn separate_supertrait_bounds(
mut g: clean::Generics,
) -> (clean::Generics, Vec<clean::GenericBound>) {
fn separate_self_bounds(mut g: clean::Generics) -> (clean::Generics, Vec<clean::GenericBound>) {
let mut ty_bounds = Vec::new();
g.where_predicates.retain(|pred| match *pred {
clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => {
@ -806,22 +812,17 @@ fn separate_supertrait_bounds(
}
pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
if did.is_local() {
if did.is_local()
|| cx.external_traits.contains_key(&did)
|| cx.active_extern_traits.contains(&did)
{
return;
}
{
if cx.external_traits.contains_key(&did) || cx.active_extern_traits.contains(&did) {
return;
}
}
{
cx.active_extern_traits.insert(did);
}
cx.active_extern_traits.insert(did);
debug!("record_extern_trait: {did:?}");
let trait_ = build_external_trait(cx, did);
let trait_ = build_trait(cx, did);
cx.external_traits.insert(did, trait_);
cx.active_extern_traits.remove(&did);

View file

@ -27,7 +27,7 @@ use rustc_span::source_map;
use rustc_span::symbol::sym;
use tracing::{debug, info};
use crate::clean::inline::build_external_trait;
use crate::clean::inline::build_trait;
use crate::clean::{self, ItemId};
use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
use crate::formats::cache::Cache;
@ -385,7 +385,7 @@ pub(crate) fn run_global_ctxt(
//
// Note that in case of `#![no_core]`, the trait is not available.
if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
let sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
let sized_trait = build_trait(&mut ctxt, sized_trait_did);
ctxt.external_traits.insert(sized_trait_did, sized_trait);
}

View file

@ -1232,12 +1232,13 @@ fn item_trait_alias(
wrap_item(w, |w| {
write!(
w,
"{attrs}trait {name}{generics}{where_b} = {bounds};",
"{attrs}trait {name}{generics} = {bounds}{where_clause};",
attrs = render_attributes_in_pre(it, "", cx),
name = it.name.unwrap(),
generics = t.generics.print(cx),
where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display(),
bounds = bounds(&t.bounds, true, cx),
where_clause =
print_where_clause(&t.generics, cx, 0, Ending::NoNewline).maybe_display(),
)
})?;

View file

@ -0,0 +1,13 @@
#![feature(trait_alias)]
pub trait ExtAlias0 = Copy + Iterator<Item = u8>;
pub trait ExtAlias1<'a, T: 'a + Clone, const N: usize> = From<[&'a T; N]>;
pub trait ExtAlias2<T> = where T: From<String>, String: Into<T>;
pub trait ExtAlias3 = Sized;
pub trait ExtAlias4 = where Self: Sized;
pub trait ExtAlias5 = ;

View file

@ -1,3 +0,0 @@
#![feature(trait_alias)]
pub trait SomeAlias = std::fmt::Debug + std::marker::Copy;

View file

@ -1,10 +0,0 @@
//@ aux-build:trait-alias-mention.rs
//@ build-aux-docs
#![crate_name = "foo"]
extern crate trait_alias_mention;
//@ has foo/fn.mention_alias_in_bounds.html '//a[@href="../trait_alias_mention/traitalias.SomeAlias.html"]' 'SomeAlias'
pub fn mention_alias_in_bounds<T: trait_alias_mention::SomeAlias>() {
}

View file

@ -0,0 +1,82 @@
// Basic testing for trait aliases.
#![feature(trait_alias)]
#![crate_name = "it"]
// Check the "local case" (HIR cleaning) //
//@ has it/all.html '//a[@href="traitalias.Alias0.html"]' 'Alias0'
//@ has it/index.html '//h2[@id="trait-aliases"]' 'Trait Aliases'
//@ has it/index.html '//a[@class="traitalias"]' 'Alias0'
//@ has it/traitalias.Alias0.html
//@ has - '//*[@class="rust item-decl"]//code' 'trait Alias0 = Copy + Iterator<Item = u8>;'
pub trait Alias0 = Copy + Iterator<Item = u8>;
//@ has it/traitalias.Alias1.html
//@ has - '//pre[@class="rust item-decl"]' \
// "trait Alias1<'a, T: 'a + Clone, const N: usize> = From<[&'a T; N]>;"
pub trait Alias1<'a, T: 'a + Clone, const N: usize> = From<[&'a T; N]>;
//@ has it/traitalias.Alias2.html
//@ has - '//pre[@class="rust item-decl"]' \
// 'trait Alias2<T> = where T: From<String>, String: Into<T>;'
pub trait Alias2<T> = where T: From<String>, String: Into<T>;
//@ has it/traitalias.Alias3.html
//@ has - '//pre[@class="rust item-decl"]' 'trait Alias3 = ;'
pub trait Alias3 =;
//@ has it/traitalias.Alias4.html
//@ has - '//pre[@class="rust item-decl"]' 'trait Alias4 = ;'
pub trait Alias4 = where;
//@ has it/fn.usage0.html
//@ has - '//pre[@class="rust item-decl"]' "pub fn usage0(_: impl Alias0)"
//@ has - '//a[@href="traitalias.Alias0.html"]' 'Alias0'
pub fn usage0(_: impl Alias0) {}
// FIXME: One can only "disambiguate" intra-doc links to trait aliases with `type@` but not with
// `trait@` (fails to resolve) or `traitalias@` (doesn't exist). We should make at least one of
// the latter two work, right?
//@ has it/link0/index.html
//@ has - '//a/@href' 'traitalias.Alias0.html'
//@ has - '//a/@href' 'traitalias.Alias1.html'
/// [Alias0], [type@Alias1]
pub mod link0 {}
// Check the "extern case" (middle cleaning) //
//@ aux-build: ext-trait-aliases.rs
extern crate ext_trait_aliases as ext;
//@ has it/traitalias.ExtAlias0.html
//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias0 = Copy + Iterator<Item = u8>;'
pub use ext::ExtAlias0;
//@ has it/traitalias.ExtAlias1.html
//@ has - '//pre[@class="rust item-decl"]' \
// "trait ExtAlias1<'a, T, const N: usize> = From<[&'a T; N]> where T: 'a + Clone;"
pub use ext::ExtAlias1;
//@ has it/traitalias.ExtAlias2.html
//@ has - '//pre[@class="rust item-decl"]' \
// 'trait ExtAlias2<T> = where T: From<String>, String: Into<T>;'
pub use ext::ExtAlias2;
//@ has it/traitalias.ExtAlias3.html
//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias3 = Sized;'
pub use ext::ExtAlias3;
// NOTE: Middle cleaning can't discern `= Sized` and `= where Self: Sized` and that's okay.
//@ has it/traitalias.ExtAlias4.html
//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias4 = Sized;'
pub use ext::ExtAlias4;
//@ has it/traitalias.ExtAlias5.html
//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias5 = ;'
pub use ext::ExtAlias5;
//@ has it/fn.usage1.html
//@ has - '//pre[@class="rust item-decl"]' "pub fn usage1(_: impl ExtAlias0)"
//@ has - '//a[@href="traitalias.ExtAlias0.html"]' 'ExtAlias0'
pub fn usage1(_: impl ExtAlias0) {}

View file

@ -1,26 +0,0 @@
#![feature(trait_alias)]
#![crate_name = "foo"]
use std::fmt::Debug;
//@ has foo/all.html '//a[@href="traitalias.CopyAlias.html"]' 'CopyAlias'
//@ has foo/all.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
//@ has foo/all.html '//a[@href="traitalias.Foo.html"]' 'Foo'
//@ has foo/index.html '//h2[@id="trait-aliases"]' 'Trait Aliases'
//@ has foo/index.html '//a[@class="traitalias"]' 'CopyAlias'
//@ has foo/index.html '//a[@class="traitalias"]' 'Alias2'
//@ has foo/index.html '//a[@class="traitalias"]' 'Foo'
//@ has foo/traitalias.CopyAlias.html
//@ has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait CopyAlias = Copy;'
pub trait CopyAlias = Copy;
//@ has foo/traitalias.Alias2.html
//@ has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait Alias2 = Copy + Debug;'
pub trait Alias2 = Copy + Debug;
//@ has foo/traitalias.Foo.html
//@ has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait Foo<T> = Into<T> + Debug;'
pub trait Foo<T> = Into<T> + Debug;
//@ has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
pub fn bar<T>() where T: Alias2 {}