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

Refactor auto trait handling in librustdoc to be accessible from librustc. #49711

Merged
merged 10 commits into from
May 9, 2018

Conversation

ibabushkin
Copy link
Contributor

These commits transfer some of the functionality introduced in #47833 to librustc with the intention of making the tools to work with auto traits accessible to third-party code, for example rust-semverver.

Some rough edges remain, and I'm certain some of the FIXMEs introduced will need some discussion, most notably the fairly ugly overall approach to pull out the core logic into librustc, which was previously fairly tightly coupled with various bits and bobs from librustdoc.

cc @Aaron1011

@petrochenkov
Copy link
Contributor

Hmm, r? @nikomatsakis perhaps?

@GuillaumeGomez
Copy link
Member

👍

@pietroalbini pietroalbini added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 6, 2018
Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few nits, but the big one is a comment explaining the purpose of this function -- it's hard to review without that.

trait_did: DefId,
generics: &ty::Generics,
auto_trait_callback: F)
-> AutoTraitResult<A>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: can we rustfmt this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do!

}

pub struct AutoTraitFinder<'a, 'tcx: 'a> {
pub tcx: &'a TyCtxt<'a, 'tcx, 'tcx>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this public?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this is a leftover from a previous iteration. Good catch.

generics: &ty::Generics,
auto_trait_callback: F)
-> AutoTraitResult<A>
where F: for<'b, 'cx, 'cx2> Fn(&InferCtxt<'b, 'cx, 'cx2>, AutoTraitInfo<'cx2>) -> A
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: using impl trait and '_, this can be:

auto_trait_callback: impl for<'infcx> Fn(&InferCtxt<'_, 'tcx, 'infcx>, AutoTraitInfo<'infcx>) -> A

}

impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
pub fn find_auto_trait_generics<A, F>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is hard to review without understanding what it does...can you write a comment explaining the purpose of this function? Thanks! <3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. To be honest, I am also quite unhappy with the actual implementation in this spot -- it is quite awkward (and hence awkward to describe). The idea is basically to offload some of the computation to the auto_trait_callback (because it, for example, requires some types outside rustc) after the main work the function's equivalent in librustdoc performed without this changeset is done.

@TimNN
Copy link
Contributor

TimNN commented Apr 6, 2018

Your PR failed on Travis. Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
Resolving deltas: 100% (612539/612539), completed with 4866 local objects.
---
[00:00:51] configure: rust.quiet-tests     := True
---
[00:04:48] tidy error: /checkout/src/librustc/traits/auto_trait.rs:76: line longer than 100 chars
[00:04:49]
[00:04:49]
[00:04:49] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/tidy" "/checkout/src" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "--no-vendor" "--quiet"
---
[00:04:49] make: *** [tidy] Error 1
[00:04:49] Makefile:79: recipe for target 'tidy' failed

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN.

@ibabushkin ibabushkin force-pushed the auto_trait_refactor branch from a189e95 to 6d11fe7 Compare April 6, 2018 22:40
@ibabushkin
Copy link
Contributor Author

I think the new comment in the file somewhat goes in the right direction, but to be honest, I find it hard making it more precise.

@topecongiro
Copy link
Contributor

@ibabushkin Looks like you may have used an older version of rustfmt. Would you mind reformatting the file with the latest version? FWIW rustup is the easiest way to install it.

@rust-highfive
Copy link
Collaborator

