Skip to content

Commit 0d02577

Browse files
committed
Make generator types always Freeze.
When working on #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 #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.
1 parent b7a9c28 commit 0d02577

File tree

1 file changed

+9
-0
lines changed

1 file changed

+9
-0
lines changed

src/librustc/traits/select.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
22082208
}
22092209
}
22102210
}
2211+
ty::Generator(..)
2212+
if self.tcx().lang_items().freeze_trait() == Some(def_id) =>
2213+
{
2214+
// Generators are always Freeze - it's impossible to do anything
2215+
// with them unless you have a mutable reference, so any interior
2216+
// mutability of types 'inside' them is not observable from
2217+
// outside the generator
2218+
candidates.vec.push(BuiltinCandidate { has_nested: false });
2219+
}
22112220

22122221
_ => candidates.vec.push(AutoImplCandidate(def_id.clone())),
22132222
}

0 commit comments

Comments
 (0)