-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Make generator types always Freeze. #65783
Conversation
r? @eddyb (rust_highfive has picked a reviewer for you, use r? to override) |
68a7566
to
d03ae1f
Compare
When working on rust-lang#57017, I discovered that generators are currently considered `Freeze` based on the witness types they contain (just like any other auto trait). That is, a generator which contains a `!Freeze` type (e.g. `Cell<T>`) will also be `!Freeze`. However, I believe that it is sound to always treat generator types as `Freeze`, regardless of what types they may store internally. The only possible of interacting with a generator is through the `resume` method of the generator trait. `resume` takes a `Pin<&mut Self>`, which requires a `&mut Self` to be created. In other words, given only a shared reference to a generator (`&{generator}`), it is impossible to mutate the generator. Note that is true regardless of whether or not types *inside* the generator have interior mutability - they can only change when `resume` is called, which is impossible to call using a shared reference. The motivation for this PR is to support further work on rust-lang#57017. My approach is to delay resolution of auto-trait predicates (e.g. `{generator}: Send)` until after we've constructed the generator MIR (specifically, after we've run the `StateTransform` MIR transformation pass). However, the const qualification pass (which runs before `StateTransform`) explictly checks whether types are `Freeze`. There are several ways of resolving this: 1. Refactor const-qualification to avoid the need to check whether generators are `Freeze`. This might involve running (part of ) const qualification after the `StateTransform` pass runs. 2. Use the current, more conservative approach for generator when checking `Freeze` - that is, use the witness types computed from the HIR. 3. Make generators always `Freeze`. Option 1 and 2 introduce a large amount of additional complexity for the sole purpose of supporting generators. Option 3 (this PR), requires only a minor change to `SelectionContext`. Theoretically, it could also improve performance, since we now perform less work when checking for `Freeze` types. This should probably have a test, but I'm not really sure how to write one, considering that `Freeze` is private.
d03ae1f
to
0d02577
Compare
r? @Zoxc cc @RalfJung @nikomatsakis |
You definitely shouldn't be doing that. |
Uh, this is subtle. So basically you are saying if we have a type like struct MyType<T>(UnsafeCell<T>);
impl<T> MyType<T> {
fn new() -> Self { ... }
fn do(&mut self) { ... }
} Then we can That... puts some assumptions about the Rust type system on its head. So far "Freeze = contains no UnsafeCell"; that would no longer be the case. So what does this mean in terms of UB? So far, as far as I am concerned, UnsafeCell is the only type here that actually affects whether some code is UB or not. So, it would not actually be UB to use interior mutability on So to have something like this PR, we'd have to attach the UB to the This needs an RFC, I would say. |
I think maybe we should close this PR until we work out better what plan we want? |
@RalfJung; The way I thought of it, generators would be treated in the same way as references with respect to I agree that this whole issue is very subtle, and should have an RFC. |
So far everything in the compiler and Stacked Borrows assumes that "layer of indirection" is about pointer indirections. You can't just re-define that; after all even with your PR, moving a generator moves its interior -- there is observably no layer of indirection. There is a layer of abstraction, but that's not the same thing. So what is your thought on the question I raised in my post regarding UB? Is writing to an |
Possibly stupid question: Could we make generator types wrap all of their mutable captures in |
I'm closing this - while I still think the underlying idea might work (even if it's by special-casing generators), it no longer seems to be necessary for #65782. Other changes to that PR should allow us to compute |
When working on #57017, I discovered that generators are currently
considered
Freeze
based on the witness types they contain (just likeany other auto trait). That is, a generator which contains a
!Freeze
type (e.g.
Cell<T>
) will also be!Freeze
.However, I believe that it is sound to always treat generator types as
Freeze
, regardless of what types they may store internally. The onlypossible of interacting with a generator is through the
resume
methodof the generator trait.
resume
takes aPin<&mut Self>
, whichrequires a
&mut Self
to be created. In other words, given only ashared reference to a generator (
&{generator}
), it is impossible tomutate the generator. Note that is true regardless of whether or not
types inside the generator have interior mutability - they can only
change when
resume
is called, which is impossible to call using ashared reference.
The motivation for this PR is to support further work on #57017. My
approach is to delay resolution of auto-trait predicates (e.g.
{generator}: Send)
until after we've constructed the generator MIR(specifically after we've run the
StateTransform
MIR transformationpass). However, the const qualification pass (which runs before
StateTransform
) explicitly checks whether types areFreeze
. There areseveral ways of resolving this:
generators are
Freeze
. This might involve running (part of ) constqualification after the
StateTransform
pass runs.checking
Freeze
- that is, use the witness types computed from theHIR.
Freeze
.Option 1 and 2 introduce a large amount of additional complexity for the
sole purpose of supporting generators. Option 3 (this PR), requires only
a minor change to
SelectionContext
. Theoretically, it could alsoimprove performance, since we now perform less work when checking for
Freeze
types.This should probably have a test, but I'm not really sure how to write
one, considering that
Freeze
is private.