Skip to content
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

Merged
merged 4 commits into from
Nov 18, 2021

Conversation

camelid
Copy link
Member

@camelid camelid commented Nov 10, 2021

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

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.
@camelid camelid added C-cleanup Category: PRs that clean code up or issues documenting cleanup. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. labels Nov 10, 2021
@rust-highfive
Copy link
Collaborator

r? @CraftSpider

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 10, 2021
@camelid
Copy link
Member Author

camelid commented Nov 10, 2021

r? @GuillaumeGomez

@camelid
Copy link
Member Author

camelid commented Nov 10, 2021

Probably best to review commit-by-commit.

@rust-log-analyzer

This comment has been minimized.

@camelid
Copy link
Member Author

camelid commented Nov 10, 2021

Hmm, I broke rustdoc somehow...

Looks like 41479e1d106460015f639e3b041fd5e6dde12e95 caused the failure.

@camelid
Copy link
Member Author

camelid commented Nov 10, 2021

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 clean_fn_decl_with_args" commit message.

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.
Copy link
Member

@jyn514 jyn514 left a 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.

@jyn514 jyn514 changed the title Replace where-bounded Clean impl with simple function rustdoc: Replace where-bounded Clean impl with simple function Nov 10, 2021
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.
@camelid
Copy link
Member Author

camelid commented Nov 10, 2021

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.

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!
Copy link
Member Author

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.

@GuillaumeGomez
Copy link
Member

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.

@camelid
Copy link
Member Author

camelid commented Nov 10, 2021

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.

@GuillaumeGomez
Copy link
Member

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.

@camelid
Copy link
Member Author

camelid commented Nov 10, 2021

Followup: I opened #90778 to track encapsulating the ordering requirement in a helper function in a future PR.

@jyn514
Copy link
Member

jyn514 commented Nov 18, 2021

@bors r+

@bors
Copy link
Contributor

bors commented Nov 18, 2021

📌 Commit c20ee3e has been approved by jyn514

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 18, 2021
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Nov 18, 2021
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`
bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 18, 2021
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
@camelid camelid assigned jyn514 and unassigned GuillaumeGomez Nov 18, 2021
@bors bors merged commit 47c1bd1 into rust-lang:master Nov 18, 2021
@rustbot rustbot added this to the 1.58.0 milestone Nov 18, 2021
@camelid camelid deleted the rm-tuple-impls-1 branch November 19, 2021 02:14
@pnkfelix
Copy link
Member

pnkfelix commented Nov 23, 2021

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?

@pnkfelix
Copy link
Member

@rustbot label: +perf-regression

@rustbot rustbot added the perf-regression Performance regression. label Nov 23, 2021
@camelid
Copy link
Member Author

camelid commented Nov 23, 2021

It seems to me like the extra work injected by PR #90750 may be unavoidable; but was it expected to be significant?

What extra work? This PR is just a refactoring that makes the work more explicit.

@camelid
Copy link
Member Author

camelid commented Nov 23, 2021

Sometimes changes to rustc impact only rustdoc, so one of the rustc changes could be at fault.

@camelid
Copy link
Member Author

camelid commented Dec 3, 2021

@pnkfelix Following up: as I said, this PR doesn't add any extra work, so it's unlikely that this caused the regression.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-cleanup Category: PRs that clean code up or issues documenting cleanup. perf-regression Performance regression. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants