Skip to content

Commit 6a23ee5

Browse files
authored
Rollup merge of #129471 - GuillaumeGomez:sort-impl-associated-items, r=t-rustdoc-frontend
[rustdoc] Sort impl associated items by kinds and then by appearance Following [this zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/.22Freeze.22.20order.20of.20items.20in.20.28trait.29.20impls.3F), I implemented it. This brings the following change: impl associated items will now be grouped by kind and will now be first sorted by kind and then by the order they are declared in the source code (like currently). The kinds are sorted in the following order: 1. Constants 2. Types 3. Functions The reason behind this order is that associated constants can be used in associated types (like length in arrays) and both associated types and associated constants can be used in associated functions. So if an associated item from the same impl is used, its definition will always be above where it's being used. cc ``@camelid`` r? ``@notriddle``
2 parents b0cc78c + 8f9c4b3 commit 6a23ee5

File tree

5 files changed

+183
-33
lines changed

5 files changed

+183
-33
lines changed

src/librustdoc/html/render/mod.rs

+52-1
Original file line numberDiff line numberDiff line change
@@ -1794,13 +1794,64 @@ fn render_impl(
17941794
let mut default_impl_items = Buffer::empty_from(w);
17951795
let impl_ = i.inner_impl();
17961796

1797+
// Impl items are grouped by kinds:
1798+
//
1799+
// 1. Constants
1800+
// 2. Types
1801+
// 3. Functions
1802+
//
1803+
// This order is because you can have associated constants used in associated types (like array
1804+
// length), and both in associcated functions. So with this order, when reading from top to
1805+
// bottom, you should see items definitions before they're actually used most of the time.
1806+
let mut assoc_types = Vec::new();
1807+
let mut methods = Vec::new();
1808+
17971809
if !impl_.is_negative_trait_impl() {
17981810
for trait_item in &impl_.items {
1811+
match *trait_item.kind {
1812+
clean::MethodItem(..) | clean::TyMethodItem(_) => methods.push(trait_item),
1813+
clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => {
1814+
assoc_types.push(trait_item)
1815+
}
1816+
clean::TyAssocConstItem(..) | clean::AssocConstItem(_) => {
1817+
// We render it directly since they're supposed to come first.
1818+
doc_impl_item(
1819+
&mut default_impl_items,
1820+
&mut impl_items,
1821+
cx,
1822+
trait_item,
1823+
if trait_.is_some() { &i.impl_item } else { parent },
1824+
link,
1825+
render_mode,
1826+
false,
1827+
trait_,
1828+
rendering_params,
1829+
);
1830+
}
1831+
_ => {}
1832+
}
1833+
}
1834+
1835+
for assoc_type in assoc_types {
17991836
doc_impl_item(
18001837
&mut default_impl_items,
18011838
&mut impl_items,
18021839
cx,
1803-
trait_item,
1840+
assoc_type,
1841+
if trait_.is_some() { &i.impl_item } else { parent },
1842+
link,
1843+
render_mode,
1844+
false,
1845+
trait_,
1846+
rendering_params,
1847+
);
1848+
}
1849+
for method in methods {
1850+
doc_impl_item(
1851+
&mut default_impl_items,
1852+
&mut impl_items,
1853+
cx,
1854+
method,
18041855
if trait_.is_some() { &i.impl_item } else { parent },
18051856
link,
18061857
render_mode,

src/librustdoc/html/render/print_item.rs

+16-16
Original file line numberDiff line numberDiff line change
@@ -843,55 +843,55 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
843843
}
844844
}
845845

846-
if !required_types.is_empty() {
846+
if !required_consts.is_empty() {
847847
write_section_heading(
848848
w,
849-
"Required Associated Types",
850-
"required-associated-types",
849+
"Required Associated Constants",
850+
"required-associated-consts",
851851
None,
852852
"<div class=\"methods\">",
853853
);
854-
for t in required_types {
854+
for t in required_consts {
855855
trait_item(w, cx, t, it);
856856
}
857857
w.write_str("</div>");
858858
}
859-
if !provided_types.is_empty() {
859+
if !provided_consts.is_empty() {
860860
write_section_heading(
861861
w,
862-
"Provided Associated Types",
863-
"provided-associated-types",
862+
"Provided Associated Constants",
863+
"provided-associated-consts",
864864
None,
865865
"<div class=\"methods\">",
866866
);
867-
for t in provided_types {
867+
for t in provided_consts {
868868
trait_item(w, cx, t, it);
869869
}
870870
w.write_str("</div>");
871871
}
872872

873-
if !required_consts.is_empty() {
873+
if !required_types.is_empty() {
874874
write_section_heading(
875875
w,
876-
"Required Associated Constants",
877-
"required-associated-consts",
876+
"Required Associated Types",
877+
"required-associated-types",
878878
None,
879879
"<div class=\"methods\">",
880880
);
881-
for t in required_consts {
881+
for t in required_types {
882882
trait_item(w, cx, t, it);
883883
}
884884
w.write_str("</div>");
885885
}
886-
if !provided_consts.is_empty() {
886+
if !provided_types.is_empty() {
887887
write_section_heading(
888888
w,
889-
"Provided Associated Constants",
890-
"provided-associated-consts",
889+
"Provided Associated Types",
890+
"provided-associated-types",
891891
None,
892892
"<div class=\"methods\">",
893893
);
894-
for t in provided_consts {
894+
for t in provided_types {
895895
trait_item(w, cx, t, it);
896896
}
897897
w.write_str("</div>");

src/librustdoc/html/render/sidebar.rs

+31-16
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,10 @@ fn sidebar_trait<'a>(
302302

303303
blocks.extend(
304304
[
305-
("required-associated-types", "Required Associated Types", req_assoc),
306-
("provided-associated-types", "Provided Associated Types", prov_assoc),
307305
("required-associated-consts", "Required Associated Constants", req_assoc_const),
308306
("provided-associated-consts", "Provided Associated Constants", prov_assoc_const),
307+
("required-associated-types", "Required Associated Types", req_assoc),
308+
("provided-associated-types", "Provided Associated Types", prov_assoc),
309309
("required-methods", "Required Methods", req_method),
310310
("provided-methods", "Provided Methods", prov_method),
311311
("foreign-impls", "Implementations on Foreign Types", foreign_impls),
@@ -394,29 +394,22 @@ fn sidebar_assoc_items<'a>(
394394
let cache = cx.cache();
395395

396396
let mut assoc_consts = Vec::new();
397+
let mut assoc_types = Vec::new();
397398
let mut methods = Vec::new();
398399
if let Some(v) = cache.impls.get(&did) {
399400
let mut used_links = FxHashSet::default();
400401
let mut id_map = IdMap::new();
401402

402403
{
403404
let used_links_bor = &mut used_links;
404-
assoc_consts.extend(
405-
v.iter()
406-
.filter(|i| i.inner_impl().trait_.is_none())
407-
.flat_map(|i| get_associated_constants(i.inner_impl(), used_links_bor)),
408-
);
405+
for impl_ in v.iter().map(|i| i.inner_impl()).filter(|i| i.trait_.is_none()) {
406+
assoc_consts.extend(get_associated_constants(impl_, used_links_bor));
407+
assoc_types.extend(get_associated_types(impl_, used_links_bor));
408+
methods.extend(get_methods(impl_, false, used_links_bor, false, cx.tcx()));
409+
}
409410
// We want links' order to be reproducible so we don't use unstable sort.
410411
assoc_consts.sort();
411-
412-
#[rustfmt::skip] // rustfmt makes the pipeline less readable
413-
methods.extend(
414-
v.iter()
415-
.filter(|i| i.inner_impl().trait_.is_none())
416-
.flat_map(|i| get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx())),
417-
);
418-
419-
// We want links' order to be reproducible so we don't use unstable sort.
412+
assoc_types.sort();
420413
methods.sort();
421414
}
422415

@@ -426,6 +419,11 @@ fn sidebar_assoc_items<'a>(
426419
"associatedconstant",
427420
assoc_consts,
428421
),
422+
LinkBlock::new(
423+
Link::new("implementations", "Associated Types"),
424+
"associatedtype",
425+
assoc_types,
426+
),
429427
LinkBlock::new(Link::new("implementations", "Methods"), "method", methods),
430428
];
431429

@@ -452,6 +450,7 @@ fn sidebar_assoc_items<'a>(
452450
&mut blocks,
453451
);
454452
}
453+
455454
links.append(&mut blocks);
456455
}
457456
}
@@ -715,3 +714,19 @@ fn get_associated_constants<'a>(
715714
})
716715
.collect::<Vec<_>>()
717716
}
717+
718+
fn get_associated_types<'a>(
719+
i: &'a clean::Impl,
720+
used_links: &mut FxHashSet<String>,
721+
) -> Vec<Link<'a>> {
722+
i.items
723+
.iter()
724+
.filter_map(|item| match item.name {
725+
Some(ref name) if !name.is_empty() && item.is_associated_type() => Some(Link::new(
726+
get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)),
727+
name.as_str(),
728+
)),
729+
_ => None,
730+
})
731+
.collect::<Vec<_>>()
732+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// This test ensures that impl associated items always follow this order:
2+
//
3+
// 1. Consts
4+
// 2. Types
5+
// 3. Functions
6+
7+
#![feature(inherent_associated_types)]
8+
#![allow(incomplete_features)]
9+
#![crate_name = "foo"]
10+
11+
//@ has 'foo/struct.Bar.html'
12+
pub struct Bar;
13+
14+
impl Bar {
15+
//@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[3]/h4' \
16+
// 'pub fn foo()'
17+
pub fn foo() {}
18+
//@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[1]/h4' \
19+
// 'pub const X: u8 = 12u8'
20+
pub const X: u8 = 12;
21+
//@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[2]/h4' \
22+
// 'pub type Y = u8'
23+
pub type Y = u8;
24+
}
25+
26+
pub trait Foo {
27+
const W: u32;
28+
fn yeay();
29+
type Z;
30+
}
31+
32+
impl Foo for Bar {
33+
//@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[2]/h4' \
34+
// 'type Z = u8'
35+
type Z = u8;
36+
//@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[1]/h4' \
37+
// 'const W: u32 = 12u32'
38+
const W: u32 = 12;
39+
//@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[3]/h4' \
40+
// 'fn yeay()'
41+
fn yeay() {}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// This test ensures that impl/trait associated items are listed in the sidebar.
2+
3+
// ignore-tidy-linelength
4+
5+
#![feature(inherent_associated_types)]
6+
#![feature(associated_type_defaults)]
7+
#![allow(incomplete_features)]
8+
#![crate_name = "foo"]
9+
10+
//@ has 'foo/struct.Bar.html'
11+
pub struct Bar;
12+
13+
impl Bar {
14+
//@ has - '//*[@class="sidebar-elems"]//h3[1]' 'Associated Constants'
15+
//@ has - '//*[@class="sidebar-elems"]//ul[@class="block associatedconstant"]/li/a[@href="#associatedconstant.X"]' 'X'
16+
pub const X: u8 = 12;
17+
//@ has - '//*[@class="sidebar-elems"]//h3[2]' 'Associated Types'
18+
//@ has - '//*[@class="sidebar-elems"]//ul[@class="block associatedtype"]/li/a[@href="#associatedtype.Y"]' 'Y'
19+
pub type Y = u8;
20+
}
21+
22+
//@ has 'foo/trait.Foo.html'
23+
pub trait Foo {
24+
//@ has - '//*[@class="sidebar-elems"]//h3[5]' 'Required Methods'
25+
//@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][5]/li/a[@href="#tymethod.yeay"]' 'yeay'
26+
fn yeay();
27+
//@ has - '//*[@class="sidebar-elems"]//h3[6]' 'Provided Methods'
28+
//@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][6]/li/a[@href="#method.boo"]' 'boo'
29+
fn boo() {}
30+
//@ has - '//*[@class="sidebar-elems"]//h3[1]' 'Required Associated Constants'
31+
//@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][1]/li/a[@href="#associatedconstant.W"]' 'W'
32+
const W: u32;
33+
//@ has - '//*[@class="sidebar-elems"]//h3[2]' 'Provided Associated Constants'
34+
//@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][2]/li/a[@href="#associatedconstant.U"]' 'U'
35+
const U: u32 = 0;
36+
//@ has - '//*[@class="sidebar-elems"]//h3[3]' 'Required Associated Types'
37+
//@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][3]/li/a[@href="#associatedtype.Z"]' 'Z'
38+
type Z;
39+
//@ has - '//*[@class="sidebar-elems"]//h3[4]' 'Provided Associated Types'
40+
//@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][4]/li/a[@href="#associatedtype.T"]' 'T'
41+
type T = u32;
42+
}

0 commit comments

Comments
 (0)