Skip to content

Commit a3fdee9

Browse files
committed
Change generator trait to use pinning
1 parent 8611577 commit a3fdee9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+209
-170
lines changed

src/doc/unstable-book/src/language-features/generators.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,19 @@ A syntactical example of a generator is:
2929
#![feature(generators, generator_trait)]
3030

3131
use std::ops::{Generator, GeneratorState};
32+
use std::pin::Pin;
3233

3334
fn main() {
3435
let mut generator = || {
3536
yield 1;
3637
return "foo"
3738
};
3839

39-
match unsafe { generator.resume() } {
40+
match Pin::new(&mut generator).resume() {
4041
GeneratorState::Yielded(1) => {}
4142
_ => panic!("unexpected value from resume"),
4243
}
43-
match unsafe { generator.resume() } {
44+
match Pin::new(&mut generator).resume() {
4445
GeneratorState::Complete("foo") => {}
4546
_ => panic!("unexpected value from resume"),
4647
}
@@ -60,6 +61,7 @@ prints all numbers in order:
6061
#![feature(generators, generator_trait)]
6162

6263
use std::ops::Generator;
64+
use std::pin::Pin;
6365

6466
fn main() {
6567
let mut generator = || {
@@ -69,9 +71,9 @@ fn main() {
6971
};
7072

7173
println!("1");
72-
unsafe { generator.resume() };
74+
Pin::new(&mut generator).resume();
7375
println!("3");
74-
unsafe { generator.resume() };
76+
Pin::new(&mut generator).resume();
7577
println!("5");
7678
}
7779
```
@@ -86,13 +88,14 @@ Feedback on the design and usage is always appreciated!
8688
The `Generator` trait in `std::ops` currently looks like:
8789

8890
```
89-
# #![feature(generator_trait)]
91+
# #![feature(arbitrary_self_types, generator_trait)]
9092
# use std::ops::GeneratorState;
93+
# use std::pin::Pin;
9194
9295
pub trait Generator {
9396
type Yield;
9497
type Return;
95-
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
98+
fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return>;
9699
}
97100
```
98101

@@ -167,6 +170,7 @@ Let's take a look at an example to see what's going on here:
167170
#![feature(generators, generator_trait)]
168171

169172
use std::ops::Generator;
173+
use std::pin::Pin;
170174

171175
fn main() {
172176
let ret = "foo";
@@ -175,17 +179,18 @@ fn main() {
175179
return ret
176180
};
177181

178-
unsafe { generator.resume() };
179-
unsafe { generator.resume() };
182+
Pin::new(&mut generator).resume();
183+
Pin::new(&mut generator).resume();
180184
}
181185
```
182186

183187
This generator literal will compile down to something similar to:
184188

185189
```rust
186-
#![feature(generators, generator_trait)]
190+
#![feature(arbitrary_self_types, generators, generator_trait)]
187191

188192
use std::ops::{Generator, GeneratorState};
193+
use std::pin::Pin;
189194

190195
fn main() {
191196
let ret = "foo";
@@ -200,9 +205,9 @@ fn main() {
200205
type Yield = i32;
201206
type Return = &'static str;
202207

203-
unsafe fn resume(&mut self) -> GeneratorState<i32, &'static str> {
208+
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<i32, &'static str> {
204209
use std::mem;
205-
match mem::replace(self, __Generator::Done) {
210+
match mem::replace(&mut *self, __Generator::Done) {
206211
__Generator::Start(s) => {
207212
*self = __Generator::Yield1(s);
208213
GeneratorState::Yielded(1)
@@ -223,8 +228,8 @@ fn main() {
223228
__Generator::Start(ret)
224229
};
225230

226-
unsafe { generator.resume() };
227-
unsafe { generator.resume() };
231+
Pin::new(&mut generator).resume();
232+
Pin::new(&mut generator).resume();
228233
}
229234
```
230235

src/liballoc/boxed.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -873,13 +873,12 @@ impl<T: ?Sized> AsMut<T> for Box<T> {
873873
impl<T: ?Sized> Unpin for Box<T> { }
874874

875875
#[unstable(feature = "generator_trait", issue = "43122")]
876-
impl<T> Generator for Box<T>
877-
where T: Generator + ?Sized
878-
{
879-
type Yield = T::Yield;
880-
type Return = T::Return;
881-
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
882-
(**self).resume()
876+
impl<G: ?Sized + Generator + Unpin> Generator for Box<G> {
877+
type Yield = G::Yield;
878+
type Return = G::Return;
879+
880+
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
881+
G::resume(Pin::new(&mut *self))
883882
}
884883
}
885884

src/libcore/ops/generator.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use crate::marker::Unpin;
2+
use crate::pin::Pin;
3+
14
/// The result of a generator resumption.
25
///
36
/// This enum is returned from the `Generator::resume` method and indicates the
@@ -39,18 +42,19 @@ pub enum GeneratorState<Y, R> {
3942
/// #![feature(generators, generator_trait)]
4043
///
4144
/// use std::ops::{Generator, GeneratorState};
45+
/// use std::pin::Pin;
4246
///
4347
/// fn main() {
4448
/// let mut generator = || {
4549
/// yield 1;
4650
/// return "foo"
4751
/// };
4852
///
49-
/// match unsafe { generator.resume() } {
53+
/// match Pin::new(&mut generator).resume() {
5054
/// GeneratorState::Yielded(1) => {}
5155
/// _ => panic!("unexpected return from resume"),
5256
/// }
53-
/// match unsafe { generator.resume() } {
57+
/// match Pin::new(&mut generator).resume() {
5458
/// GeneratorState::Complete("foo") => {}
5559
/// _ => panic!("unexpected return from resume"),
5660
/// }
@@ -88,10 +92,6 @@ pub trait Generator {
8892
/// generator will continue executing until it either yields or returns, at
8993
/// which point this function will return.
9094
///
91-
/// The function is unsafe because it can be used on an immovable generator.
92-
/// After such a call, the immovable generator must not move again, but
93-
/// this is not enforced by the compiler.
94-
///
9595
/// # Return value
9696
///
9797
/// The `GeneratorState` enum returned from this function indicates what
@@ -110,16 +110,25 @@ pub trait Generator {
110110
/// been returned previously. While generator literals in the language are
111111
/// guaranteed to panic on resuming after `Complete`, this is not guaranteed
112112
/// for all implementations of the `Generator` trait.
113-
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
113+
fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return>;
114+
}
115+
116+
#[unstable(feature = "generator_trait", issue = "43122")]
117+
impl<G: ?Sized + Generator> Generator for Pin<&mut G> {
118+
type Yield = G::Yield;
119+
type Return = G::Return;
120+
121+
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
122+
G::resume((*self).as_mut())
123+
}
114124
}
115125

116126
#[unstable(feature = "generator_trait", issue = "43122")]
117-
impl<T> Generator for &mut T
118-
where T: Generator + ?Sized
119-
{
120-
type Yield = T::Yield;
121-
type Return = T::Return;
122-
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
123-
(**self).resume()
127+
impl<G: ?Sized + Generator + Unpin> Generator for &mut G {
128+
type Yield = G::Yield;
129+
type Return = G::Return;
130+
131+
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
132+
G::resume(Pin::new(&mut *self))
124133
}
125134
}

src/librustc_mir/diagnostics.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,14 +2119,15 @@ This error occurs because a borrow in a generator persists across a
21192119
yield point.
21202120
21212121
```compile_fail,E0626
2122-
# #![feature(generators, generator_trait)]
2122+
# #![feature(generators, generator_trait, pin)]
21232123
# use std::ops::Generator;
2124+
# use std::pin::Pin;
21242125
let mut b = || {
21252126
let a = &String::new(); // <-- This borrow...
21262127
yield (); // ...is still in scope here, when the yield occurs.
21272128
println!("{}", a);
21282129
};
2129-
unsafe { b.resume() };
2130+
Pin::new(&mut b).resume();
21302131
```
21312132
21322133
At present, it is not permitted to have a yield that occurs while a
@@ -2137,14 +2138,15 @@ resolve the previous example by removing the borrow and just storing
21372138
the integer by value:
21382139
21392140
```
2140-
# #![feature(generators, generator_trait)]
2141+
# #![feature(generators, generator_trait, pin)]
21412142
# use std::ops::Generator;
2143+
# use std::pin::Pin;
21422144
let mut b = || {
21432145
let a = 3;
21442146
yield ();
21452147
println!("{}", a);
21462148
};
2147-
unsafe { b.resume() };
2149+
Pin::new(&mut b).resume();
21482150
```
21492151
21502152
This is a very simple case, of course. In more complex cases, we may
@@ -2154,37 +2156,40 @@ in those cases, something like the `Rc` or `Arc` types may be useful.
21542156
This error also frequently arises with iteration:
21552157
21562158
```compile_fail,E0626
2157-
# #![feature(generators, generator_trait)]
2159+
# #![feature(generators, generator_trait, pin)]
21582160
# use std::ops::Generator;
2161+
# use std::pin::Pin;
21592162
let mut b = || {
21602163
let v = vec![1,2,3];
21612164
for &x in &v { // <-- borrow of `v` is still in scope...
21622165
yield x; // ...when this yield occurs.
21632166
}
21642167
};
2165-
unsafe { b.resume() };
2168+
Pin::new(&mut b).resume();
21662169
```
21672170
21682171
Such cases can sometimes be resolved by iterating "by value" (or using
21692172
`into_iter()`) to avoid borrowing:
21702173
21712174
```
2172-
# #![feature(generators, generator_trait)]
2175+
# #![feature(generators, generator_trait, pin)]
21732176
# use std::ops::Generator;
2177+
# use std::pin::Pin;
21742178
let mut b = || {
21752179
let v = vec![1,2,3];
21762180
for x in v { // <-- Take ownership of the values instead!
21772181
yield x; // <-- Now yield is OK.
21782182
}
21792183
};
2180-
unsafe { b.resume() };
2184+
Pin::new(&mut b).resume();
21812185
```
21822186
21832187
If taking ownership is not an option, using indices can work too:
21842188
21852189
```
2186-
# #![feature(generators, generator_trait)]
2190+
# #![feature(generators, generator_trait, pin)]
21872191
# use std::ops::Generator;
2192+
# use std::pin::Pin;
21882193
let mut b = || {
21892194
let v = vec![1,2,3];
21902195
let len = v.len(); // (*)
@@ -2193,7 +2198,7 @@ let mut b = || {
21932198
yield x; // <-- Now yield is OK.
21942199
}
21952200
};
2196-
unsafe { b.resume() };
2201+
Pin::new(&mut b).resume();
21972202
21982203
// (*) -- Unfortunately, these temporaries are currently required.
21992204
// See <https://github.com/rust-lang/rust/issues/43122>.

src/libstd/future.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
3333
impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
3434
type Output = T::Return;
3535
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
36-
set_task_waker(lw, || match unsafe { Pin::get_unchecked_mut(self).0.resume() } {
36+
// Safe because we're !Unpin + !Drop mapping to a ?Unpin value
37+
let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
38+
set_task_waker(lw, || match gen.resume() {
3739
GeneratorState::Yielded(()) => Poll::Pending,
3840
GeneratorState::Complete(x) => Poll::Ready(x),
3941
})

src/test/run-pass/drop/dynamic-drop.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use std::cell::{Cell, RefCell};
1313
use std::ops::Generator;
1414
use std::panic;
15+
use std::pin::Pin;
1516
use std::usize;
1617

1718
struct InjectedFailure;
@@ -172,7 +173,7 @@ fn generator(a: &Allocator, run_count: usize) {
172173
);
173174
};
174175
for _ in 0..run_count {
175-
unsafe { gen.resume(); }
176+
Pin::new(&mut gen).resume();
176177
}
177178
}
178179

src/test/run-pass/generator/auxiliary/xcrate.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![feature(generators, generator_trait)]
22

3+
use std::marker::Unpin;
34
use std::ops::Generator;
45

56
pub fn foo() -> impl Generator<Yield = (), Return = ()> {
@@ -10,7 +11,7 @@ pub fn foo() -> impl Generator<Yield = (), Return = ()> {
1011
}
1112
}
1213

13-
pub fn bar<T: 'static>(t: T) -> Box<Generator<Yield = T, Return = ()>> {
14+
pub fn bar<T: Unpin + 'static>(t: T) -> Box<Generator<Yield = T, Return = ()> + Unpin> {
1415
Box::new(|| {
1516
yield t;
1617
})

src/test/run-pass/generator/conditional-drop.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![feature(generators, generator_trait)]
44

55
use std::ops::Generator;
6+
use std::pin::Pin;
67
use std::sync::atomic::{AtomicUsize, Ordering};
78

89
static A: AtomicUsize = AtomicUsize::new(0);
@@ -34,9 +35,9 @@ fn t1() {
3435
};
3536

3637
let n = A.load(Ordering::SeqCst);
37-
unsafe { a.resume() };
38+
Pin::new(&mut a).resume();
3839
assert_eq!(A.load(Ordering::SeqCst), n + 1);
39-
unsafe { a.resume() };
40+
Pin::new(&mut a).resume();
4041
assert_eq!(A.load(Ordering::SeqCst), n + 1);
4142
}
4243

@@ -50,8 +51,8 @@ fn t2() {
5051
};
5152

5253
let n = A.load(Ordering::SeqCst);
53-
unsafe { a.resume() };
54+
Pin::new(&mut a).resume();
5455
assert_eq!(A.load(Ordering::SeqCst), n);
55-
unsafe { a.resume() };
56+
Pin::new(&mut a).resume();
5657
assert_eq!(A.load(Ordering::SeqCst), n + 1);
5758
}

src/test/run-pass/generator/control-flow.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
#![feature(generators, generator_trait)]
44

5+
use std::marker::Unpin;
56
use std::ops::{GeneratorState, Generator};
7+
use std::pin::Pin;
68

79
fn finish<T>(mut amt: usize, mut t: T) -> T::Return
8-
where T: Generator<Yield = ()>
10+
where T: Generator<Yield = ()> + Unpin,
911
{
1012
loop {
11-
match unsafe { t.resume() } {
13+
match Pin::new(&mut t).resume() {
1214
GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(),
1315
GeneratorState::Complete(ret) => {
1416
assert_eq!(amt, 0);

0 commit comments

Comments
 (0)