1
Fork 0

Change generator trait to use pinning

This commit is contained in:
Wim Looman 2018-10-04 20:49:38 +02:00
parent 8611577360
commit a3fdee9a75
44 changed files with 209 additions and 170 deletions

View file

@ -29,6 +29,7 @@ A syntactical example of a generator is:
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::{Generator, GeneratorState}; use std::ops::{Generator, GeneratorState};
use std::pin::Pin;
fn main() { fn main() {
let mut generator = || { let mut generator = || {
@ -36,11 +37,11 @@ fn main() {
return "foo" return "foo"
}; };
match unsafe { generator.resume() } { match Pin::new(&mut generator).resume() {
GeneratorState::Yielded(1) => {} GeneratorState::Yielded(1) => {}
_ => panic!("unexpected value from resume"), _ => panic!("unexpected value from resume"),
} }
match unsafe { generator.resume() } { match Pin::new(&mut generator).resume() {
GeneratorState::Complete("foo") => {} GeneratorState::Complete("foo") => {}
_ => panic!("unexpected value from resume"), _ => panic!("unexpected value from resume"),
} }
@ -60,6 +61,7 @@ prints all numbers in order:
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
fn main() { fn main() {
let mut generator = || { let mut generator = || {
@ -69,9 +71,9 @@ fn main() {
}; };
println!("1"); println!("1");
unsafe { generator.resume() }; Pin::new(&mut generator).resume();
println!("3"); println!("3");
unsafe { generator.resume() }; Pin::new(&mut generator).resume();
println!("5"); println!("5");
} }
``` ```
@ -86,13 +88,14 @@ Feedback on the design and usage is always appreciated!
The `Generator` trait in `std::ops` currently looks like: The `Generator` trait in `std::ops` currently looks like:
``` ```
# #![feature(generator_trait)] # #![feature(arbitrary_self_types, generator_trait)]
# use std::ops::GeneratorState; # use std::ops::GeneratorState;
# use std::pin::Pin;
pub trait Generator { pub trait Generator {
type Yield; type Yield;
type Return; type Return;
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>; fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return>;
} }
``` ```
@ -167,6 +170,7 @@ Let's take a look at an example to see what's going on here:
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
fn main() { fn main() {
let ret = "foo"; let ret = "foo";
@ -175,17 +179,18 @@ fn main() {
return ret return ret
}; };
unsafe { generator.resume() }; Pin::new(&mut generator).resume();
unsafe { generator.resume() }; Pin::new(&mut generator).resume();
} }
``` ```
This generator literal will compile down to something similar to: This generator literal will compile down to something similar to:
```rust ```rust
#![feature(generators, generator_trait)] #![feature(arbitrary_self_types, generators, generator_trait)]
use std::ops::{Generator, GeneratorState}; use std::ops::{Generator, GeneratorState};
use std::pin::Pin;
fn main() { fn main() {
let ret = "foo"; let ret = "foo";
@ -200,9 +205,9 @@ fn main() {
type Yield = i32; type Yield = i32;
type Return = &'static str; type Return = &'static str;
unsafe fn resume(&mut self) -> GeneratorState<i32, &'static str> { fn resume(mut self: Pin<&mut Self>) -> GeneratorState<i32, &'static str> {
use std::mem; use std::mem;
match mem::replace(self, __Generator::Done) { match mem::replace(&mut *self, __Generator::Done) {
__Generator::Start(s) => { __Generator::Start(s) => {
*self = __Generator::Yield1(s); *self = __Generator::Yield1(s);
GeneratorState::Yielded(1) GeneratorState::Yielded(1)
@ -223,8 +228,8 @@ fn main() {
__Generator::Start(ret) __Generator::Start(ret)
}; };
unsafe { generator.resume() }; Pin::new(&mut generator).resume();
unsafe { generator.resume() }; Pin::new(&mut generator).resume();
} }
``` ```

View file

@ -873,13 +873,12 @@ impl<T: ?Sized> AsMut<T> for Box<T> {
impl<T: ?Sized> Unpin for Box<T> { } impl<T: ?Sized> Unpin for Box<T> { }
#[unstable(feature = "generator_trait", issue = "43122")] #[unstable(feature = "generator_trait", issue = "43122")]
impl<T> Generator for Box<T> impl<G: ?Sized + Generator + Unpin> Generator for Box<G> {
where T: Generator + ?Sized type Yield = G::Yield;
{ type Return = G::Return;
type Yield = T::Yield;
type Return = T::Return; fn resume(mut self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> { G::resume(Pin::new(&mut *self))
(**self).resume()
} }
} }

View file

@ -1,3 +1,6 @@
use crate::marker::Unpin;
use crate::pin::Pin;
/// The result of a generator resumption. /// The result of a generator resumption.
/// ///
/// This enum is returned from the `Generator::resume` method and indicates the /// This enum is returned from the `Generator::resume` method and indicates the
@ -39,6 +42,7 @@ pub enum GeneratorState<Y, R> {
/// #![feature(generators, generator_trait)] /// #![feature(generators, generator_trait)]
/// ///
/// use std::ops::{Generator, GeneratorState}; /// use std::ops::{Generator, GeneratorState};
/// use std::pin::Pin;
/// ///
/// fn main() { /// fn main() {
/// let mut generator = || { /// let mut generator = || {
@ -46,11 +50,11 @@ pub enum GeneratorState<Y, R> {
/// return "foo" /// return "foo"
/// }; /// };
/// ///
/// match unsafe { generator.resume() } { /// match Pin::new(&mut generator).resume() {
/// GeneratorState::Yielded(1) => {} /// GeneratorState::Yielded(1) => {}
/// _ => panic!("unexpected return from resume"), /// _ => panic!("unexpected return from resume"),
/// } /// }
/// match unsafe { generator.resume() } { /// match Pin::new(&mut generator).resume() {
/// GeneratorState::Complete("foo") => {} /// GeneratorState::Complete("foo") => {}
/// _ => panic!("unexpected return from resume"), /// _ => panic!("unexpected return from resume"),
/// } /// }
@ -88,10 +92,6 @@ pub trait Generator {
/// generator will continue executing until it either yields or returns, at /// generator will continue executing until it either yields or returns, at
/// which point this function will return. /// which point this function will return.
/// ///
/// The function is unsafe because it can be used on an immovable generator.
/// After such a call, the immovable generator must not move again, but
/// this is not enforced by the compiler.
///
/// # Return value /// # Return value
/// ///
/// The `GeneratorState` enum returned from this function indicates what /// The `GeneratorState` enum returned from this function indicates what
@ -110,16 +110,25 @@ pub trait Generator {
/// been returned previously. While generator literals in the language are /// been returned previously. While generator literals in the language are
/// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// guaranteed to panic on resuming after `Complete`, this is not guaranteed
/// for all implementations of the `Generator` trait. /// for all implementations of the `Generator` trait.
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>; fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return>;
} }
#[unstable(feature = "generator_trait", issue = "43122")] #[unstable(feature = "generator_trait", issue = "43122")]
impl<T> Generator for &mut T impl<G: ?Sized + Generator> Generator for Pin<&mut G> {
where T: Generator + ?Sized type Yield = G::Yield;
{ type Return = G::Return;
type Yield = T::Yield;
type Return = T::Return; fn resume(mut self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> { G::resume((*self).as_mut())
(**self).resume() }
}
#[unstable(feature = "generator_trait", issue = "43122")]
impl<G: ?Sized + Generator + Unpin> Generator for &mut G {
type Yield = G::Yield;
type Return = G::Return;
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
G::resume(Pin::new(&mut *self))
} }
} }

View file

@ -2119,14 +2119,15 @@ This error occurs because a borrow in a generator persists across a
yield point. yield point.
```compile_fail,E0626 ```compile_fail,E0626
# #![feature(generators, generator_trait)] # #![feature(generators, generator_trait, pin)]
# use std::ops::Generator; # use std::ops::Generator;
# use std::pin::Pin;
let mut b = || { let mut b = || {
let a = &String::new(); // <-- This borrow... let a = &String::new(); // <-- This borrow...
yield (); // ...is still in scope here, when the yield occurs. yield (); // ...is still in scope here, when the yield occurs.
println!("{}", a); println!("{}", a);
}; };
unsafe { b.resume() }; Pin::new(&mut b).resume();
``` ```
At present, it is not permitted to have a yield that occurs while a 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
the integer by value: the integer by value:
``` ```
# #![feature(generators, generator_trait)] # #![feature(generators, generator_trait, pin)]
# use std::ops::Generator; # use std::ops::Generator;
# use std::pin::Pin;
let mut b = || { let mut b = || {
let a = 3; let a = 3;
yield (); yield ();
println!("{}", a); println!("{}", a);
}; };
unsafe { b.resume() }; Pin::new(&mut b).resume();
``` ```
This is a very simple case, of course. In more complex cases, we may 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.
This error also frequently arises with iteration: This error also frequently arises with iteration:
```compile_fail,E0626 ```compile_fail,E0626
# #![feature(generators, generator_trait)] # #![feature(generators, generator_trait, pin)]
# use std::ops::Generator; # use std::ops::Generator;
# use std::pin::Pin;
let mut b = || { let mut b = || {
let v = vec![1,2,3]; let v = vec![1,2,3];
for &x in &v { // <-- borrow of `v` is still in scope... for &x in &v { // <-- borrow of `v` is still in scope...
yield x; // ...when this yield occurs. yield x; // ...when this yield occurs.
} }
}; };
unsafe { b.resume() }; Pin::new(&mut b).resume();
``` ```
Such cases can sometimes be resolved by iterating "by value" (or using Such cases can sometimes be resolved by iterating "by value" (or using
`into_iter()`) to avoid borrowing: `into_iter()`) to avoid borrowing:
``` ```
# #![feature(generators, generator_trait)] # #![feature(generators, generator_trait, pin)]
# use std::ops::Generator; # use std::ops::Generator;
# use std::pin::Pin;
let mut b = || { let mut b = || {
let v = vec![1,2,3]; let v = vec![1,2,3];
for x in v { // <-- Take ownership of the values instead! for x in v { // <-- Take ownership of the values instead!
yield x; // <-- Now yield is OK. yield x; // <-- Now yield is OK.
} }
}; };
unsafe { b.resume() }; Pin::new(&mut b).resume();
``` ```
If taking ownership is not an option, using indices can work too: If taking ownership is not an option, using indices can work too:
``` ```
# #![feature(generators, generator_trait)] # #![feature(generators, generator_trait, pin)]
# use std::ops::Generator; # use std::ops::Generator;
# use std::pin::Pin;
let mut b = || { let mut b = || {
let v = vec![1,2,3]; let v = vec![1,2,3];
let len = v.len(); // (*) let len = v.len(); // (*)
@ -2193,7 +2198,7 @@ let mut b = || {
yield x; // <-- Now yield is OK. yield x; // <-- Now yield is OK.
} }
}; };
unsafe { b.resume() }; Pin::new(&mut b).resume();
// (*) -- Unfortunately, these temporaries are currently required. // (*) -- Unfortunately, these temporaries are currently required.
// See <https://github.com/rust-lang/rust/issues/43122>. // See <https://github.com/rust-lang/rust/issues/43122>.

View file

@ -33,7 +33,9 @@ impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
impl<T: Generator<Yield = ()>> Future for GenFuture<T> { impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
type Output = T::Return; type Output = T::Return;
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
set_task_waker(lw, || match unsafe { Pin::get_unchecked_mut(self).0.resume() } { // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
set_task_waker(lw, || match gen.resume() {
GeneratorState::Yielded(()) => Poll::Pending, GeneratorState::Yielded(()) => Poll::Pending,
GeneratorState::Complete(x) => Poll::Ready(x), GeneratorState::Complete(x) => Poll::Ready(x),
}) })

View file

@ -12,6 +12,7 @@
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::ops::Generator; use std::ops::Generator;
use std::panic; use std::panic;
use std::pin::Pin;
use std::usize; use std::usize;
struct InjectedFailure; struct InjectedFailure;
@ -172,7 +173,7 @@ fn generator(a: &Allocator, run_count: usize) {
); );
}; };
for _ in 0..run_count { for _ in 0..run_count {
unsafe { gen.resume(); } Pin::new(&mut gen).resume();
} }
} }

View file

@ -1,5 +1,6 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::marker::Unpin;
use std::ops::Generator; use std::ops::Generator;
pub fn foo() -> impl Generator<Yield = (), Return = ()> { pub fn foo() -> impl Generator<Yield = (), Return = ()> {
@ -10,7 +11,7 @@ pub fn foo() -> impl Generator<Yield = (), Return = ()> {
} }
} }
pub fn bar<T: 'static>(t: T) -> Box<Generator<Yield = T, Return = ()>> { pub fn bar<T: Unpin + 'static>(t: T) -> Box<Generator<Yield = T, Return = ()> + Unpin> {
Box::new(|| { Box::new(|| {
yield t; yield t;
}) })

View file

@ -3,6 +3,7 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
static A: AtomicUsize = AtomicUsize::new(0); static A: AtomicUsize = AtomicUsize::new(0);
@ -34,9 +35,9 @@ fn t1() {
}; };
let n = A.load(Ordering::SeqCst); let n = A.load(Ordering::SeqCst);
unsafe { a.resume() }; Pin::new(&mut a).resume();
assert_eq!(A.load(Ordering::SeqCst), n + 1); assert_eq!(A.load(Ordering::SeqCst), n + 1);
unsafe { a.resume() }; Pin::new(&mut a).resume();
assert_eq!(A.load(Ordering::SeqCst), n + 1); assert_eq!(A.load(Ordering::SeqCst), n + 1);
} }
@ -50,8 +51,8 @@ fn t2() {
}; };
let n = A.load(Ordering::SeqCst); let n = A.load(Ordering::SeqCst);
unsafe { a.resume() }; Pin::new(&mut a).resume();
assert_eq!(A.load(Ordering::SeqCst), n); assert_eq!(A.load(Ordering::SeqCst), n);
unsafe { a.resume() }; Pin::new(&mut a).resume();
assert_eq!(A.load(Ordering::SeqCst), n + 1); assert_eq!(A.load(Ordering::SeqCst), n + 1);
} }

