-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Add simple async drop glue generation #121801
Conversation
rustbot has assigned @michaelwoerister. Use r? to explicitly pick a reviewer |
This comment has been minimized.
This comment has been minimized.
The Miri subtree was changed cc @rust-lang/miri Some changes occurred to the CTFE / Miri engine cc @rust-lang/miri Some changes occurred in src/tools/rustfmt cc @rust-lang/rustfmt Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor |
This comment has been minimized.
This comment has been minimized.
Some high level comments: This PR adds many lang items, it would be good to document not just what they do, but why are they added
It would also be good to add test cases that are not yet supported in a test, to see what happens when they are encountered and add corresponding FIXMEs for people to see. Also add a test for a struct (or tuple) with 2 fields, one with non-trivial async drop, and one with non-trivial sync drop. |
This needs a review from someone who maintains MIR building/passes/transforms. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Great to see Miri tests already in the initial PR, that's much appreciated. :) |
I would say there's one specific problem about this API. To move forward I can either remove this For now I've decided to stick with removing |
Did a partial review to get an overview. I think the main comment of this PR should mention that this does not yet do
or any other automatic drop glue handling. All that we get is that a type gets dropped asynchronously plus the glue needed for field types and builtin types |
/// Empty strategy should generate this: | ||
/// | ||
/// ```ignore (illustrative) | ||
/// ready_unit() | ||
/// ``` | ||
Empty, |
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.
can we avoid this variant by never requesting the shim for these at all?
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.
We would still need to be able to directly call async_drop_in_place(_raw)::<()>
so we cannot "never request". This is true for regular drop glue too.
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.
May be relevant: #121801 (comment)
} | ||
} | ||
|
||
GlueStrategy::Chain { has_surface_async_drop, elem_tys } => { |
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.
can we write most of this one in surface Rust somehow? Maybe we could generate a tuple of the various types that should be dropped and recursively invoke drop on them?
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.
Sorry but I don't understand what you are describing. If you imagine a handwritten async destructor future for a tuple it would be an enum, for which each variant of it represents running an async destructor for some field, sequentially ordered one after the other + variants like Unresumed
and Done
.
I have not reviewed the shim impls yet, I'd prefer it if we could avoid such a complex shim |
When it comes to EDIT: However it will instead introduce ADT async destructors |
To reduce complexity of shim generation code I can try modeling it as nested expressions instead of directly creating basic blocks. Yeah, I should try doing that. EDIT: going to prioritize this for now since making changes became a bit unwieldy. EDIT2: Done in 16010ba :) |
Also this "constructor of async destructor" is confusing to say. Not sure what naming convention I should use instead. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@rustbot labels +T-lang +I-lang-nominated Let's discuss approval of this as an experiment. @zetanumbers / @petrochenkov: If you could perhaps write up further details for the lang team to review as part of this nomination about the nature of this part of the experiment, what the motivation for it is, and how this fits into the larger body of work, that work be helpful. |
Uh-oh
|
Sorry for adding changes last moment. |
The StableMIR change looks fine. Thanks for addressing it. |
why? The equivalent matches on |
Some |
@@ -2319,6 +2319,10 @@ impl<'tcx> Ty<'tcx> { | |||
|
|||
/// Returns the type of the async destructor of this type. | |||
pub fn async_destructor_ty(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Ty<'tcx> { | |||
if self.is_async_destructor_noop(tcx, param_env) || matches!(self.kind(), ty::Error(_)) { |
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.
prefer self.references_error()
over matching for ty::Error
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.
Neither drop glue nor discriminant kind do this. I will have to switch every match on ty::Error
otherwise compiler may emit type errors.
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 I cannot add this case to be a part of is_async_destructor_noop
because of this line, which differs from other similar types like ints:
| ty::Error(_) => false, |
But I'm not sure, maybe I should include it?
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 guess we can look if there's a general thing to improve here everywhere
/// Returning `false` means the type is known to not have `Drop` | ||
/// implementation. Returning `true` means nothing -- could be | ||
/// `Drop`, might not be. | ||
fn could_have_surface_drop(self) -> bool { |
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.
how does this relate to is_trivially_const_drop
and can we deduplicate some code?
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_trivially_const_drop
recurses into array and tuple elements to determine if type can be trivially destructed, while could_have_surface_drop
only checks if there's possible impl Drop for T
. This function would return false for a tuple with any collection of types, while !is_trivially_const_drop
for the same tuple may be true because of some element type could be an ADT. I could use could_have_surface_drop
from is_trivially_const_drop
since the former's negative implies the latter if it's ok.
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.
Well, in contrast is_trivially_const_drop
does not check/intend to check ManuallyDrop
, so those could mean a bit different things after all.
@bors r+ |
@bors rollup=never |
☀️ Test successful - checks-actions |
Finished benchmarking commit (aca749e): comparison URL. Overall result: ❌ regressions - no action needed@rustbot label: -perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 672.713s -> 674.396s (0.25%) |
Implement `needs_async_drop` in rustc and optimize async drop glue This PR expands on rust-lang#121801 and implements `Ty::needs_async_drop` which works almost exactly the same as `Ty::needs_drop`, which is needed for rust-lang#123948. Also made compiler's async drop code to look more like compiler's regular drop code, which enabled me to write an optimization where types which do not use `AsyncDrop` can simply forward async drop glue to `drop_in_place`. This made size of the async block from the [async_drop test](https://github.com/zetanumbers/rust/blob/67980dd6fb11917d23d01a19c2cf4cfc3978aac8/tests/ui/async-await/async-drop.rs) to decrease by 12%.
This is a prototype of the async drop glue generation for some simple types. Async drop glue is intended to behave very similar to the regular drop glue except for being asynchronous. Currently it does not execute synchronous drops but only calls user implementations of
AsyncDrop::async_drop
associative function and awaits the returned future. It is not complete as it only recurses into arrays, slices, tuples, and structs and does not have same sensible restrictions as the oldDrop
trait implementation like having the same bounds as the type definition, while code assumes their existence (requires a future work).This current design uses a workaround as it does not create any custom async destructor state machine types for ADTs, but instead uses types defined in the std library called future combinators (deferred_async_drop, chain, ready_unit).
Also I recommend reading my explainer.
This is a part of the MCP: Low level components for async drop work.
Feature completeness:
AsyncDrop
traitasync_drop_in_place_raw
/async drop glue generation support fordyn Trait
, see explainer's proposed design)async_drop_in_place_raw
AsyncDrop
implementation requires same bounds as type definitionTyKind::AdtAsyncDestructor
and get rid of combinators