-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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: Fix generics generation in search index #88268
Conversation
Some changes occurred in HTML/CSS/JS. |
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 used this opportunity to allow generics to have generics themselves
What does this mean? What code does it allow you to represent? I'm not really clear what any of this code is doing ...
RenderType { | ||
name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()), | ||
generics: get_generics(clean_type), | ||
generics: if generics.is_empty() { None } else { Some(generics) }, |
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.
Why store an option for this? The caller can check if the Vec is empty, this means it has to check for both None and empty.
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.
Because if it's not an option, it'll generate []
, which is unneeded. Before to not generate anything then.
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'll add a comment to make it clear.
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'm confused though - can't you just do this same check wherever it would generate an empty Vec? Why does it have to be specifically here?
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'm not sure about the other places... In this case, it's contained inside a vec, so if the vec length is 1 or 2, it's not really a problem. For the other places, it might be different.
1 | ||
} else { | ||
0 | ||
res.push(TypeWithKind::from((index_ty, ItemType::Primitive))); |
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.
Why did you change this bit? How do you know it's a primitive? Can you add an assertion?
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.
There is a ty.is_primitive()
check just like before. Did I miss something?
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.
Oh, I misread the code. Why did you remove the else branch? What did 0 represent?
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.
Before, it returned the number of items inserted to know if something needed to be added into the HashSet. Now we add all arguments (as long as they have a name).
So basically, the else
branch did nothing and returned value confirming it did nothing.
Let's take an example then! struct Foo<A, B>(A, B);
fn foo<A: Display, B: Foo<u32, u64>, C: Foo<A, B>>(arg: A) {} Like this, |
843afc5
to
6758aa8
Compare
This comment has been minimized.
This comment has been minimized.
6758aa8
to
518e8aa
Compare
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.
Is there a reference for how the search index works somewhere? Your examples helped but I have no idea how they'll actually affect search, I don't really feel comfortable signing off on this. Maybe @notriddle or @ollie27 are familiar with search?
1 | ||
} else { | ||
0 | ||
res.push(TypeWithKind::from((index_ty, ItemType::Primitive))); |
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.
Oh, I misread the code. Why did you remove the else branch? What did 0 represent?
// }] | ||
// ``` | ||
// | ||
// To be noted that it can work if there is ONLY ONE generic, otherwise we 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.
Why does it only work if there's a single generic argument? It seems weird to have an outer object that just has 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.
It's what I tried to explain but I failed I guess haha.
So basically, arguments can only have a type and generics. What happens in case the argument is a full generic which is Display + Debug + Write
? Then we can't say it's one type (from a search perspective) but a generic type (with empty name) having three generics.
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 just discussed this with Guillaume, and I think I can explain it now.
For purposes of search-indexing, fn foo<T: Display>(x: T)
is treated as the type fn(x: Display)
. This makes a search like trait:Display ->
show foo
. (It turns out you can filter by item type in rustdoc searches, which is part of what ItemType
is for.)
However, fn foo<T: Display + Clone>(x: T)
's argument cannot be reduced into an ItemType::Trait
because there are two traits involved, the Display
trait and the Clone
trait. So instead it's represented as a ItemType::Generic
, which means there was more than one bound involved.
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.
Exactly. :)
RenderType { | ||
name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()), | ||
generics: get_generics(clean_type), | ||
generics: if generics.is_empty() { None } else { Some(generics) }, |
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'm confused though - can't you just do this same check wherever it would generate an empty Vec? Why does it have to be specifically here?
518e8aa
to
c6b1f3e
Compare
This comment has been minimized.
This comment has been minimized.
c6b1f3e
to
ee93609
Compare
ping @jyn514 |
I don't really understand this example. Why will Also, How did the search index look previously? Based on your description, it sounds like the type of this function used to be treated as something like Sorry for all the questions; I'm not very familiar with the search-index code ;) |
Woups, I meant that struct Foo<A, B>(A, B);
fn foo<A: Display, B: Foo<u32, u64>, C: Foo<A, B>>(arg: C) {} And indeed, it looks like a tree:
|
@@ -48,6 +48,7 @@ crate enum ItemType { | |||
ProcAttribute = 23, | |||
ProcDerive = 24, | |||
TraitAlias = 25, | |||
Generic = 26, |
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.
Why are generic parameters treated as items?
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 pure generic ones, like fn foo<T: Display + Debug>(a: T)
, in here, a
cannot be both "Display" and "Debug", it needs to go through a level:
arg: [
{
name: "",
generics: [
{
name: "Display"
generics: []
},
{
name: "Debug"
generics: []
}
]
}
]
So in here, the argument with name ""
is a "pure" generic, hence creating a new ItemType
for it.
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.
But value parameters like a: T
don't have item types (at least from looking at the ItemType
enum definition), so how are they represented?
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.
Just with an empty name. If they are still present, might be interesting to remove them since they're useless for the search index.
Oh, sorry, I just saw this ping. Do you still need me to review? |
If you have time, it'd very appreciated, otherwise I'll try to help @camelid finish it. |
It sounds like Camelid understands what's going on better than me, I'll leave them assigned. |
☔ The latest upstream changes (presumably #89430) made this pull request unmergeable. Please resolve the merge conflicts. |
adae003
to
81b333b
Compare
☔ The latest upstream changes (presumably #90337) made this pull request unmergeable. Please resolve the merge conflicts. |
81b333b
to
a924745
Compare
@notriddle Could you take another look on the rust changes please? :) |
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.
Other than the naming thing, I really have only one thing to ask. The code changes, in substance, look reasonable to me.
Can you write some test cases for the JavaScript changes?
src/librustdoc/html/render/cache.rs
Outdated
@@ -301,6 +326,7 @@ crate fn get_real_types<'tcx>( | |||
} | |||
_ => false, | |||
}) { | |||
let mut gens = Vec::new(); |
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 isn't a very useful name. Maybe it can instead be something like ty_generics
?
In particular, it doesn't look like there's any rustdoc test cases for |
a924745
to
87f4894
Compare
I added the test you suggested @notriddle (in |
This comment has been minimized.
This comment has been minimized.
87f4894
to
355e6ed
Compare
@bors: r=notriddle,camelid,jyn514 |
📌 Commit 355e6ed has been approved by |
☀️ Test successful - checks-actions |
Finished benchmarking commit (22f1ad7): comparison url. Summary: This benchmark run did not return any relevant changes. If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf. @rustbot label: -perf-regression |
The generics were not added to the search index as they should, instead they were added as arguments. I used this opportunity to allow generics to have generics themselves (will come in very handy for my current rewrite of the search engine!).
r? @jyn514