diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index a402d79950492..0014cb0f35413 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1197,11 +1197,33 @@ pub(crate) fn render_all_impls( blanket_impl: &[&Impl], ) { let mut impls = Buffer::html(); - render_impls(cx, &mut impls, concrete, containing_item, true); + + let (concrete_local, concrete_nonlocal): (Vec<&Impl>, Vec<&Impl>) = concrete + .into_iter() + .filter(|elem| elem.inner_impl().trait_.is_some()) + .partition(|elem| elem.inner_impl().trait_.as_ref().unwrap().def_id().is_local()); + + render_impls(cx, &mut impls, &concrete_local, containing_item, true); + let impls = impls.into_inner(); if !impls.is_empty() { - write_impl_section_heading(&mut w, "Trait Implementations", "trait-implementations"); - write!(w, "
{impls}
").unwrap(); + write_impl_section_heading( + &mut w, + "Crate Trait Implementations", + "crate-trait-implementations", + ); + write!(w, "
{impls}
").unwrap(); + } + + if !concrete_nonlocal.is_empty() { + write_impl_section_heading( + &mut w, + "External Trait Implementations", + "external-trait-implementations", + ); + w.write_str("
").unwrap(); + render_impls(cx, &mut w, &concrete_nonlocal, containing_item, false); + w.write_str("
").unwrap(); } if !synthetic.is_empty() { diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 842ee81624ef2..26df008caeacc 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -620,6 +620,39 @@ fn sidebar_render_assoc_items( blanket_impl: Vec<&Impl>, items: &mut Vec>, ) { + let format_concrete_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| { + let mut links = FxHashSet::default(); + + let (locals, externals): (Vec<(Link<'static>, bool)>, Vec<(Link<'static>, bool)>) = impls + .iter() + .filter_map(|it| { + let trait_ = it.inner_impl().trait_.as_ref()?; + + let encoded = id_map.derive(super::get_id_for_impl(cx.tcx(), it.impl_item.item_id)); + + let prefix = match it.inner_impl().polarity { + ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", + ty::ImplPolarity::Negative => "!", + }; + let generated = Link::new(encoded, format!("{prefix}{:#}", trait_.print(cx))); + if links.insert(generated.clone()) { + Some((generated, trait_.res.def_id().is_local())) + } else { + None + } + }) + .partition(|elem| elem.1); + + let mut locals = locals.into_iter().map(|elem| elem.0).collect::>>(); + locals.sort(); + + let mut externals = + externals.into_iter().map(|elem| elem.0).collect::>>(); + externals.sort(); + + (locals, externals) + }; + let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| { let mut links = FxHashSet::default(); @@ -641,14 +674,19 @@ fn sidebar_render_assoc_items( ret }; - let concrete = format_impls(concrete, id_map); + let (concrete_locals, concrete_externals) = format_concrete_impls(concrete, id_map); let synthetic = format_impls(synthetic, id_map); let blanket = format_impls(blanket_impl, id_map); items.extend([ LinkBlock::new( - Link::new("trait-implementations", "Trait Implementations"), + Link::new("crate-trait-implementations", "Crate Trait Implementations"), + "trait-implementation", + concrete_locals, + ), + LinkBlock::new( + Link::new("external-trait-implementations", "External Trait Implementations"), "trait-implementation", - concrete, + concrete_externals, ), LinkBlock::new( Link::new("synthetic-implementations", "Auto Trait Implementations"),