Skip to content

Commit 9d2525a

Browse files
authored
Rollup merge of rust-lang#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 7440221 + 4a80840 commit 9d2525a

File tree

5 files changed

+182
-33
lines changed

5 files changed

+182
-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

+30-16
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,10 @@ fn sidebar_trait<'a>(
224224
}
225225

226226
let mut blocks: Vec<LinkBlock<'_>> = [
227-
("required-associated-types", "Required Associated Types", req_assoc),
228-
("provided-associated-types", "Provided Associated Types", prov_assoc),
229227
("required-associated-consts", "Required Associated Constants", req_assoc_const),
230228
("provided-associated-consts", "Provided Associated Constants", prov_assoc_const),
229+
("required-associated-types", "Required Associated Types", req_assoc),
230+
("provided-associated-types", "Provided Associated Types", prov_assoc),
231231
("required-methods", "Required Methods", req_method),
232232
("provided-methods", "Provided Methods", prov_method),
233233
("foreign-impls", "Implementations on Foreign Types", foreign_impls),
@@ -320,29 +320,22 @@ fn sidebar_assoc_items<'a>(
320320
let cache = cx.cache();
321321

322322
let mut assoc_consts = Vec::new();
323+
let mut assoc_types = Vec::new();
323324
let mut methods = Vec::new();
324325
if let Some(v) = cache.impls.get(&did) {
325326
let mut used_links = FxHashSet::default();
326327
let mut id_map = IdMap::new();
327328

328329
{
329330
let used_links_bor = &mut used_links;
330-
assoc_consts.extend(
331-
v.iter()
332-
.filter(|i| i.inner_impl().trait_.is_none())
333-
.flat_map(|i| get_associated_constants(i.inner_impl(), used_links_bor)),
334-
);
331+
for impl_ in v.iter().map(|i| i.inner_impl()).filter(|i| i.trait_.is_none()) {
332+
assoc_consts.extend(get_associated_constants(impl_, used_links_bor));
333+
assoc_types.extend(get_associated_types(impl_, used_links_bor));
334+
methods.extend(get_methods(impl_, false, used_links_bor, false, cx.tcx()));
335+
}
335336
// We want links' order to be reproducible so we don't use unstable sort.
336337
assoc_consts.sort();
337-
338-
#[rustfmt::skip] // rustfmt makes the pipeline less readable
339-
methods.extend(
340-
v.iter()
341-
.filter(|i| i.inner_impl().trait_.is_none())
342-
.flat_map(|i| get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx())),
343-
);
344-
345-
// We want links' order to be reproducible so we don't use unstable sort.
338+
assoc_types.sort();
346339
methods.sort();
347340
}
348341

@@ -379,6 +372,11 @@ fn sidebar_assoc_items<'a>(
379372
"associatedconstant",
380373
assoc_consts,
381374
),
375+
LinkBlock::new(
376+
Link::new("implementations", "Associated Types"),
377+
"associatedtype",
378+
assoc_types,
379+
),
382380
LinkBlock::new(Link::new("implementations", "Methods"), "method", methods),
383381
];
384382
blocks.append(&mut deref_methods);
@@ -629,3 +627,19 @@ fn get_associated_constants<'a>(
629627
})
630628
.collect::<Vec<_>>()
631629
}
630+
631+
fn get_associated_types<'a>(
632+
i: &'a clean::Impl,
633+
used_links: &mut FxHashSet<String>,
634+
) -> Vec<Link<'a>> {
635+
i.items
636+
.iter()
637+
.filter_map(|item| match item.name {
638+
Some(ref name) if !name.is_empty() && item.is_associated_type() => Some(Link::new(
639+
get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)),
640+
name.as_str(),
641+
)),
642+
_ => None,
643+
})
644+
.collect::<Vec<_>>()
645+
}
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)