-
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] Improve "in parameters" search and search more generally #59004
Conversation
Some changes occurred in HTML/CSS. |
(rust_highfive has picked a reviewer for you, use r? to override) |
37bcbce
to
6efbcaa
Compare
ping from triage @QuietMisdreavus waiting for your review on this |
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.
Looks good, just a couple small comments. This may clash with #59170 whenever that lands.
src/librustdoc/clean/mod.rs
Outdated
@@ -1694,22 +1737,135 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, | |||
} | |||
} | |||
|
|||
// The point is to replace bounds with types. |
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 write doc comments for the functions you added? For example, this could be something like "Extract the types from a function's parameters and generics" with maybe a note about trait bounds since you've already added the comment 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.
Ah sure.
generics: &Generics, | ||
arg: &Type, | ||
cx: &DocContext<'_, '_, '_>, | ||
) -> FxHashSet<Type> { |
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.
If you use a BTreeSet
instead, it comes pre-sorted - otherwise it comes out in an arbitrary order. I'm not sure if you wanted it to be properly sorted or just deduplicated, though.
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.
Dedup, the order doesn't matter. ;)
src/librustdoc/clean/mod.rs
Outdated
if !adds.is_empty() { | ||
for a in adds.into_iter() { | ||
res.insert(a); | ||
} |
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.
You can replace this loop with res.extend(adds)
, since the sets implement the Extend trait.
☔ The latest upstream changes (presumably #58927) made this pull request unmergeable. Please resolve the merge conflicts. |
6efbcaa
to
befe9ca
Compare
@QuietMisdreavus I applied your comments. |
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.
Excellent, thanks for doing this! This will make the in-doc search much more powerful.
@bors r+ |
📌 Commit befe9ca has been approved by |
…=QuietMisdreavus [rustdoc] Improve "in parameters" search and search more generally Fixes rust-lang#58230. r? @QuietMisdreavus
Rollup of 7 pull requests Successful merges: - #59004 ([rustdoc] Improve "in parameters" search and search more generally) - #59026 (Fix moving text in search tabs headers) - #59197 (Exclude old book redirect stubs from search engines) - #59330 (Improve the documentation for std::convert (From, Into, AsRef and AsMut)) - #59424 (Fix code block display in portability element in dark theme) - #59427 (Link to PhantomData in NonNull documentation) - #59432 (Improve some compiletest documentation) Failed merges: r? @ghost
Rollup of 7 pull requests Successful merges: - #59004 ([rustdoc] Improve "in parameters" search and search more generally) - #59026 (Fix moving text in search tabs headers) - #59197 (Exclude old book redirect stubs from search engines) - #59330 (Improve the documentation for std::convert (From, Into, AsRef and AsMut)) - #59424 (Fix code block display in portability element in dark theme) - #59427 (Link to PhantomData in NonNull documentation) - #59432 (Improve some compiletest documentation) Failed merges: r? @ghost
@GuillaumeGomez @QuietMisdreavus Please do not merge PRs that change the compiler (in this case, typeck) without a review from @rust-lang/compiler. |
pub fn get_type(&self, cx: &DocContext<'_>) -> Option<Type> { | ||
match *self { | ||
GenericParamDefKind::Type { did, .. } => { | ||
rustc_typeck::checked_type_of(cx.tcx, did, false).map(|t| t.clean(cx)) |
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.
You didn't have to do any of the typeck changes, the default is already there:
GenericParamDefKind::Type { ref default, .. } => default.clone(),
@@ -1707,12 +1750,122 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, | |||
} | |||
} | |||
|
|||
/// The point of this function is to replace bounds with types. | |||
/// | |||
/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return |
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.
Option<T>
is not a bound... how does this make sense?
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 point is to replace T by the type/trait if any. For example:
fn<T>(x: T)
where T: Display
In there, T
should be replaced with Display
. In here, it's all about the rustdoc search, not about finding exact types. If we have two types with the same name, we don't care, we just remove one name from the list and that's 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.
Sure, but you can get the desired effect without using confusing terminology.
So what you want is "types of arguments" and "bounds on parameters in those arguments"?
Why bother with that complication tho? Why not just record all paths in a signature, be it args/return, or bounds/where clauses? Getting all that is less work and much easier to reason about.
|
||
pub fn is_full_generic(&self) -> bool { | ||
match *self { | ||
Type::Generic(_) => true, |
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 should be called Param
or GenericParam
.
@@ -2410,6 +2581,13 @@ impl Type { | |||
_ => None | |||
} | |||
} | |||
|
|||
pub fn is_full_generic(&self) -> bool { |
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 should be called is_param
or is_generic_param
.
/// wrapped types in here). | ||
fn get_real_types( | ||
generics: &Generics, | ||
arg: &Type, |
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 should probably be called ty
?
continue | ||
} | ||
if let Some(ty) = x.get_type(cx) { | ||
let adds = get_real_types(generics, &ty, cx); |
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 is unguarded recursion, can easily become infinite, probably the cause of #59502.
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 was indeed.
}) { | ||
for bound in bound.get_bounds().unwrap_or_else(|| &[]) { | ||
if let Some(ty) = bound.get_trait_type() { | ||
let adds = get_real_types(generics, &ty, cx); |
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.
Same here, unguarded recursion.
if let Some(gens) = arg.generics() { | ||
for gen in gens.iter() { | ||
if gen.is_full_generic() { | ||
let adds = get_real_types(generics, gen, cx); |
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.
Same here, unguarded recursion.
/// Return the full list of types when bounds have been resolved. | ||
/// | ||
/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return | ||
/// `[u32, Display, Option]`. |
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.
Same here, Option<A>
is not a bound.
} | ||
} | ||
} | ||
if let Some(bound) = generics.params.iter().find(|g| { |
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.
bound
here seems to be a misnomer, this is a param
.
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.
IMO this should be above the where
handling above, doing it this way is far more confusing.
} | ||
} | ||
if let Some(bound) = generics.params.iter().find(|g| { | ||
g.is_type() && g.name == arg_s |
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 is this by name instead of by DefId
?
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 don't care about DefId
in here, I only care about names. Don't forget it's to generate rustdoc search array. I'm not looking for a given type but for a given type 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.
You're searching for a type parameter though, not a struct/enum.
And you implemented the other search for type parameters by DefId
, so it's inconsistent.
let adds = get_real_types(generics, &ty, cx); | ||
if !adds.is_empty() { | ||
res.extend(adds); | ||
} else if !ty.is_full_generic() { |
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.
ty
is a trait, not a type, so is_full_generic()
should never be the case.
/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return | ||
/// `[Display, Option]` (we just returns the list of the types, we don't care about the | ||
/// wrapped types in here). | ||
fn get_real_types( |
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 name should be find_concrete_types
, or, even better, find_type_paths
.
res.insert(arg.clone()); | ||
if let Some(gens) = arg.generics() { | ||
for gen in gens.iter() { | ||
if gen.is_full_generic() { |
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.
So this means that get_real_types(Option<T>)
will look at T
's bounds... why?
if !adds.is_empty() { | ||
res.extend(adds); | ||
} else if !ty.is_full_generic() { | ||
res.insert(ty.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.
ty
is a trait, so your returned set contains both types and traits?
@@ -1084,9 +1084,10 @@ impl GenericBound { | |||
|
|||
fn get_trait_type(&self) -> Option<Type> { |
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 existence of a trait path as a value of Type
was a mistake, IMO.
If you move DefId
into Path
, you can replace trait_: Type
with path: Path
in:
rust/src/librustdoc/clean/mod.rs
Lines 2428 to 2431 in 237bf32
pub struct PolyTrait { | |
pub trait_: Type, | |
pub generic_params: Vec<GenericParamDef>, | |
} |
and this (and other places) with
PolyTrait { path, generic_params: late_bounds }
:rust/src/librustdoc/clean/mod.rs
Lines 1196 to 1201 in 237bf32
trait_: ResolvedPath { | |
path, | |
param_names: None, | |
did: trait_ref.def_id, | |
is_generic: false, | |
}, |
Wait, Path
has a Def
which contains a DefId
:
rust/src/librustdoc/clean/mod.rs
Lines 3421 to 3425 in 237bf32
pub struct Path { | |
pub global: bool, | |
pub def: Def, | |
pub segments: Vec<PathSegment>, | |
} |
So Type::ResolvedPath
's DefId
is just redundant?!
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, you'd need this to take a Def
, too (which can replace trait_did
):
rust/src/librustdoc/clean/mod.rs
Lines 1153 to 1154 in 237bf32
fn external_path(cx: &DocContext<'_>, name: &str, trait_did: Option<DefId>, has_self: bool, | |
bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> Path { |
Opened #59789. |
Revert two unapproved changes to rustc_typeck. There was a breakdown in process (#59004 (comment), #58894 (comment)) and two changes were made to `rustc_typeck`'s "collect" queries, for rustdoc, that were neither needed *nor* correct. I'm reverting them here, and will fix up rustdoc *somehow*, if necessary. cc @rust-lang/compiler How do we ensure this doesn't happen again? r? @nikomatsakis or @oli-obk
Revert two unapproved changes to rustc_typeck. There was a breakdown in process (rust-lang#59004 (comment), rust-lang#58894 (comment)) and two changes were made to `rustc_typeck`'s "collect" queries, for rustdoc, that were neither needed *nor* correct. I'm reverting them here, and will fix up rustdoc *somehow*, if necessary. cc @rust-lang/compiler How do we ensure this doesn't happen again? r? @nikomatsakis or @oli-obk
Fixes #58230.
r? @QuietMisdreavus