Skip to content

Commit 418dd64

Browse files
committed
test more generator resume things
1 parent d208a5f commit 418dd64

File tree

2 files changed

+138
-18
lines changed

2 files changed

+138
-18
lines changed

tests/run-pass/generator.rs

Lines changed: 137 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
11
#![feature(generators, generator_trait, never_type)]
22

3-
use std::ops::{GeneratorState, Generator};
3+
use std::panic::{catch_unwind, AssertUnwindSafe};
4+
use std::ops::{GeneratorState::{self, *}, Generator};
45
use std::pin::Pin;
6+
use std::sync::atomic::{AtomicUsize, Ordering};
7+
use std::fmt::Debug;
58

6-
fn finish<T>(mut amt: usize, mut t: T) -> T::Return
7-
where T: Generator<Yield = usize>
8-
{
9-
// We are not moving the `t` around until it gets dropped, so this is okay.
10-
let mut t = unsafe { Pin::new_unchecked(&mut t) };
11-
loop {
12-
match t.as_mut().resume(()) {
13-
GeneratorState::Yielded(y) => amt -= y,
14-
GeneratorState::Complete(ret) => {
15-
assert_eq!(amt, 0);
16-
return ret
9+
fn basic() {
10+
fn finish<T>(mut amt: usize, mut t: T) -> T::Return
11+
where T: Generator<Yield = usize>
12+
{
13+
// We are not moving the `t` around until it gets dropped, so this is okay.
14+
let mut t = unsafe { Pin::new_unchecked(&mut t) };
15+
loop {
16+
match t.as_mut().resume(()) {
17+
GeneratorState::Yielded(y) => amt -= y,
18+
GeneratorState::Complete(ret) => {
19+
assert_eq!(amt, 0);
20+
return ret
21+
}
1722
}
1823
}
1924
}
20-
}
2125

22-
enum Never {}
23-
fn never() -> Never {
24-
panic!()
25-
}
26+
enum Never {}
27+
fn never() -> Never {
28+
panic!()
29+
}
2630

27-
fn main() {
2831
finish(1, || yield 1);
2932

3033
finish(3, || {
@@ -94,3 +97,119 @@ fn main() {
9497
let _x: (String, !) = (String::new(), { yield 2; return });
9598
});
9699
}
100+
101+
fn smoke_resume_arg() {
102+
fn drain<G: Generator<R, Yield = Y> + Unpin, R, Y>(
103+
gen: &mut G,
104+
inout: Vec<(R, GeneratorState<Y, G::Return>)>,
105+
) where
106+
Y: Debug + PartialEq,
107+
G::Return: Debug + PartialEq,
108+
{
109+
let mut gen = Pin::new(gen);
110+
111+
for (input, out) in inout {
112+
assert_eq!(gen.as_mut().resume(input), out);
113+
}
114+
}
115+
116+
static DROPS: AtomicUsize = AtomicUsize::new(0);
117+
118+
#[derive(Debug, PartialEq)]
119+
struct DropMe;
120+
121+
impl Drop for DropMe {
122+
fn drop(&mut self) {
123+
DROPS.fetch_add(1, Ordering::SeqCst);
124+
}
125+
}
126+
127+
fn expect_drops<T>(expected_drops: usize, f: impl FnOnce() -> T) -> T {
128+
DROPS.store(0, Ordering::SeqCst);
129+
130+
let res = f();
131+
132+
let actual_drops = DROPS.load(Ordering::SeqCst);
133+
assert_eq!(actual_drops, expected_drops);
134+
res
135+
}
136+
137+
drain(
138+
&mut |mut b| {
139+
while b != 0 {
140+
b = yield (b + 1);
141+
}
142+
-1
143+
},
144+
vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))],
145+
);
146+
147+
expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))]));
148+
149+
expect_drops(6, || {
150+
drain(
151+
&mut |a| yield yield a,
152+
vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))],
153+
)
154+
});
155+
156+
#[allow(unreachable_code)]
157+
expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))]));
158+
159+
expect_drops(2, || {
160+
drain(
161+
&mut |a: DropMe| {
162+
if false { yield () } else { a }
163+
},
164+
vec![(DropMe, Complete(DropMe))],
165+
)
166+
});
167+
168+
expect_drops(4, || {
169+
drain(
170+
#[allow(unused_assignments, unused_variables)]
171+
&mut |mut a: DropMe| {
172+
a = yield;
173+
a = yield;
174+
a = yield;
175+
},
176+
vec![
177+
(DropMe, Yielded(())),
178+
(DropMe, Yielded(())),
179+
(DropMe, Yielded(())),
180+
(DropMe, Complete(())),
181+
],
182+
)
183+
});
184+
}
185+
186+
fn panic_drop_resume() {
187+
static DROP: AtomicUsize = AtomicUsize::new(0);
188+
189+
struct Dropper {}
190+
191+
impl Drop for Dropper {
192+
fn drop(&mut self) {
193+
DROP.fetch_add(1, Ordering::SeqCst);
194+
}
195+
}
196+
197+
let mut gen = |_arg| {
198+
if true {
199+
panic!();
200+
}
201+
yield ();
202+
};
203+
let mut gen = Pin::new(&mut gen);
204+
205+
assert_eq!(DROP.load(Ordering::Acquire), 0);
206+
let res = catch_unwind(AssertUnwindSafe(|| gen.as_mut().resume(Dropper {})));
207+
assert!(res.is_err());
208+
assert_eq!(DROP.load(Ordering::Acquire), 1);
209+
}
210+
211+
fn main() {
212+
basic();
213+
smoke_resume_arg();
214+
panic_drop_resume();
215+
}

tests/run-pass/generator.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
thread 'main' panicked at 'explicit panic', $DIR/generator.rs:199:13

0 commit comments

Comments
 (0)