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

rustc: keep upvars tupled in {Closure,Generator}Substs. #69968

Merged
merged 3 commits into from
Mar 23, 2020

Conversation

eddyb
Copy link
Member

@eddyb eddyb commented Mar 13, 2020

Previously, each closure/generator capture's (aka "upvar") type was tracked as one "synthetic" type parameter in the closure/generator substs, and figuring out where the parent fn's generics end and the synthetics start involved slicing at tcx.generics_of(def_id).parent_count.

Needing to query generics_of limited @davidtwco (who wants to compute some TypeFlags differently for parent generics vs upvars, and TyCtxt is not available there), which is how I got started on this, but it's also possible that the generics_of queries are slowing down {Closure,Generator}Substs methods.

To give an example, for a foo::<T, U>::{closure#0} with captures x: X and y: Y, substs are:

  • before this PR: [T, U, /*kind*/, /*signature*/, X, Y]
  • after this PR: [T, U, /*kind*/, /*signature*/, (X, Y)]

You can see that, with this PR, no matter how many captures, the last 3 entries in the substs (or 5 for a generator) are always the "synthetic" ones, with the last one being the tuple of capture types.

r? @nikomatsakis cc @Zoxc

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 13, 2020
@eddyb
Copy link
Member Author

eddyb commented Mar 13, 2020

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented Mar 13, 2020

⌛ Trying commit da30907 with merge 6429062...

bors added a commit that referenced this pull request Mar 13, 2020
rustc: keep upvars tupled in {Closure,Generator}Substs.

Previously, each closure/generator capture's (aka "upvar") type was tracked as one "synthetic" type parameter in the closure/generator substs, and figuring out where the parent `fn`'s generics end and the synthetics start involved slicing at `tcx.generics_of(def_id).parent_count`.

Needing to query `generics_of` limited @davidtwco (who wants to compute some `TypeFlags` differently for parent generics vs upvars, and `TyCtxt` is not available there), which is how I got started on this, but it's also possible that the `generics_of` queries are slowing down `{Closure,Generator}Substs` methods.

To give an example, for a `foo::<T, U>::{closure#0}` with captures `x: X` and `y: Y`, substs are:
* before this PR: `[T, U, /*kind*/, /*signature*/, X, Y]`
* after this PR: `[T, U, /*kind*/, /*signature*/, (X, Y)]`

You can see that, with this PR, no matter how many captures, the last 3 entries in the substs (or 5 for a generator) are always the "synthetic" ones, with the last one being the tuple of capture types.

r? @nikomatsakis cc @Zoxc
= note: consider adding a `#![type_length_limit="26214380"]` attribute to your crate
= note: consider adding a `#![type_length_limit="30408681"]` attribute to your crate
Copy link
Member Author

Choose a reason for hiding this comment

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

@rust-lang/compiler This is a bit silly, can we remove type_length_limit?
Does it do anything for us nowadays? Other than slow down compilation.

Copy link
Contributor

Choose a reason for hiding this comment

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

I assume by "remove" you mean "make it do nothing"?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, right, it's stable. The other thing we can do is count only unique types, which should make cases like these far less drastic presumably.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused -- why would it not do something for us? There are various cases where the size of types and amount of computational work can balloon without generating large stacks (also true: in the SLG solver Chalk at least, we don't even have a concept of overflow apart from type-size limits, though depending on what precise solver design we wind up with, we could keep something like overflow, but it's not a great concept because it makes results for a given query dependent on context instead of independent).

Copy link
Contributor

Choose a reason for hiding this comment

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

That said, this is an orthogonal place where we could apply type-limits, instead of applying them at type creation time or whatever.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it was added originally to not generate LLVM type names that were too long or something, which is a silly problem IMO.

At the very least we should switch to a DAG approach (i.e. don't count duplicates), I assume Chalk at least is similarly proportional in unique types, not total occurrences.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure what duplicates exactly means? Oh, I guess like Foo<(A, A)> only counts A once? Chalk is currently just counting the total number of types I think. I'd have to think if the DAG version "suffices". I'm not sure, why is that much better? I'm just a bit confused about why you care about this I guess. Is it something that you've seen arise frequently?

Copy link
Member Author

Choose a reason for hiding this comment

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

Is it something that you've seen arise frequently?

It's almost guaranteed to arise with closures in generic functions, the generic shows up once in the parent Substs and then in one or more capture types.

That multiplies during monomorphization, and can blow out of proportions, despite nothing actually operating proportionally to the multiple occurrences.

Remember #54540? 🤣

@bors
Copy link
Contributor

bors commented Mar 13, 2020

💥 Test timed out

@eddyb
Copy link
Member Author

eddyb commented Mar 13, 2020

@bors try

@bors
Copy link
Contributor

bors commented Mar 13, 2020

⌛ Trying commit da30907 with merge 26cab41b863fc625c0d81f771e063c685680f335...

src/librustc/ty/sty.rs Outdated Show resolved Hide resolved
src/librustc/ty/sty.rs Outdated Show resolved Hide resolved
src/librustc/ty/sty.rs Outdated Show resolved Hide resolved
src/librustc/ty/sty.rs Outdated Show resolved Hide resolved
src/librustc/ty/sty.rs Outdated Show resolved Hide resolved
fn split(self, def_id: DefId, tcx: TyCtxt<'_>) -> SplitClosureSubsts<'tcx> {
let generics = tcx.generics_of(def_id);
let parent_len = generics.parent_count;
fn split(self) -> SplitClosureSubsts<'tcx> {
Copy link
Member

Choose a reason for hiding this comment

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

I've already mentioned this to @eddyb via PM, but it could be useful for SplitClosureSubsts to contain a parent_substs: &'tcx [GenericArg<'tcx>] field - that way any callers that need to access the specific components of the closure substs (and use SplitClosureSubsts to do so) can also access the parent substs without having to reproduce some of this logic.

Copy link
Member Author

Choose a reason for hiding this comment

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

You can add this in your PR, FWIW, but if @nikomatsakis doesn't mind I can do it in this one too.

@bors
Copy link
Contributor

bors commented Mar 13, 2020

💥 Test timed out

@eddyb
Copy link
Member Author

eddyb commented Mar 13, 2020

@bors try (CI outage should be fixed now)

@bors
Copy link
Contributor

bors commented Mar 13, 2020

⌛ Trying commit da30907 with merge f7b1e868f01ad49dcc05daad583793f5c413bc9a...

@bors
Copy link
Contributor

bors commented Mar 13, 2020

☀️ Try build successful - checks-azure
Build commit: f7b1e868f01ad49dcc05daad583793f5c413bc9a (f7b1e868f01ad49dcc05daad583793f5c413bc9a)

@rust-timer
Copy link
Collaborator

Queued f7b1e868f01ad49dcc05daad583793f5c413bc9a with parent 54b7d21, future comparison URL.

@eddyb

This comment has been minimized.

@davidtwco davidtwco mentioned this pull request Mar 14, 2020
@eddyb eddyb force-pushed the tupled-closure-captures branch 2 times, most recently from ca8521b to cb6cdc0 Compare March 15, 2020 15:44
@eddyb

This comment has been minimized.

@rust-timer

This comment has been minimized.

@bors

This comment has been minimized.

bors added a commit that referenced this pull request Mar 15, 2020
rustc: keep upvars tupled in {Closure,Generator}Substs.

Previously, each closure/generator capture's (aka "upvar") type was tracked as one "synthetic" type parameter in the closure/generator substs, and figuring out where the parent `fn`'s generics end and the synthetics start involved slicing at `tcx.generics_of(def_id).parent_count`.

Needing to query `generics_of` limited @davidtwco (who wants to compute some `TypeFlags` differently for parent generics vs upvars, and `TyCtxt` is not available there), which is how I got started on this, but it's also possible that the `generics_of` queries are slowing down `{Closure,Generator}Substs` methods.

To give an example, for a `foo::<T, U>::{closure#0}` with captures `x: X` and `y: Y`, substs are:
* before this PR: `[T, U, /*kind*/, /*signature*/, X, Y]`
* after this PR: `[T, U, /*kind*/, /*signature*/, (X, Y)]`

You can see that, with this PR, no matter how many captures, the last 3 entries in the substs (or 5 for a generator) are always the "synthetic" ones, with the last one being the tuple of capture types.

r? @nikomatsakis cc @Zoxc
@bors

This comment has been minimized.

@bors

This comment has been minimized.

@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 Mar 21, 2020
@eddyb
Copy link
Member Author

eddyb commented Mar 21, 2020

@bors r=nikomatsakis

@bors
Copy link
Contributor

bors commented Mar 21, 2020

📌 Commit d9a15cc 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-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 21, 2020
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 23, 2020
Rollup of 8 pull requests

Successful merges:

 - rust-lang#69080 (rustc_codegen_llvm: don't generate any type debuginfo for -Cdebuginfo=1.)
 - rust-lang#69940 (librustc_codegen_llvm: Replace deprecated API usage)
 - rust-lang#69942 (Increase verbosity when suggesting subtle code changes)
 - rust-lang#69968 (rustc: keep upvars tupled in {Closure,Generator}Substs.)
 - rust-lang#70123 (Ensure LLVM is in the link path for rustc tools)
 - rust-lang#70159 (Update the bundled wasi-libc with libstd)
 - rust-lang#70233 (resolve: Do not resolve visibilities on proc macro definitions twice)
 - rust-lang#70286 (Miri error type: remove UbExperimental variant)

Failed merges:

r? @ghost
@bors bors merged commit bee074f into rust-lang:master Mar 23, 2020
matthiaskrgr added a commit to matthiaskrgr/rust-clippy that referenced this pull request Mar 23, 2020
bors added a commit to rust-lang/rust-clippy that referenced this pull request Mar 23, 2020
@eddyb eddyb deleted the tupled-closure-captures branch March 23, 2020 14:48
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Mar 23, 2020
Changes:
````
rustup rust-lang#69968
Fix documentation generation for configurable lints
Fix single binding in closure
Improvement: Don't show function body in needless_lifetimes
````
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 23, 2020
submodules: update clippy from d8e6e4c to 1ff81c1

Changes:
````
rustup rust-lang#69968
Fix documentation generation for configurable lints
Fix single binding in closure
Improvement: Don't show function body in needless_lifetimes
````
Fixes rust-lang#70310
r? @Dylan-DPC
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request May 5, 2020
Changes:
````
rustup rust-lang/rust#69968
Fix documentation generation for configurable lints
Fix single binding in closure
Improvement: Don't show function body in needless_lifetimes
````
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