-
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: Replace where-bounded Clean impl with simple function #90750
Conversation
This was the only Clean impl I found with `where` bounds. This impl was doubly-confusing: it was implemented on a tuple and it was polymorphic. Combined, this caused a "spooky action at a distance" effect to make the code very confusing.
r? @CraftSpider (rust-highfive has picked a reviewer for you, use r? to override) |
Probably best to review commit-by-commit. |
This comment has been minimized.
This comment has been minimized.
Hmm, I broke rustdoc somehow... Looks like 41479e1d106460015f639e3b041fd5e6dde12e95 caused the failure. |
8b30d1b
to
45f7220
Compare
Ok, I fixed the test failures. Long story short: generics have to be cleaned before arguments. You can read the full saga in the "Remove where bound from |
45f7220
to
86b5975
Compare
Basically, this entails moving the arguments cleaning to the call site. I extracted several local variables because: 1. It makes the code easier to read and understand. 2. If I hadn't, the extra `clean()` calls would have caused complicated tuples to be split across several lines. 3. I couldn't just extract local variables for `args` because then the arguments would be cleaned *before* the generics, while rustdoc expects them to be cleaned *after*. Only extracting `args` caused panics like this: thread 'rustc' panicked at 'assertion failed: cx.impl_trait_bounds.is_empty()', src/librustdoc/clean/utils.rs:462:5 Extracting variables makes the control flow -- and the required order of cleaning -- more explicit.
86b5975
to
c615b11
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.
Hmm, I'm kind of concerned this makes it easier to make mistakes when cleaning function declarations. As you noted, the order is important, and it would be really easy to miss that when adding a new call. I kind of liked the version in the first commit better, with the where
clause - I think if you added a comment there about the ordering it would be better than requiring each caller to know about it.
Otherwise, rustdoc panics with messages like this: thread 'rustc' panicked at 'assertion failed: cx.impl_trait_bounds.is_empty()', src/librustdoc/clean/utils.rs:462:5 This ordering requirement is unrelated to the `clean_fn_decl_with_args` refactoring, but the requirement was uncovered as part of that change. I'm not sure if *all* of these places have the requirement, but I added comments to them just in case.
c5864e2
to
c20ee3e
Compare
We discussed this and came to the conclusion that the "generics before args" ordering requirement was there all along; it is not affected by this PR. So, this change should be all good. At Joshua's suggestion, I added comments to what I believe are the relevant places to reduce the risk of the order accidentally being changed in the future. |
@@ -229,6 +229,7 @@ fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Functi | |||
let asyncness = cx.tcx.asyncness(did); | |||
let predicates = cx.tcx.predicates_of(did); | |||
let (generics, decl) = clean::enter_impl_trait(cx, |cx| { | |||
// NOTE: generics need to be cleaned before the decl! |
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.
As I mentioned in the commit message, some of these places may not have the ordering requirement, but just to be safe I added comments in almost all of them.
The only place I didn't add a comment is the following
clean/inline.rs
446: clean::enter_impl_trait(cx, |cx| (tcx.generics_of(did), predicates).clean(cx)),
since it seemed like a different scenario. Let me know if you think I should add a comment there though.
I agree with @jyn514: it's a bit worrying that the order matters. Would it be possible to create a function where you handle the clean calls in the right order and then call it from the other places? That would make it much less likely to call cleans in the wrong order. |
As I said above, Joshua and I came to the conclusion that the required order is not affected by this PR. I agree that it'd be good to not have this ordering requirement spread across the code, but it should happen in a future PR since it is unrelated. The only reason I stumbled upon the ordering requirement in this PR is that I was trying to extract some local variables to make the code simpler, and I accidentally changed the order of cleaning. (The local variables are now in the correct order.) Like I said, the ordering is not affected by this PR. |
Except that you do call them all "by hand". Even if the order isn't affected by this PR. It's not a blocker for me though, just a preference. |
Followup: I opened #90778 to track encapsulating the ordering requirement in a helper function in a future PR. |
@bors r+ |
📌 Commit c20ee3e has been approved by |
rustdoc: Replace where-bounded Clean impl with simple function This is the first step in removing the Clean impls for tuples. Either way, this significantly simplifies the code since it reduces the amount of "trait magic". (To clarify, I'm referring to impls like `impl Clean for (A, B)`, not Clean impls that work on tuples in the user's program.) cc `@jyn514`
Rollup of 8 pull requests Successful merges: - rust-lang#90386 (Add `-Zassert-incr-state` to assert state of incremental cache) - rust-lang#90438 (Clean up mess for --show-coverage documentation) - rust-lang#90480 (Mention `Vec::remove` in `Vec::swap_remove`'s docs) - rust-lang#90607 (Make slice->str conversion and related functions `const`) - rust-lang#90750 (rustdoc: Replace where-bounded Clean impl with simple function) - rust-lang#90895 (require full validity when determining the discriminant of a value) - rust-lang#90989 (Avoid suggesting literal formatting that turns into member access) - rust-lang#91002 (rustc: Remove `#[rustc_synthetic]`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This PR has been tagged as being the root cause of the performance regression flagged here. It seems to me like the extra work injected by PR #90750 may be unavoidable; but was it expected to be significant? |
@rustbot label: +perf-regression |
What extra work? This PR is just a refactoring that makes the work more explicit. |
Sometimes changes to rustc impact only rustdoc, so one of the rustc changes could be at fault. |
@pnkfelix Following up: as I said, this PR doesn't add any extra work, so it's unlikely that this caused the regression. |
This is the first step in removing the Clean impls for tuples. Either way, this
significantly simplifies the code since it reduces the amount of "trait magic".
(To clarify, I'm referring to impls like
impl Clean for (A, B)
, not Clean implsthat work on tuples in the user's program.)
cc @jyn514