-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Conversation
@bors try @rust-timer queue |
Awaiting bors try build completion |
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 |
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.
@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.
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 assume by "remove" you mean "make it do nothing"?
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, 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.
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'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).
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.
That said, this is an orthogonal place where we could apply type-limits, instead of applying them at type creation time or whatever.
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 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.
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'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?
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.
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? 🤣
💥 Test timed out |
@bors try |
⌛ Trying commit da30907 with merge 26cab41b863fc625c0d81f771e063c685680f335... |
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> { |
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'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.
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 add this in your PR, FWIW, but if @nikomatsakis doesn't mind I can do it in this one too.
💥 Test timed out |
@bors try (CI outage should be fixed now) |
⌛ Trying commit da30907 with merge f7b1e868f01ad49dcc05daad583793f5c413bc9a... |
☀️ Try build successful - checks-azure |
Queued f7b1e868f01ad49dcc05daad583793f5c413bc9a with parent 54b7d21, future comparison URL. |
This comment has been minimized.
This comment has been minimized.
ca8521b
to
cb6cdc0
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
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
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
7c39021
to
d9a15cc
Compare
@bors r=nikomatsakis |
📌 Commit d9a15cc has been approved by |
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
rustup rust-lang/rust#69968 changelog: none
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 ````
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
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 ````
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 attcx.generics_of(def_id).parent_count
.Needing to query
generics_of
limited @davidtwco (who wants to compute someTypeFlags
differently for parent generics vs upvars, andTyCtxt
is not available there), which is how I got started on this, but it's also possible that thegenerics_of
queries are slowing down{Closure,Generator}Substs
methods.To give an example, for a
foo::<T, U>::{closure#0}
with capturesx: X
andy: Y
, substs are:[T, U, /*kind*/, /*signature*/, X, Y]
[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