View file

@ -2,13 +2,15 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::marker::Unpin;
use std::ops::{GeneratorState, Generator}; use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
fn finish<T>(mut amt: usize, mut t: T) -> T::Return fn finish<T>(mut amt: usize, mut t: T) -> T::Return
where T: Generator<Yield = ()> where T: Generator<Yield = ()> + Unpin,
{ {
loop { loop {
match unsafe { t.resume() } { match Pin::new(&mut t).resume() {
GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(), GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(),
GeneratorState::Complete(ret) => { GeneratorState::Complete(ret) => {
assert_eq!(amt, 0); assert_eq!(amt, 0);

View file

@ -3,6 +3,7 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
static A: AtomicUsize = AtomicUsize::new(0); static A: AtomicUsize = AtomicUsize::new(0);
@ -29,7 +30,7 @@ fn t1() {
}; };
let n = A.load(Ordering::SeqCst); let n = A.load(Ordering::SeqCst);
drop(unsafe { foo.resume() }); drop(Pin::new(&mut foo).resume());
assert_eq!(A.load(Ordering::SeqCst), n); assert_eq!(A.load(Ordering::SeqCst), n);
drop(foo); drop(foo);
assert_eq!(A.load(Ordering::SeqCst), n + 1); assert_eq!(A.load(Ordering::SeqCst), n + 1);
@ -42,7 +43,7 @@ fn t2() {
}; };
let n = A.load(Ordering::SeqCst); let n = A.load(Ordering::SeqCst);
drop(unsafe { foo.resume() }); drop(Pin::new(&mut foo).resume());
assert_eq!(A.load(Ordering::SeqCst), n + 1); assert_eq!(A.load(Ordering::SeqCst), n + 1);
drop(foo); drop(foo);
assert_eq!(A.load(Ordering::SeqCst), n + 1); assert_eq!(A.load(Ordering::SeqCst), n + 1);

View file

@ -3,6 +3,7 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::{ Generator, GeneratorState }; use std::ops::{ Generator, GeneratorState };
use std::pin::Pin;
fn foo(_: &str) -> String { fn foo(_: &str) -> String {
String::new() String::new()
@ -27,8 +28,6 @@ fn bar2(baz: String) -> impl Generator<Yield = String, Return = ()> {
} }
fn main() { fn main() {
unsafe { assert_eq!(Pin::new(&mut bar(String::new())).resume(), GeneratorState::Yielded(String::new()));
assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new())); assert_eq!(Pin::new(&mut bar2(String::new())).resume(), GeneratorState::Complete(()));
assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(()));
}
} }

View file

@ -2,24 +2,26 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::marker::Unpin;
use std::ops::{GeneratorState, Generator}; use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
struct W<T>(T); struct W<T>(T);
// This impl isn't safe in general, but the generator used in this test is movable // This impl isn't safe in general, but the generator used in this test is movable
// so it won't cause problems. // so it won't cause problems.
impl<T: Generator<Return = ()>> Iterator for W<T> { impl<T: Generator<Return = ()> + Unpin> Iterator for W<T> {
type Item = T::Yield; type Item = T::Yield;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
match unsafe { self.0.resume() } { match Pin::new(&mut self.0).resume() {
GeneratorState::Complete(..) => None, GeneratorState::Complete(..) => None,
GeneratorState::Yielded(v) => Some(v), GeneratorState::Yielded(v) => Some(v),
} }
} }
} }
fn test() -> impl Generator<Return=(), Yield=u8> { fn test() -> impl Generator<Return=(), Yield=u8> + Unpin {
|| { || {
for i in 1..6 { for i in 1..6 {
yield i yield i

View file

@ -3,11 +3,12 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
fn main() { fn main() {
let b = |_| 3; let b = |_| 3;
let mut a = || { let mut a = || {
b(yield); b(yield);
}; };
unsafe { a.resume() }; Pin::new(&mut a).resume();
} }

View file

@ -1,10 +1,9 @@
// run-pass // run-pass
#![feature(generators)] #![feature(generators, generator_trait)]
#![feature(generator_trait)]
use std::ops::Generator; use std::ops::{Generator, GeneratorState};
use std::ops::GeneratorState; use std::pin::Pin;
fn main() { fn main() {
let _generator = || { let _generator = || {
@ -12,7 +11,7 @@ fn main() {
yield 2; yield 2;
}; };
match unsafe { sub_generator.resume() } { match Pin::new(&mut sub_generator).resume() {
GeneratorState::Yielded(x) => { GeneratorState::Yielded(x) => {
yield x; yield x;
} }

View file

@ -6,6 +6,7 @@
use std::ops::Generator; use std::ops::Generator;
use std::panic; use std::panic;
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
static A: AtomicUsize = AtomicUsize::new(0); static A: AtomicUsize = AtomicUsize::new(0);
@ -34,7 +35,7 @@ fn main() {
assert_eq!(A.load(Ordering::SeqCst), 0); assert_eq!(A.load(Ordering::SeqCst), 0);
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
unsafe { foo.resume() } Pin::new(&mut foo).resume()
})); }));
assert!(res.is_err()); assert!(res.is_err());
assert_eq!(A.load(Ordering::SeqCst), 1); assert_eq!(A.load(Ordering::SeqCst), 1);
@ -49,7 +50,7 @@ fn main() {
assert_eq!(A.load(Ordering::SeqCst), 1); assert_eq!(A.load(Ordering::SeqCst), 1);
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
unsafe { foo.resume() } Pin::new(&mut foo).resume()
})); }));
assert!(res.is_err()); assert!(res.is_err());
assert_eq!(A.load(Ordering::SeqCst), 1); assert_eq!(A.load(Ordering::SeqCst), 1);

View file

@ -5,6 +5,7 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
use std::panic; use std::panic;
fn main() { fn main() {
@ -16,13 +17,13 @@ fn main() {
}; };
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
unsafe { foo.resume() } Pin::new(&mut foo).resume()
})); }));
assert!(res.is_err()); assert!(res.is_err());
for _ in 0..10 { for _ in 0..10 {
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
unsafe { foo.resume() } Pin::new(&mut foo).resume()
})); }));
assert!(res.is_err()); assert!(res.is_err());
} }

