add Yield and Return type into generator

This commit is contained in:
Niko Matsakis 2017-11-09 15:07:39 -05:00
parent 7c609eb090
commit 7010d8cf51
3 changed files with 56 additions and 9 deletions

View file

@ -256,6 +256,17 @@ pub enum TypeVariants<'tcx> {
/// closure C wind up influencing the decisions we ought to make for
/// closure C (which would then require fixed point iteration to
/// handle). Plus it fixes an ICE. :P
///
/// ## Generators
///
/// Perhaps surprisingly, `ClosureSubsts` are also used for
/// generators. In that case, what is written above is only half-true
/// -- the set of type parameters is similar, but the role of CK and
/// CS are different. CK represents the "yield type" and CS
/// represents the "return type" of the generator.
///
/// It'd be nice to split this struct into ClosureSubsts and
/// GeneratorSubsts, I believe. -nmatsakis
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct ClosureSubsts<'tcx> {
/// Lifetime and type parameters from the enclosing function,
@ -310,6 +321,31 @@ impl<'tcx> ClosureSubsts<'tcx> {
pub fn closure_sig_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
self.split(def_id, tcx).closure_sig_ty
}
/// Returns the type representing the yield type of the generator.
pub fn generator_yield_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
self.closure_kind_ty(def_id, tcx)
}
/// Returns the type representing the return type of the generator.
pub fn generator_return_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
self.closure_sig_ty(def_id, tcx)
}
/// Return the "generator signature", which consists of its yield
/// and return types.
///
/// NB. We treat this as a `PolyGenSig`, but since it only
/// contains associated types of the generator, at present it
/// never binds any regions.
pub fn generator_poly_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> PolyGenSig<'tcx> {
ty::Binder(
ty::GenSig {
yield_ty: self.generator_yield_ty(def_id, tcx),
return_ty: self.generator_return_ty(def_id, tcx),
}
)
}
}
impl<'tcx> ClosureSubsts<'tcx> {

View file

@ -10,7 +10,7 @@
//! Code for type-checking closure expressions.
use super::{check_fn, Expectation, FnCtxt};
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use astconv::AstConv;
use rustc::hir::def_id::DefId;
@ -79,7 +79,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("check_closure: ty_of_closure returns {:?}", liberated_sig);
let interior = check_fn(
let generator_types = check_fn(
self,
self.param_env,
liberated_sig,
@ -106,13 +106,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let substs = ty::ClosureSubsts { substs };
let closure_type = self.tcx.mk_closure(expr_def_id, substs);
if let Some(interior) = interior {
if let Some(GeneratorTypes { yield_ty, interior }) = generator_types {
self.demand_eqtype(expr.span,
ty::ClosureKind::FnOnce.to_ty(self.tcx),
substs.closure_kind_ty(expr_def_id, self.tcx));
yield_ty,
substs.generator_yield_ty(expr_def_id, self.tcx));
self.demand_eqtype(expr.span,
self.tcx.types.char, // for generator, use some bogus type
substs.closure_sig_ty(expr_def_id, self.tcx));
liberated_sig.output(),
substs.generator_return_ty(expr_def_id, self.tcx));
return self.tcx.mk_generator(expr_def_id, substs, interior);
}

View file

@ -972,6 +972,17 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
_: hir::BodyId, _: Span, _: ast::NodeId) { }
}
/// When `check_fn` is invoked on a generator (i.e., a body that
/// includes yield), it returns back some information about the yield
/// points.
struct GeneratorTypes<'tcx> {
/// Type of value that is yielded.
yield_ty: ty::Ty<'tcx>,
/// Types that are captured (see `GeneratorInterior` for more).
interior: ty::GeneratorInterior<'tcx>
}
/// Helper used for fns and closures. Does the grungy work of checking a function
/// body and returns the function context used for that purpose, since in the case of a fn item
/// there is still a bit more to do.
@ -985,7 +996,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId,
body: &'gcx hir::Body,
can_be_generator: bool)
-> (FnCtxt<'a, 'gcx, 'tcx>, Option<ty::GeneratorInterior<'tcx>>)
-> (FnCtxt<'a, 'gcx, 'tcx>, Option<GeneratorTypes<'tcx>>)
{
let mut fn_sig = fn_sig.clone();
@ -1047,7 +1058,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
inherited.tables.borrow_mut().generator_interiors_mut().insert(fn_hir_id, interior);
Some(interior)
Some(GeneratorTypes { yield_ty: gen_sig.yield_ty, interior: interior })
} else {
inherited.tables.borrow_mut().generator_sigs_mut().insert(fn_hir_id, None);
None