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"),