View file

@ -5,6 +5,7 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::{GeneratorState, Generator}; use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
use std::panic; use std::panic;
fn main() { fn main() {
@ -15,12 +16,12 @@ fn main() {
yield; yield;
}; };
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {} GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
match panic::catch_unwind(move || unsafe { foo.resume() }) { match panic::catch_unwind(move || Pin::new(&mut foo).resume()) {
Ok(_) => panic!("generator successfully resumed"), Ok(_) => panic!("generator successfully resumed"),
Err(_) => {} Err(_) => {}
} }

View file

@ -6,6 +6,7 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::{GeneratorState, Generator}; use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
use std::thread; use std::thread;
#[test] #[test]
@ -16,7 +17,7 @@ fn simple() {
} }
}; };
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {} GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
@ -32,7 +33,7 @@ fn return_capture() {
a a
}; };
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(ref s) if *s == "foo" => {} GeneratorState::Complete(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
@ -44,11 +45,11 @@ fn simple_yield() {
yield; yield;
}; };
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(()) => {} GeneratorState::Yielded(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {} GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
@ -61,11 +62,11 @@ fn yield_capture() {
yield b; yield b;
}; };
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(ref s) if *s == "foo" => {} GeneratorState::Yielded(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {} GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
@ -78,11 +79,11 @@ fn simple_yield_value() {
return String::from("foo") return String::from("foo")
}; };
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(ref s) if *s == "bar" => {} GeneratorState::Yielded(ref s) if *s == "bar" => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(ref s) if *s == "foo" => {} GeneratorState::Complete(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
@ -96,11 +97,11 @@ fn return_after_yield() {
return a return a
}; };
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(()) => {} GeneratorState::Yielded(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(ref s) if *s == "foo" => {} GeneratorState::Complete(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
@ -148,11 +149,11 @@ fn send_and_sync() {
fn send_over_threads() { fn send_over_threads() {
let mut foo = || { yield }; let mut foo = || { yield };
thread::spawn(move || { thread::spawn(move || {
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(()) => {} GeneratorState::Yielded(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {} GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
@ -161,11 +162,11 @@ fn send_over_threads() {
let a = String::from("a"); let a = String::from("a");
let mut foo = || { yield a }; let mut foo = || { yield a };
thread::spawn(move || { thread::spawn(move || {
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(ref s) if *s == "a" => {} GeneratorState::Yielded(ref s) if *s == "a" => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {} GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }

View file

@ -2,6 +2,7 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::pin::Pin;
use std::ops::{Generator, GeneratorState}; use std::ops::{Generator, GeneratorState};
fn main() { fn main() {
@ -11,8 +12,9 @@ fn main() {
yield; yield;
assert_eq!(b as *const _, &a as *const _); assert_eq!(b as *const _, &a as *const _);
}; };
unsafe { // Safety: We shadow the original generator variable so have no safe API to
assert_eq!(generator.resume(), GeneratorState::Yielded(())); // move it after this point.
assert_eq!(generator.resume(), GeneratorState::Complete(())); let mut generator = unsafe { Pin::new_unchecked(&mut generator) };
} assert_eq!(generator.as_mut().resume(), GeneratorState::Yielded(()));
assert_eq!(generator.as_mut().resume(), GeneratorState::Complete(()));
} }

View file

@ -7,7 +7,8 @@
extern crate xcrate_reachable as foo; extern crate xcrate_reachable as foo;
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
fn main() { fn main() {
unsafe { foo::foo().resume(); } Pin::new(&mut foo::foo()).resume();
} }

View file

@ -7,22 +7,23 @@
extern crate xcrate; extern crate xcrate;
use std::ops::{GeneratorState, Generator}; use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
fn main() { fn main() {
let mut foo = xcrate::foo(); let mut foo = xcrate::foo();
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {} GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
let mut foo = xcrate::bar(3); let mut foo = xcrate::bar(3);
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(3) => {} GeneratorState::Yielded(3) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }
match unsafe { foo.resume() } { match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {} GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s), s => panic!("bad state: {:?}", s),
} }

View file

@ -1,12 +1,12 @@
error[E0597]: `a` does not live long enough error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:8:29 --> $DIR/borrowing.rs:9:33
| |
LL | unsafe { (|| yield &a).resume() } LL | Pin::new(&mut || yield &a).resume()
| -----------^- | ----------^
| || | | | |
| || borrowed value does not live long enough | | borrowed value does not live long enough
| |value captured here by generator | value captured here by generator
| a temporary with access to the borrow is created here ... | a temporary with access to the borrow is created here ...
LL | //~^ ERROR: `a` does not live long enough LL | //~^ ERROR: `a` does not live long enough
LL | }; LL | };
| -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator
@ -16,7 +16,7 @@ LL | };
= note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block.
error[E0597]: `a` does not live long enough error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:15:20 --> $DIR/borrowing.rs:16:20
| |
LL | let _b = { LL | let _b = {
| -- borrow later stored here | -- borrow later stored here

View file

@ -1,11 +1,12 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
fn main() { fn main() {
let _b = { let _b = {
let a = 3; let a = 3;
unsafe { (|| yield &a).resume() } Pin::new(&mut || yield &a).resume()
//~^ ERROR: `a` does not live long enough //~^ ERROR: `a` does not live long enough
}; };

View file

@ -1,10 +1,10 @@
error[E0597]: `a` does not live long enough error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:8:29 --> $DIR/borrowing.rs:9:33
| |
LL | unsafe { (|| yield &a).resume() } LL | Pin::new(&mut || yield &a).resume()
| -- ^ borrowed value does not live long enough | -- ^ borrowed value does not live long enough
| | | |
| capture occurs here | capture occurs here
LL | //~^ ERROR: `a` does not live long enough LL | //~^ ERROR: `a` does not live long enough
LL | }; LL | };
| - borrowed value only lives until here | - borrowed value only lives until here
@ -13,7 +13,7 @@ LL | }
| - borrowed value needs to live until here | - borrowed value needs to live until here
error[E0597]: `a` does not live long enough error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:15:20 --> $DIR/borrowing.rs:16:20
| |
LL | || { LL | || {
| -- capture occurs here | -- capture occurs here

View file

@ -1,5 +1,5 @@
error[E0597]: `*cell` does not live long enough error[E0597]: `*cell` does not live long enough
--> $DIR/dropck.rs:9:40 --> $DIR/dropck.rs:10:40
| |
LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
| ^^^^ borrowed value does not live long enough | ^^^^ borrowed value does not live long enough
@ -13,7 +13,7 @@ LL | }
= note: values in a scope are dropped in the opposite order they are defined = note: values in a scope are dropped in the opposite order they are defined
error[E0597]: `ref_` does not live long enough error[E0597]: `ref_` does not live long enough
--> $DIR/dropck.rs:14:18 --> $DIR/dropck.rs:15:18
| |
LL | gen = || { LL | gen = || {
| -- value captured here by generator | -- value captured here by generator

View file

@ -2,6 +2,7 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
fn main() { fn main() {
let (mut gen, cell); let (mut gen, cell);
@ -14,6 +15,6 @@ fn main() {
let _d = ref_.take(); //~ ERROR `ref_` does not live long enough let _d = ref_.take(); //~ ERROR `ref_` does not live long enough
yield; yield;
}; };
unsafe { gen.resume(); } Pin::new(&mut gen).resume();
// drops the RefCell and then the Ref, leading to use-after-free // drops the RefCell and then the Ref, leading to use-after-free
} }

View file

@ -1,5 +1,5 @@
error[E0597]: `*cell` does not live long enough error[E0597]: `*cell` does not live long enough
--> $DIR/dropck.rs:9:40 --> $DIR/dropck.rs:10:40
| |
LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
| ^^^^ borrowed value does not live long enough | ^^^^ borrowed value does not live long enough
@ -10,7 +10,7 @@ LL | }
= note: values in a scope are dropped in the opposite order they are created = note: values in a scope are dropped in the opposite order they are created
error[E0597]: `ref_` does not live long enough error[E0597]: `ref_` does not live long enough
--> $DIR/dropck.rs:14:18 --> $DIR/dropck.rs:15:18
| |
LL | gen = || { LL | gen = || {
| -- capture occurs here | -- capture occurs here

View file

@ -1,5 +1,5 @@
error[E0621]: explicit lifetime required in the type of `x` error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/generator-region-requirements.rs:15:51 --> $DIR/generator-region-requirements.rs:16:51
| |
LL | fn dangle(x: &mut i32) -> &'static mut i32 { LL | fn dangle(x: &mut i32) -> &'static mut i32 {
| -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32` | -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32`

View file

@ -1,5 +1,5 @@
error[E0621]: explicit lifetime required in the type of `x` error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/generator-region-requirements.rs:15:51 --> $DIR/generator-region-requirements.rs:16:51
| |
LL | fn dangle(x: &mut i32) -> &'static mut i32 { LL | fn dangle(x: &mut i32) -> &'static mut i32 {
| -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32` | -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32`

View file

@ -4,6 +4,7 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
#![cfg_attr(nll, feature(nll))] #![cfg_attr(nll, feature(nll))]
use std::ops::{Generator, GeneratorState}; use std::ops::{Generator, GeneratorState};
use std::pin::Pin;
fn dangle(x: &mut i32) -> &'static mut i32 { fn dangle(x: &mut i32) -> &'static mut i32 {
let mut g = || { let mut g = || {
@ -11,7 +12,7 @@ fn dangle(x: &mut i32) -> &'static mut i32 {
x x
}; };
loop { loop {
match unsafe { g.resume() } { match Pin::new(&mut g).resume() {
GeneratorState::Complete(c) => return c, GeneratorState::Complete(c) => return c,
//[nll]~^ ERROR explicit lifetime required //[nll]~^ ERROR explicit lifetime required
//[ast]~^^ ERROR explicit lifetime required //[ast]~^^ ERROR explicit lifetime required

View file

@ -1,5 +1,5 @@
error[E0521]: borrowed data escapes outside of generator error[E0521]: borrowed data escapes outside of generator
--> $DIR/ref-escapes-but-not-over-yield.rs:14:9 --> $DIR/ref-escapes-but-not-over-yield.rs:11:9
| |
LL | let mut a = &3; LL | let mut a = &3;
| ----- `a` is declared here, outside of the generator body | ----- `a` is declared here, outside of the generator body

View file

@ -1,7 +1,4 @@
#![feature(generators, generator_trait)] #![feature(generators)]
use std::ops::{GeneratorState, Generator};
use std::cell::Cell;
fn foo(x: &i32) { fn foo(x: &i32) {
// In this case, a reference to `b` escapes the generator, but not // In this case, a reference to `b` escapes the generator, but not

View file

@ -1,5 +1,5 @@
error[E0597]: `b` does not live long enough error[E0597]: `b` does not live long enough
--> $DIR/ref-escapes-but-not-over-yield.rs:14:14 --> $DIR/ref-escapes-but-not-over-yield.rs:11:14
| |
LL | a = &b; LL | a = &b;
| ^ borrowed value does not live long enough | ^ borrowed value does not live long enough

View file

@ -1,6 +1,7 @@
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin;
fn main() { fn main() {
let s = String::from("foo"); let s = String::from("foo");
@ -8,6 +9,6 @@ fn main() {
//~^ ERROR the size for values of type //~^ ERROR the size for values of type
yield s[..]; yield s[..];
}; };
unsafe { gen.resume(); } Pin::new(&mut gen).resume();
//~^ ERROR the size for values of type //~^ ERROR the size for values of type
} }

View file

@ -1,5 +1,5 @@
error[E0277]: the size for values of type `str` cannot be known at compilation time error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/sized-yield.rs:7:26 --> $DIR/sized-yield.rs:8:26
| |
LL | let mut gen = move || { LL | let mut gen = move || {
| __________________________^ | __________________________^
@ -13,10 +13,10 @@ LL | | };
= note: the yield type of a generator must have a statically known size = note: the yield type of a generator must have a statically known size
error[E0277]: the size for values of type `str` cannot be known at compilation time error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/sized-yield.rs:11:17 --> $DIR/sized-yield.rs:12:23
| |
LL | unsafe { gen.resume(); } LL | Pin::new(&mut gen).resume();
| ^^^^^^ doesn't have a size known at compile-time | ^^^^^^ doesn't have a size known at compile-time
| |
= help: the trait `std::marker::Sized` is not implemented for `str` = help: the trait `std::marker::Sized` is not implemented for `str`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>

View file

@ -1,5 +1,5 @@
error[E0626]: borrow may still be in use when generator yields error[E0626]: borrow may still be in use when generator yields
--> $DIR/yield-while-iterating.rs:12:18 --> $DIR/yield-while-iterating.rs:13:18
| |
LL | for p in &x { //~ ERROR LL | for p in &x { //~ ERROR
| ^^ | ^^
@ -7,7 +7,7 @@ LL | yield();
| ------- possible yield occurs here | ------- possible yield occurs here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/yield-while-iterating.rs:57:20 --> $DIR/yield-while-iterating.rs:58:20
| |
LL | let mut b = || { LL | let mut b = || {
| -- mutable borrow occurs here | -- mutable borrow occurs here
@ -16,8 +16,8 @@ LL | for p in &mut x {
... ...
LL | println!("{}", x[0]); //~ ERROR LL | println!("{}", x[0]); //~ ERROR
| ^ immutable borrow occurs here | ^ immutable borrow occurs here
LL | b.resume(); LL | Pin::new(&mut b).resume();
| - mutable borrow later used here | ------ mutable borrow later used here
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -2,6 +2,7 @@
use std::ops::{GeneratorState, Generator}; use std::ops::{GeneratorState, Generator};
use std::cell::Cell; use std::cell::Cell;
use std::pin::Pin;
fn yield_during_iter_owned_data(x: Vec<i32>) { fn yield_during_iter_owned_data(x: Vec<i32>) {
// The generator owns `x`, so we error out when yielding with a // The generator owns `x`, so we error out when yielding with a
@ -33,7 +34,7 @@ fn yield_during_iter_borrowed_slice_2() {
println!("{:?}", x); println!("{:?}", x);
} }
unsafe fn yield_during_iter_borrowed_slice_3() { fn yield_during_iter_borrowed_slice_3() {
// OK to take a mutable ref to `x` and yield // OK to take a mutable ref to `x` and yield
// up pointers from it: // up pointers from it:
let mut x = vec![22_i32]; let mut x = vec![22_i32];
@ -42,10 +43,10 @@ unsafe fn yield_during_iter_borrowed_slice_3() {
yield p; yield p;
} }
}; };
b.resume(); Pin::new(&mut b).resume();
} }
unsafe fn yield_during_iter_borrowed_slice_4() { fn yield_during_iter_borrowed_slice_4() {
// ...but not OK to do that while reading // ...but not OK to do that while reading
// from `x` too // from `x` too
let mut x = vec![22_i32]; let mut x = vec![22_i32];
@ -55,10 +56,10 @@ unsafe fn yield_during_iter_borrowed_slice_4() {
} }
}; };
println!("{}", x[0]); //~ ERROR println!("{}", x[0]); //~ ERROR
b.resume(); Pin::new(&mut b).resume();
} }
unsafe fn yield_during_range_iter() { fn yield_during_range_iter() {
// Should be OK. // Should be OK.
let mut b = || { let mut b = || {
let v = vec![1,2,3]; let v = vec![1,2,3];
@ -68,7 +69,7 @@ unsafe fn yield_during_range_iter() {
yield x; yield x;
} }
}; };
b.resume(); Pin::new(&mut b).resume();
} }
fn main() { } fn main() { }

View file

@ -1,5 +1,5 @@
error[E0626]: borrow may still be in use when generator yields error[E0626]: borrow may still be in use when generator yields
--> $DIR/yield-while-iterating.rs:12:19 --> $DIR/yield-while-iterating.rs:13:19
| |
LL | for p in &x { //~ ERROR LL | for p in &x { //~ ERROR
| ^ | ^
@ -7,7 +7,7 @@ LL | yield();
| ------- possible yield occurs here | ------- possible yield occurs here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/yield-while-iterating.rs:57:20 --> $DIR/yield-while-iterating.rs:58:20
| |
LL | let mut b = || { LL | let mut b = || {
| -- mutable borrow occurs here | -- mutable borrow occurs here
@ -16,7 +16,7 @@ LL | for p in &mut x {
... ...
LL | println!("{}", x[0]); //~ ERROR LL | println!("{}", x[0]); //~ ERROR
| ^ immutable borrow occurs here | ^ immutable borrow occurs here
LL | b.resume(); LL | Pin::new(&mut b).resume();
LL | } LL | }
| - mutable borrow ends here | - mutable borrow ends here

View file

@ -4,8 +4,9 @@
use std::ops::{GeneratorState, Generator}; use std::ops::{GeneratorState, Generator};
use std::cell::Cell; use std::cell::Cell;
use std::pin::Pin;
unsafe fn borrow_local_inline() { fn borrow_local_inline() {
// Not OK to yield with a borrow of a temporary. // Not OK to yield with a borrow of a temporary.
// //
// (This error occurs because the region shows up in the type of // (This error occurs because the region shows up in the type of
@ -17,10 +18,10 @@ unsafe fn borrow_local_inline() {
yield(); yield();
println!("{}", a); println!("{}", a);
}; };
b.resume(); Pin::new(&mut b).resume();
} }
unsafe fn borrow_local_inline_done() { fn borrow_local_inline_done() {
// No error here -- `a` is not in scope at the point of `yield`. // No error here -- `a` is not in scope at the point of `yield`.
let mut b = move || { let mut b = move || {
{ {
@ -28,10 +29,10 @@ unsafe fn borrow_local_inline_done() {
} }
yield(); yield();
}; };
b.resume(); Pin::new(&mut b).resume();
} }
unsafe fn borrow_local() { fn borrow_local() {
// Not OK to yield with a borrow of a temporary. // Not OK to yield with a borrow of a temporary.
// //
// (This error occurs because the region shows up in the type of // (This error occurs because the region shows up in the type of
@ -46,7 +47,7 @@ unsafe fn borrow_local() {
println!("{}", b); println!("{}", b);
} }
}; };
b.resume(); Pin::new(&mut b).resume();
} }
fn main() { } fn main() { }

View file

@ -1,5 +1,5 @@
error[E0626]: borrow may still be in use when generator yields (Ast) error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/yield-while-local-borrowed.rs:14:22 --> $DIR/yield-while-local-borrowed.rs:15:22
| |
LL | let a = &mut 3; LL | let a = &mut 3;
| ^ | ^
@ -8,7 +8,7 @@ LL | yield();
| ------- possible yield occurs here | ------- possible yield occurs here
error[E0626]: borrow may still be in use when generator yields (Ast) error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/yield-while-local-borrowed.rs:42:22 --> $DIR/yield-while-local-borrowed.rs:43:22
| |
LL | let b = &a; LL | let b = &a;
| ^ | ^
@ -17,7 +17,7 @@ LL | yield();
| ------- possible yield occurs here | ------- possible yield occurs here
error[E0626]: borrow may still be in use when generator yields (Mir) error[E0626]: borrow may still be in use when generator yields (Mir)
--> $DIR/yield-while-local-borrowed.rs:14:17 --> $DIR/yield-while-local-borrowed.rs:15:17
| |
LL | let a = &mut 3; LL | let a = &mut 3;
| ^^^^^^ | ^^^^^^
@ -26,7 +26,7 @@ LL | yield();
| ------- possible yield occurs here | ------- possible yield occurs here
error[E0626]: borrow may still be in use when generator yields (Mir) error[E0626]: borrow may still be in use when generator yields (Mir)
--> $DIR/yield-while-local-borrowed.rs:42:21 --> $DIR/yield-while-local-borrowed.rs:43:21
| |
LL | let b = &a; LL | let b = &a;
| ^^ | ^^

View file

@ -1,5 +1,5 @@
error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
--> $DIR/yield-while-ref-reborrowed.rs:35:20 --> $DIR/yield-while-ref-reborrowed.rs:36:20
| |
LL | let mut b = || { LL | let mut b = || {
| -- generator construction occurs here | -- generator construction occurs here
@ -8,8 +8,8 @@ LL | let a = &mut *x;
... ...
LL | println!("{}", x); //~ ERROR LL | println!("{}", x); //~ ERROR
| ^ second borrow occurs here | ^ second borrow occurs here
LL | b.resume(); LL | Pin::new(&mut b).resume();
| - first borrow later used here | ------ first borrow later used here
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,8 +2,9 @@
use std::ops::{GeneratorState, Generator}; use std::ops::{GeneratorState, Generator};
use std::cell::Cell; use std::cell::Cell;
use std::pin::Pin;
unsafe fn reborrow_shared_ref(x: &i32) { fn reborrow_shared_ref(x: &i32) {
// This is OK -- we have a borrow live over the yield, but it's of // This is OK -- we have a borrow live over the yield, but it's of
// data that outlives the generator. // data that outlives the generator.
let mut b = move || { let mut b = move || {
@ -11,10 +12,10 @@ unsafe fn reborrow_shared_ref(x: &i32) {
yield(); yield();
println!("{}", a); println!("{}", a);
}; };
b.resume(); Pin::new(&mut b).resume();
} }
unsafe fn reborrow_mutable_ref(x: &mut i32) { fn reborrow_mutable_ref(x: &mut i32) {
// This is OK -- we have a borrow live over the yield, but it's of // This is OK -- we have a borrow live over the yield, but it's of
// data that outlives the generator. // data that outlives the generator.
let mut b = move || { let mut b = move || {
@ -22,10 +23,10 @@ unsafe fn reborrow_mutable_ref(x: &mut i32) {
yield(); yield();
println!("{}", a); println!("{}", a);
}; };
b.resume(); Pin::new(&mut b).resume();
} }
unsafe fn reborrow_mutable_ref_2(x: &mut i32) { fn reborrow_mutable_ref_2(x: &mut i32) {
// ...but not OK to go on using `x`. // ...but not OK to go on using `x`.
let mut b = || { let mut b = || {
let a = &mut *x; let a = &mut *x;
@ -33,7 +34,7 @@ unsafe fn reborrow_mutable_ref_2(x: &mut i32) {
println!("{}", a); println!("{}", a);
}; };
println!("{}", x); //~ ERROR println!("{}", x); //~ ERROR
b.resume(); Pin::new(&mut b).resume();
} }
fn main() { } fn main() { }

View file

@ -1,5 +1,5 @@
error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
--> $DIR/yield-while-ref-reborrowed.rs:35:20 --> $DIR/yield-while-ref-reborrowed.rs:36:20
| |
LL | let mut b = || { LL | let mut b = || {
| -- closure construction occurs here | -- closure construction occurs here
@ -8,7 +8,7 @@ LL | let a = &mut *x;
... ...
LL | println!("{}", x); //~ ERROR LL | println!("{}", x); //~ ERROR
| ^ borrow occurs here | ^ borrow occurs here
LL | b.resume(); LL | Pin::new(&mut b).resume();
LL | } LL | }
| - borrow from closure ends here | - borrow from closure ends here

View file

@ -1,23 +1,23 @@
#![allow(unused_mut)] #![allow(unused_mut)]
#![feature(generators, generator_trait)] #![feature(generators, generator_trait)]
use std::marker::Unpin;
use std::ops::Generator; use std::ops::Generator;
use std::ops::GeneratorState::Yielded; use std::ops::GeneratorState::Yielded;
use std::pin::Pin;
pub struct GenIter<G>(G); pub struct GenIter<G>(G);
impl <G> Iterator for GenIter<G> impl <G> Iterator for GenIter<G>
where where
G: Generator, G: Generator + Unpin,
{ {
type Item = G::Yield; type Item = G::Yield;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
unsafe { match Pin::new(&mut self.0).resume() {
match self.0.resume() { Yielded(y) => Some(y),
Yielded(y) => Some(y), _ => None
_ => None
}
} }
} }
} }