Your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
Resolving deltas: 100% (612921/612921), completed with 4877 local objects.
---
[00:00:47] configure: rust.quiet-tests     := True
---
[00:05:03] tidy error: /checkout/src/librustc/traits/auto_trait.rs:76: line longer than 100 chars
[00:05:04] some tidy checks failed
[00:05:04]
[00:05:04]
[00:05:04] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/tidy" "/checkout/src" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "--no-vendor" "--quiet"
[00:05:04] expected success, got: exit code: 1
[00:05:04]
[00:05:04]
[00:05:04] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test src/tools/tidy
[00:05:04] Build completed unsuccessfully in 0:02:01
[00:05:04] make: *** [tidy] Error 1
[00:05:04] Makefile:79: recipe for target 'tidy' failed
---
$ ls -lat $HOME/Library/Logs/DiagnosticReports/
ls: cannot access /home/travis/Library/Logs/DiagnosticReports/: No such file or directory
travis_time:end:01a9d426:start=1523527631091517032,finish=1523527631097636959,duration=6119927
travis_fold:end:after_failure.2
travis_fold:start:after_failure.3
travis_time:start:08a6e160
$ find $HOME/Library/Logs/DiagnosticReports -type f -name '*.crash' -not -name '*.stage2-*.crash' -not -name 'com.apple.CoreSimulator.CoreSimulatorService-*.crash' -exec printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" {} \; -exec head -750 {} \; -exec echo travis_fold":"end:crashlog \; || true
find: `/home/travis/Library/Logs/DiagnosticReports': No such file or directory
travis_time:end:08a6e160:start=1523527631103495261,finish=1523527631110054064,duration=6558803
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:0fd884f9
$ dmesg | grep -i kill
[   10.907031] init: failsafe main process (1096) killed by TERM signal

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@ibabushkin
Copy link
Contributor Author

ibabushkin commented Apr 12, 2018

@topecongiro That's what happens when I run rustfmt (even in a newer version) on then code. Tidy checks fail because a line is too long (which I edited by hand before).

@topecongiro
Copy link
Contributor

@ibabushkin Thanks, that is interesting...would you mind checking the version of rustfmt? It should be rustfmt 0.4.1-nightly (e784712 2018-04-09) or 0.3.8-nightly (346238f 2018-02-04), depending on the toolchain you use.

@ibabushkin
Copy link
Contributor Author

@topecongiro Surprisingly, a rustfmt installed/updated via rustup component add rustfmt-preview --toolchain nightly, as per the instructions, outputs the following:

$ rustfmt --version
0.8.4 ()

However, I suggest we move this discussion somewhere else, as this somewhat derails the discussion in this issue :)

@topecongiro
Copy link
Contributor

@ibabushkin Ok, looks like you already have rustfmt which has been installed via cargo install rustfmt. Please remove ~/.cargo/bin/rustfmt and ~/.cargo/bin/cargo-fmt, then run the rustup command. If this does not work, would you mind opening an issue in rustfmt repo? I could help you there.

My appologies for derailing the discussion in this issue.

@ibabushkin ibabushkin force-pushed the auto_trait_refactor branch from 6e8227d to 0c735a6 Compare April 12, 2018 18:05
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
pub enum RegionTarget<'tcx> {
Region(Region<'tcx>),
RegionVid(RegionVid),
Copy link
Contributor

@nikomatsakis nikomatsakis Apr 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this exist, given that Region has a case for inference variables?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following enum is defined in librustdoc, and used in the code I moved over:

#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
enum RegionTarget<'tcx> {
    Region(Region<'tcx>),
    RegionVid(RegionVid)
}

I did not find any explanation or reasoning there, so I duplicated the enumeration (as stated in the TODO comment). I suppose we could eliminate this type altogether given what you said about Region, but that would require further testing. Maybe @Aaron1011 can tell us more about the bits of code here that use this type.

@nikomatsakis
Copy link
Contributor

So I have sort of a meta question:

Is the goal here to just kind of "rubber stamp" moving some code out of rustdoc into rustc, or to really design a nice API?

If the latter, obviously, I'd want to think over more carefully what's going on here. If the former, we can add some comments like "stay away from this code" and land with lighter review, I imagine.

Overall, I do want to add more stable APIs for working with traits that consumers like rustdoc etc can use. This particular API is going in precisely the opposite direction of what I had in mind, though, in terms of exposing internal concepts like vtable that I'd like to remove. (It's kind of interesting, though, since many of the concepts I'd like to remove are basically those that rustdoc wants -- i.e., those that are tightly tied to the source code structure.)

@ibabushkin
Copy link
Contributor Author

Well, the point you bring up is an important one -- I initially was working on adding support for auto traits to rust-semverver, and was pointed at this code that was supposedly trivial to move. I was quickly convinced that moving it over in a clean fashion would require significantly more design and implementation work. So yes, I am aware this module is terribly designed, but given that the original code was fairly complex and deeply entangled with rustdoc's internals, I still went with this route.

To conclude: I agree that a properly designed refactor for this machinery would be much nicer, but that would come at a cost of a time penalty for what I was working on, and require some work (I'd love to help, but I sadly am somewhat short on time).

@nikomatsakis
Copy link
Contributor

OK, I skimmed in a bit more depth. I think I see now what this code is trying to do -- it seems like it's trying to find, if there is an auto trait impl, what the transitive conditions are on this impl and report those back to the user? That's interesting. Is there an example of the resulting output?

(Also, I was wrong to say it exposes VtableImpl, which is good.)

@ibabushkin
Copy link
Contributor Author

ibabushkin commented Apr 12, 2018

As far as I am aware, auto trait instances are being generated in rustdoc output. I've not seen examples of that however (and couldn't find any right now). The original PR shows the functionality in a quite detailed way though.

There is also a rust-semverver branch which uses some of the functionality in a rudimentary way.

Regarding the inner working of the code: Yes, your description pretty much coincides with my mental model of it.

@bors
Copy link
Contributor

bors commented Apr 14, 2018

☔ The latest upstream changes (presumably #49939) made this pull request unmergeable. Please resolve the merge conflicts.

@ibabushkin ibabushkin force-pushed the auto_trait_refactor branch from 0c735a6 to c35f334 Compare April 15, 2018 15:07
@ibabushkin
Copy link
Contributor Author

Do we have a definite conclusion on this? Any further changes needed? A proper, clean rewrite from scratch of the mechanics underneath?

@Aaron1011
Copy link
Member

Well, the point you bring up is an important one -- I initially was working on adding support for auto traits to rust-semverver, and was pointed at this code that was supposedly trivial to move. I was quickly convinced that moving it over in a clean fashion would require significantly more design and implementation work.

@ibabushkin: I'm sorry about that - I should have taken a closer look at what work would be required before telling you that.

I'd be happy to help out with this in any way I can, especially if parts of my code are unclear or poorly written.

@ibabushkin
Copy link
Contributor Author

ibabushkin commented Apr 22, 2018 via email

@nikomatsakis
Copy link
Contributor

OK. So, I'm of mixed minds here. First off, a question:

What does this code do for a type like this:

struct Foo<T: Iterator> {
  data: <T as Iterator>::Item
}

i.e., what where clauses does it give back?

In general, the "always correct" answer for send impls is actually way simpler than what this code does. The correct answer is just to enumerate the field types. So for Foo, the right impl is:

impl<T: Iterator> Send for Foo
  where <T as Iterator>::Item: Send
{ }

This is possible only because Send is an autotrait, and therefore treated "coinductively" -- in short, cycles are ok, as long as those cycles consist only of other autotraits. However, the transformation that this code does produces a more "minimal" result, better suited for display to end users for sure.

I don't really feel like I have the bandwidth to think carefully about whether this API is the kind we would like to support longer term. I suspect something like it would be fine, but we'd want to make changes.

I think I'm inclined therefore to r+ this, since it's basically just moving existing code around it, but with the warning that as the work on chalk etc integration proceeds we may want to make radical changes to the API.

@nikomatsakis
Copy link
Contributor

@ibabushkin

I think I'm inclined therefore to r+ this, since it's basically just moving existing code around it, but with the warning that as the work on chalk etc integration proceeds we may want to make radical changes to the API.

I specifically wanted to know how you felt about that =)

@ibabushkin
Copy link
Contributor Author

I'm in the same boat there -- the API as-is, after the move, certainly isn't pretty. Given that only two consumers of it are to be expected in the foreseeable future, and that I'd like to get back to this at some point in the future, I am totally fine with it being a temporary state of things.

@ibabushkin
Copy link
Contributor Author

Am I mistaken or are the build failures unrelated to the changes?

@nikomatsakis
Copy link
Contributor

@ibabushkin you'd think so... but it seems repeatable. =)

@nikomatsakis
Copy link
Contributor

Huh, re-reading the code I can't really see how those failures could come about. It feels like they have to be spurious.

@nikomatsakis
Copy link
Contributor

@bors retry

@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 May 1, 2018
@nikomatsakis
Copy link
Contributor

@bors r- -- well, let me check

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels May 1, 2018
@TimNN TimNN added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 8, 2018
@TimNN
Copy link
Contributor

TimNN commented May 8, 2018

@bors r- -- well, let me check

Ping from triage, @nikomatsakis, any updates?

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 8, 2018
@TimNN TimNN added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 8, 2018
@nikomatsakis
Copy link
Contributor

Argh I forgot I had left this on that note. No, I've no idea how this could be anything but spurious. Shall we give it another try?

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented May 9, 2018

📌 Commit 8901392 has been approved by nikomatsakis

@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 May 9, 2018
@bors
Copy link
Contributor

bors commented May 9, 2018

⌛ Testing commit 8901392 with merge 4725417...

bors added a commit that referenced this pull request May 9, 2018
Refactor auto trait handling in librustdoc to be accessible from librustc.

These commits transfer some of the functionality introduced in #47833 to librustc with the intention of making the tools to work with auto traits accessible to third-party code, for example [rust-semverver](https://github.com/rust-lang-nursery/rust-semverver).

Some rough edges remain, and I'm certain some of the FIXMEs introduced will need some discussion, most notably the fairly ugly overall approach to pull out the core logic into librustc, which was previously fairly tightly coupled with various bits and bobs from librustdoc.

cc @Aaron1011
@bors
Copy link
Contributor

bors commented May 9, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 4725417 to master...

@bors bors merged commit 8901392 into rust-lang:master May 9, 2018
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 1, 2024
…mpl-synth, r=<try>

rustdoc: heavily simplify the synthesis of auto trait impls

`gd --numstat HEAD~2 HEAD src/librustdoc/clean/auto_trait.rs`
**+315 -705** 🟩🟥🟥🟥⬛

---

As outlined in issue rust-lang#113015, there are currently 3[^1] large separate routines that “clean” `rustc_middle::ty` data types related to generics & predicates to rustdoc data types. Every single one has their own kinds of bugs. While I've patched a lot of bugs in each of the routines in the past, it's about time to unify them. This PR is only the first in a series. It completely *yanks* the custom “bounds cleaning” of mod `auto_trait` and reuses the routines found in mod `simplify`. As mentioned, `simplify` is also flawed but still it's more complete than `auto_trait`'s routines. See also my review comment over at `tests/rustdoc/synthetic_auto/bounds.rs`.

This is preparatory work for rewriting “bounds cleaning” in follow-up PRs in order to finally [fix] rust-lang#113015.

Apart from that, I've eliminated all potential sources of *unstable rendering output*.
See also rust-lang#119597. I'm pretty sure this fixes rust-lang#119597.

This PR does not attempt to fix [any other issues related to synthetic auto trait impls](https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+label%3AA-synthetic-impls%20label%3AA-auto-traits).
However, it's definitely meant to be a *stepping stone* by making `auto_trait` more contributor friendly.

---

* Replace `FxHash{Map,Set}` with `FxIndex{Map,Set}` to guarantee a stable / more predictable iteration order
  * Or as a perf opt, `UnordSet` (a thin wrapper around `FxHashSet`) in cases where we never iterate over the set.
* Remove the types `RegionTarget` and `RegionDeps` from `librustdoc`. They were duplicates of the identical types found in `rustc`. Just import them from `rustc`. For some reason, they were duplicated when splitting `auto_trait` in two in rust-lang#49711.
* Get rid of the useless “type namespace” `AutoTraitFinder` in `librustdoc`
  * The struct only held a `DocContext`, it was over-engineered
  * Turn the associated functions into free ones
    * Eliminates rightward drift; increases legibility
  * `rustc` also contains a useless `AutoTraitFinder` struct but I plan on removing that in a follow-up PR
* Rename a bunch of methods to be way more descriptive
* Eliminate `use super::*;`
  * Lead to `clean/mod.rs` accumulating a lot of unnecessary imports and therefore
  * made `auto_traits` less modular

I plan on adding extensive documentation to `librustdoc`'s `auto_trait` in follow-up PRs.
I don't want to do that in this PR because further refactoring & bug fix PRs may alter the overall structure of `librustdoc`'s & `rustc`'s `auto_trait` modules to a great degree. I'm slowly digging into the dark details of `rustc`'s `auto_trait` module again and once I have the full picture I will be able to provide proper docs.

---

While this PR does indeed touch `rustc`'s `auto_trait` — mostly tiny refactorings — I argue this PR doesn't need any compiler reviewers next to rustdoc ones since that module falls under the purview of rustdoc — it used to be part of `librustdoc` after all (rust-lang#49711).

Sorry for not having split this into more commits. If you'd like me to I can try to retroactively separate it into more atomic commits. However, I don't know if that would actually make reviewing this PR easier.

r? `@GuillaumeGomez`

[^1]: Or even 4 depending on the way you're counting.
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 2, 2024
…mpl-synth, r=GuillaumeGomez

rustdoc: heavily simplify the synthesis of auto trait impls

`gd --numstat HEAD~2 HEAD src/librustdoc/clean/auto_trait.rs`
**+315 -705** 🟩🟥🟥🟥⬛

---

As outlined in issue rust-lang#113015, there are currently 3[^1] large separate routines that “clean” `rustc_middle::ty` data types related to generics & predicates to rustdoc data types. Every single one has their own kinds of bugs. While I've patched a lot of bugs in each of the routines in the past, it's about time to unify them. This PR is only the first in a series. It completely **yanks** the custom “bounds cleaning” of mod `auto_trait` and reuses the routines found in mod `simplify`. As alluded to, `simplify` is also flawed but it's still more complete than `auto_trait`'s routines. [See also my review comment over at `tests/rustdoc/synthetic_auto/bounds.rs`](rust-lang#123340 (comment)).

This is preparatory work for rewriting “bounds cleaning” from scratch in follow-up PRs in order to finally [fix] rust-lang#113015.

Apart from that, I've eliminated all potential sources of *instability* in the rendered output.
See also rust-lang#119597. I'm pretty sure this fixes rust-lang#119597.

This PR does not attempt to fix [any other issues related to synthetic auto trait impls](https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+label%3AA-synthetic-impls%20label%3AA-auto-traits).
However, it's definitely meant to be a *stepping stone* by making `auto_trait` more contributor-friendly.

---

* Replace `FxHash{Map,Set}` with `FxIndex{Map,Set}` to guarantee a stable iteration order
  * Or as a perf opt, `UnordSet` (a thin wrapper around `FxHashSet`) in cases where we never iterate over the set.
  * Yes, we do make use of `swap_remove` but that shouldn't matter since all the callers are deterministic. It does make the output less “predictable” but it's still better than before. Ofc, I rely on `rustc_infer` being deterministic. I hope that holds.
* Utilizing `clean::simplify` over the custom “bounds cleaning” routines wipes out the last reference to `collect_referenced_late_bound_regions` in rustdoc (`simplify` uses `bound_vars`) which was a source of instability / unpredictability (cc rust-lang#116388)
* Remove the types `RegionTarget` and `RegionDeps` from `librustdoc`. They were duplicates of the identical types found in `rustc`. Just import them from `rustc`. For some reason, they were duplicated when splitting `auto_trait` in two in rust-lang#49711.
* Get rid of the useless “type namespace” `AutoTraitFinder` in `librustdoc`
  * The struct only held a `DocContext`, it was over-engineered
  * Turn the associated functions into free ones
    * Eliminates rightward drift; increases legibility
  * `rustc` also contains a useless `AutoTraitFinder` struct but I plan on removing that in a follow-up PR
* Rename a bunch of methods to be way more descriptive
* Eliminate `use super::*;`
  * Lead to `clean/mod.rs` accumulating a lot of unnecessary imports
  * Made `auto_traits` less modular
* Eliminate a custom `TypeFolder`: We can just use the rustc helper `fold_regions` which does that for us

I plan on adding extensive documentation to `librustdoc`'s `auto_trait` in follow-up PRs.
I don't want to do that in this PR because further refactoring & bug fix PRs may alter the overall structure of `librustdoc`'s & `rustc`'s `auto_trait` modules to a great degree. I'm slowly digging into the dark details of `rustc`'s `auto_trait` module again and once I have the full picture I will be able to provide proper docs.

---

While this PR does indeed touch `rustc`'s `auto_trait` — mostly tiny refactorings — I argue this PR doesn't need any compiler reviewers next to rustdoc ones since that module falls under the purview of rustdoc — it used to be part of `librustdoc` after all (rust-lang#49711).

Sorry for not having split this into more commits. If you'd like me to I can try to split it into more atomic commits retroactively. However, I don't know if that would actually make reviewing easier. I think the best way to review this might just be to place the master version of `auto_trait` on the left of your screen and the patched one on the right, not joking.

r? `@GuillaumeGomez`

[^1]: Or even 4 depending on the way you're counting.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants