Skip to content

Commit 70e8f64

Browse files
committed
Auto merge of #68524 - jonas-schievink:generator-resume-arguments, r=<try>
Generator Resume Arguments cc #43122 and #56974
2 parents 6d3f4e0 + 1738840 commit 70e8f64

File tree

79 files changed

+657
-242
lines changed

Some content is hidden

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

79 files changed

+657
-242
lines changed

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

+11-15
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ fn main() {
3737
return "foo"
3838
};
3939

40-
match Pin::new(&mut generator).resume() {
40+
match Pin::new(&mut generator).resume(()) {
4141
GeneratorState::Yielded(1) => {}
4242
_ => panic!("unexpected value from resume"),
4343
}
44-
match Pin::new(&mut generator).resume() {
44+
match Pin::new(&mut generator).resume(()) {
4545
GeneratorState::Complete("foo") => {}
4646
_ => panic!("unexpected value from resume"),
4747
}
@@ -71,9 +71,9 @@ fn main() {
7171
};
7272

7373
println!("1");
74-
Pin::new(&mut generator).resume();
74+
Pin::new(&mut generator).resume(());
7575
println!("3");
76-
Pin::new(&mut generator).resume();
76+
Pin::new(&mut generator).resume(());
7777
println!("5");
7878
}
7979
```
@@ -92,10 +92,10 @@ The `Generator` trait in `std::ops` currently looks like:
9292
# use std::ops::GeneratorState;
9393
# use std::pin::Pin;
9494
95-
pub trait Generator {
95+
pub trait Generator<R = ()> {
9696
type Yield;
9797
type Return;
98-
fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return>;
98+
fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState<Self::Yield, Self::Return>;
9999
}
100100
```
101101

@@ -152,10 +152,6 @@ closure-like semantics. Namely:
152152
* Whenever a generator is dropped it will drop all captured environment
153153
variables.
154154

155-
Note that unlike closures, generators at this time cannot take any arguments.
156-
That is, generators must always look like `|| { ... }`. This restriction may be
157-
lifted at a future date, the design is ongoing!
158-
159155
### Generators as state machines
160156

161157
In the compiler, generators are currently compiled as state machines. Each
@@ -179,8 +175,8 @@ fn main() {
179175
return ret
180176
};
181177

182-
Pin::new(&mut generator).resume();
183-
Pin::new(&mut generator).resume();
178+
Pin::new(&mut generator).resume(());
179+
Pin::new(&mut generator).resume(());
184180
}
185181
```
186182

@@ -205,7 +201,7 @@ fn main() {
205201
type Yield = i32;
206202
type Return = &'static str;
207203

208-
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<i32, &'static str> {
204+
fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState<i32, &'static str> {
209205
use std::mem;
210206
match mem::replace(&mut *self, __Generator::Done) {
211207
__Generator::Start(s) => {
@@ -228,8 +224,8 @@ fn main() {
228224
__Generator::Start(ret)
229225
};
230226

231-
Pin::new(&mut generator).resume();
232-
Pin::new(&mut generator).resume();
227+
Pin::new(&mut generator).resume(());
228+
Pin::new(&mut generator).resume(());
233229
}
234230
```
235231

src/liballoc/boxed.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@ impl<T: ?Sized> AsMut<T> for Box<T> {
11031103
#[stable(feature = "pin", since = "1.33.0")]
11041104
impl<T: ?Sized> Unpin for Box<T> {}
11051105

1106+
#[cfg(bootstrap)]
11061107
#[unstable(feature = "generator_trait", issue = "43122")]
11071108
impl<G: ?Sized + Generator + Unpin> Generator for Box<G> {
11081109
type Yield = G::Yield;
@@ -1113,6 +1114,7 @@ impl<G: ?Sized + Generator + Unpin> Generator for Box<G> {
11131114
}
11141115
}
11151116

1117+
#[cfg(bootstrap)]
11161118
#[unstable(feature = "generator_trait", issue = "43122")]
11171119
impl<G: ?Sized + Generator> Generator for Pin<Box<G>> {
11181120
type Yield = G::Yield;
@@ -1123,6 +1125,28 @@ impl<G: ?Sized + Generator> Generator for Pin<Box<G>> {
11231125
}
11241126
}
11251127

1128+
#[cfg(not(bootstrap))]
1129+
#[unstable(feature = "generator_trait", issue = "43122")]
1130+
impl<G: ?Sized + Generator<R> + Unpin, R> Generator<R> for Box<G> {
1131+
type Yield = G::Yield;
1132+
type Return = G::Return;
1133+
1134+
fn resume(mut self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
1135+
G::resume(Pin::new(&mut *self), arg)
1136+
}
1137+
}
1138+
1139+
#[cfg(not(bootstrap))]
1140+
#[unstable(feature = "generator_trait", issue = "43122")]
1141+
impl<G: ?Sized + Generator<R>, R> Generator<R> for Pin<Box<G>> {
1142+
type Yield = G::Yield;
1143+
type Return = G::Return;
1144+
1145+
fn resume(mut self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
1146+
G::resume((*self).as_mut(), arg)
1147+
}
1148+
}
1149+
11261150
#[stable(feature = "futures_api", since = "1.36.0")]
11271151
impl<F: ?Sized + Future + Unpin> Future for Box<F> {
11281152
type Output = F::Output;

src/libcore/ops/generator.rs

+31-4
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ pub enum GeneratorState<Y, R> {
5050
/// return "foo"
5151
/// };
5252
///
53-
/// match Pin::new(&mut generator).resume() {
53+
/// match Pin::new(&mut generator).resume(()) {
5454
/// GeneratorState::Yielded(1) => {}
5555
/// _ => panic!("unexpected return from resume"),
5656
/// }
57-
/// match Pin::new(&mut generator).resume() {
57+
/// match Pin::new(&mut generator).resume(()) {
5858
/// GeneratorState::Complete("foo") => {}
5959
/// _ => panic!("unexpected return from resume"),
6060
/// }
@@ -67,7 +67,7 @@ pub enum GeneratorState<Y, R> {
6767
#[lang = "generator"]
6868
#[unstable(feature = "generator_trait", issue = "43122")]
6969
#[fundamental]
70-
pub trait Generator {
70+
pub trait Generator<#[cfg(not(bootstrap))] R = ()> {
7171
/// The type of value this generator yields.
7272
///
7373
/// This associated type corresponds to the `yield` expression and the
@@ -110,9 +110,13 @@ 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-
fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return>;
113+
fn resume(
114+
self: Pin<&mut Self>,
115+
#[cfg(not(bootstrap))] arg: R,
116+
) -> GeneratorState<Self::Yield, Self::Return>;
114117
}
115118

119+
#[cfg(bootstrap)]
116120
#[unstable(feature = "generator_trait", issue = "43122")]
117121
impl<G: ?Sized + Generator> Generator for Pin<&mut G> {
118122
type Yield = G::Yield;
@@ -123,6 +127,7 @@ impl<G: ?Sized + Generator> Generator for Pin<&mut G> {
123127
}
124128
}
125129

130+
#[cfg(bootstrap)]
126131
#[unstable(feature = "generator_trait", issue = "43122")]
127132
impl<G: ?Sized + Generator + Unpin> Generator for &mut G {
128133
type Yield = G::Yield;
@@ -132,3 +137,25 @@ impl<G: ?Sized + Generator + Unpin> Generator for &mut G {
132137
G::resume(Pin::new(&mut *self))
133138
}
134139
}
140+
141+
#[cfg(not(bootstrap))]
142+
#[unstable(feature = "generator_trait", issue = "43122")]
143+
impl<G: ?Sized + Generator<R>, R> Generator<R> for Pin<&mut G> {
144+
type Yield = G::Yield;
145+
type Return = G::Return;
146+
147+
fn resume(mut self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
148+
G::resume((*self).as_mut(), arg)
149+
}
150+
}
151+
152+
#[cfg(not(bootstrap))]
153+
#[unstable(feature = "generator_trait", issue = "43122")]
154+
impl<G: ?Sized + Generator<R> + Unpin, R> Generator<R> for &mut G {
155+
type Yield = G::Yield;
156+
type Return = G::Return;
157+
158+
fn resume(mut self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
159+
G::resume(Pin::new(&mut *self), arg)
160+
}
161+
}

src/librustc/infer/opaque_types/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ where
744744

745745
substs.as_generator().return_ty(def_id, self.tcx).visit_with(self);
746746
substs.as_generator().yield_ty(def_id, self.tcx).visit_with(self);
747+
substs.as_generator().resume_ty(def_id, self.tcx).visit_with(self);
747748
}
748749
_ => {
749750
ty.super_visit_with(self);

src/librustc/mir/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,8 @@ pub enum TerminatorKind<'tcx> {
11201120
value: Operand<'tcx>,
11211121
/// Where to resume to.
11221122
resume: BasicBlock,
1123+
/// The place to store the resume argument in.
1124+
resume_arg: Place<'tcx>,
11231125
/// Cleanup to be done if the generator is dropped at this suspend point.
11241126
drop: Option<BasicBlock>,
11251127
},
@@ -2641,9 +2643,12 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
26412643
target,
26422644
unwind,
26432645
},
2644-
Yield { ref value, resume, drop } => {
2645-
Yield { value: value.fold_with(folder), resume: resume, drop: drop }
2646-
}
2646+
Yield { ref value, resume, ref resume_arg, drop } => Yield {
2647+
value: value.fold_with(folder),
2648+
resume,
2649+
resume_arg: resume_arg.fold_with(folder),
2650+
drop,
2651+
},
26472652
Call { ref func, ref args, ref destination, cleanup, from_hir_call } => {
26482653
let dest =
26492654
destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest));

src/librustc/mir/visit.rs

+6
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,14 @@ macro_rules! make_mir_visitor {
516516
TerminatorKind::Yield {
517517
value,
518518
resume: _,
519+
resume_arg,
519520
drop: _,
520521
} => {
522+
self.visit_place(
523+
resume_arg,
524+
PlaceContext::MutatingUse(MutatingUseContext::Store),
525+
source_location,
526+
);
521527
self.visit_operand(value, source_location);
522528
}
523529

src/librustc/traits/util.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,10 @@ pub fn generator_trait_ref_and_outputs(
643643
self_ty: Ty<'tcx>,
644644
sig: ty::PolyGenSig<'tcx>,
645645
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
646-
let trait_ref =
647-
ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[]) };
646+
let trait_ref = ty::TraitRef {
647+
def_id: fn_trait_def_id,
648+
substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]),
649+
};
648650
ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
649651
}
650652

src/librustc/ty/layout.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -2350,8 +2350,9 @@ impl<'tcx> ty::Instance<'tcx> {
23502350
]);
23512351
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
23522352

2353-
tcx.mk_fn_sig(iter::once(env_ty),
2354-
ret_ty,
2353+
tcx.mk_fn_sig(
2354+
[env_ty, sig.resume_ty].iter(),
2355+
&ret_ty,
23552356
false,
23562357
hir::Unsafety::Normal,
23572358
rustc_target::spec::abi::Abi::Rust

src/librustc/ty/structural_impls.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -598,8 +598,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> {
598598
impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> {
599599
type Lifted = ty::GenSig<'tcx>;
600600
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
601-
tcx.lift(&(self.yield_ty, self.return_ty))
602-
.map(|(yield_ty, return_ty)| ty::GenSig { yield_ty, return_ty })
601+
tcx.lift(&(self.resume_ty, self.yield_ty, self.return_ty))
602+
.map(|(resume_ty, yield_ty, return_ty)| ty::GenSig { resume_ty, yield_ty, return_ty })
603603
}
604604
}
605605

src/librustc/ty/sty.rs

+32-9
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,17 @@ static_assert_size!(TyKind<'_>, 24);
346346
/// ## Generators
347347
///
348348
/// Generators are handled similarly in `GeneratorSubsts`. The set of
349-
/// type parameters is similar, but the role of CK and CS are
350-
/// different. CK represents the "yield type" and CS represents the
351-
/// "return type" of the generator.
349+
/// type parameters is similar, but `CK` and `CS` are replaced by the
350+
/// following type parameters:
351+
///
352+
/// * `GS`: The generator's "resume type", which is the type of the
353+
/// argument passed to `resume`, and the type of `yield` expressions
354+
/// inside the generator.
355+
/// * `GY`: The "yield type", which is the type of values passed to
356+
/// `yield` inside the generator.
357+
/// * `GR`: The "return type", which is the type of value returned upon
358+
/// completion of the generator.
359+
/// * `GW`: The "generator witness".
352360
#[derive(Copy, Clone, Debug, TypeFoldable)]
353361
pub struct ClosureSubsts<'tcx> {
354362
/// Lifetime and type parameters from the enclosing function,
@@ -442,6 +450,7 @@ pub struct GeneratorSubsts<'tcx> {
442450
}
443451

444452
struct SplitGeneratorSubsts<'tcx> {
453+
resume_ty: Ty<'tcx>,
445454
yield_ty: Ty<'tcx>,
446455
return_ty: Ty<'tcx>,
447456
witness: Ty<'tcx>,
@@ -453,10 +462,11 @@ impl<'tcx> GeneratorSubsts<'tcx> {
453462
let generics = tcx.generics_of(def_id);
454463
let parent_len = generics.parent_count;
455464
SplitGeneratorSubsts {
456-
yield_ty: self.substs.type_at(parent_len),
457-
return_ty: self.substs.type_at(parent_len + 1),
458-
witness: self.substs.type_at(parent_len + 2),
459-
upvar_kinds: &self.substs[parent_len + 3..],
465+
resume_ty: self.substs.type_at(parent_len),
466+
yield_ty: self.substs.type_at(parent_len + 1),
467+
return_ty: self.substs.type_at(parent_len + 2),
468+
witness: self.substs.type_at(parent_len + 3),
469+
upvar_kinds: &self.substs[parent_len + 4..],
460470
}
461471
}
462472

@@ -485,6 +495,11 @@ impl<'tcx> GeneratorSubsts<'tcx> {
485495
})
486496
}
487497

