-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rustdoc: disambiguate Implementors when the type name is not unique #38414
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
Ignore-whitespace diff: https://github.com/rust-lang/rust/pull/38414/files?w=1 |
// full path, for example in `std::iter::ExactSizeIterator` | ||
let mut dissambiguate = false; | ||
for l in implementors.iter() { | ||
match (k.impl_.for_.clone(), l.impl_.for_.clone()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two .clone() can be removed, just use match (&k.impl_.for_, &l....)
if not rewriting the loop entirely due to the other comment.
match (k.impl_.for_.clone(), l.impl_.for_.clone()) { | ||
(clean::Type::ResolvedPath {path: path_a, ..}, | ||
clean::Type::ResolvedPath {path: path_b, ..}) => { | ||
if k.def_id != l.def_id && path_a.last_name() == path_b.last_name() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed (not in this patch) that last_name creates a String where it could just be a &str
, too.
} | ||
} | ||
_ => (), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The loops are quadratic (complexity) in the number of implementors, I don't think we can afford that. A trait like Clone only lists ~480 impls, but still.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I'm missing something, you can change last_name()
to return &str
and create a HashMap<&str, usize>
or something to count everything's duplicitly here.
@@ -2110,24 +2110,27 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, | |||
<h2 id='implementors'>Implementors</h2> | |||
<ul class='item-list' id='implementors-list'> | |||
")?; | |||
let mut implementor_count: FxHashMap<String, usize> = FxHashMap(); | |||
for (_, implementors) in cache.implementors.iter() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's counting far too many.. all implementors instead of just the ones for this trait(!). I tested a fix.
Can you apply this diff? Then it uses &str instead, and counts the right implementors. I wrote this up to make sure that it was possible (to not make suggestions that can't be). diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 28ca92f..a99d4dd 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2205,8 +2205,8 @@ impl Path {
}
}
- pub fn last_name(&self) -> String {
- self.segments.last().unwrap().name.clone()
+ pub fn last_name(&self) -> &str {
+ &self.segments.last().unwrap().name
}
}
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 846c072..5839c46 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2110,23 +2110,22 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
<h2 id='implementors'>Implementors</h2>
<ul class='item-list' id='implementors-list'>
")?;
- let mut implementor_count: FxHashMap<String, usize> = FxHashMap();
- for (_, implementors) in cache.implementors.iter() {
+ if let Some(implementors) = cache.implementors.get(&it.def_id) {
+ let mut implementor_count: FxHashMap<&str, usize> = FxHashMap();
for implementor in implementors {
if let clean::Type::ResolvedPath {ref path, ..} = implementor.impl_.for_ {
*implementor_count.entry(path.last_name()).or_insert(0) += 1;
}
}
- }
- if let Some(implementors) = cache.implementors.get(&it.def_id) {
- for implementor in implementors.iter() {
+
+ for implementor in implementors {
write!(w, "<li><code>")?;
// If there's already another implementor that has the same abbridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
let dissambiguate = if let clean::Type::ResolvedPath {
ref path, ..
} = implementor.impl_.for_ {
- *implementor_count.get(&path.last_name()).unwrap_or(&0) > 1
+ implementor_count[path.last_name()] > 1
} else {
false
};
|
@bluss applied 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, we can integrate, let's just clean up that bool parameter's name to be consistent across the patch.
@@ -433,7 +433,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> { | |||
/// Used when rendering a `ResolvedPath` structure. This invokes the `path` | |||
/// rendering function with the necessary arguments for linking to a local path. | |||
fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, | |||
print_all: bool) -> fmt::Result { | |||
print_all: bool, use_absolute: bool) -> fmt::Result { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you go through the patch and use the same name for this parameter everywhere (the use_absolute
here)? That's one step that makes a bool parameter more bearable.
// Paths like T::Output and Self::Output should be rendered with all segments | ||
resolved_path(f, did, path, is_generic)?; | ||
tybounds(f, typarams) | ||
fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, full_path: bool) -> fmt::Result { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parameter is the same (full_path
), so this and in other places.
fmt_impl_for_trait_page(&i.impl_, w)?; | ||
// If there's already another implementor that has the same abbridged name, use the | ||
// full path, for example in `std::iter::ExactSizeIterator` | ||
let dissambiguate = if let clean::Type::ResolvedPath { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra s
in the spelling here. It's another of the ones that should have the same name across the patch, though.
/cc @rust-lang/tools |
@bors: r+ thanks! |
Excellent, thanks a lot for this! |
@bors r=steveklabnik |
📌 Commit 346a442 has been approved by |
@bors r=steveklabnik |
💡 This pull request was already approved, no need to approve it again.
|
📌 Commit 346a442 has been approved by |
Rustdoc: disambiguate Implementors when the type name is not unique Presentation [goes from](https://doc.rust-lang.org/stable/std/iter/trait.ExactSizeIterator.html#implementors): <img width="492" alt="" src="https://cloud.githubusercontent.com/assets/1606434/21276752/b2b50474-c387-11e6-96e1-9766851da269.png"> to: <img width="787" alt="" src="https://cloud.githubusercontent.com/assets/1606434/21276763/bb37f6b0-c387-11e6-8596-9163cb254674.png"> on cases where there're multiple implementors with the same name. Fixes #37762.
☀️ Test successful - status-appveyor, status-travis |
Presentation goes from:
to:
on cases where there're multiple implementors with the same name.
Fixes #37762.