498+
/// Returns the type representing the resume type of the generator.
499+
pub fn resume_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> {
500+
self.split(def_id, tcx).resume_ty
501+
}
502+
488503
/// Returns the type representing the yield type of the generator.
489504
pub fn yield_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> {
490505
self.split(def_id, tcx).yield_ty
@@ -505,10 +520,14 @@ impl<'tcx> GeneratorSubsts<'tcx> {
505520
ty::Binder::dummy(self.sig(def_id, tcx))
506521
}
507522

508-
/// Returns the "generator signature", which consists of its yield
523+
/// Returns the "generator signature", which consists of its resume, yield
509524
/// and return types.
510525
pub fn sig(self, def_id: DefId, tcx: TyCtxt<'_>) -> GenSig<'tcx> {
511-
ty::GenSig { yield_ty: self.yield_ty(def_id, tcx), return_ty: self.return_ty(def_id, tcx) }
526+
ty::GenSig {
527+
resume_ty: self.resume_ty(def_id, tcx),
528+
yield_ty: self.yield_ty(def_id, tcx),
529+
return_ty: self.return_ty(def_id, tcx),
530+
}
512531
}
513532
}
514533

@@ -1072,13 +1091,17 @@ impl<'tcx> ProjectionTy<'tcx> {
10721091

10731092
#[derive(Clone, Debug, TypeFoldable)]
10741093
pub struct GenSig<'tcx> {
1094+
pub resume_ty: Ty<'tcx>,
10751095
pub yield_ty: Ty<'tcx>,
10761096
pub return_ty: Ty<'tcx>,
10771097
}
10781098

10791099
pub type PolyGenSig<'tcx> = Binder<GenSig<'tcx>>;
10801100

10811101
impl<'tcx> PolyGenSig<'tcx> {
1102+
pub fn resume_ty(&self) -> ty::Binder<Ty<'tcx>> {
1103+
self.map_bound_ref(|sig| sig.resume_ty)
1104+
}
10821105
pub fn yield_ty(&self) -> ty::Binder<Ty<'tcx>> {
10831106
self.map_bound_ref(|sig| sig.yield_ty)
10841107
}

src/librustc_ast_lowering/expr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -688,12 +688,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
688688
) -> Option<hir::Movability> {
689689
match generator_kind {
690690
Some(hir::GeneratorKind::Gen) => {
691-
if !decl.inputs.is_empty() {
691+
if decl.inputs.len() > 1 {
692692
struct_span_err!(
693693
self.sess,
694694
fn_decl_span,
695695
E0628,
696-
"generators cannot have explicit parameters"
696+
"too many parameters for generator (expected 0 or 1 parameters)"
697697
)
698698
.emit();
699699
}

0 commit comments

Comments
 (0)