Propagate bounds from generators

This commit is contained in:
Matthew Jasper 2018-10-12 15:16:29 +01:00
parent 121320d523
commit ef1a40d5fe
6 changed files with 57 additions and 19 deletions

View File

@ -1268,7 +1268,7 @@ pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> {
tcx: TyCtxt<'_, 'gcx, 'tcx>, tcx: TyCtxt<'_, 'gcx, 'tcx>,
location: Location, location: Location,
closure_def_id: DefId, closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'tcx>, closure_substs: &'tcx ty::subst::Substs<'tcx>,
) -> Vec<QueryRegionConstraint<'tcx>>; ) -> Vec<QueryRegionConstraint<'tcx>>;
fn subst_closure_mapping<T>( fn subst_closure_mapping<T>(
@ -1299,23 +1299,19 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
tcx: TyCtxt<'_, 'gcx, 'tcx>, tcx: TyCtxt<'_, 'gcx, 'tcx>,
location: Location, location: Location,
closure_def_id: DefId, closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'tcx>, closure_substs: &'tcx ty::subst::Substs<'tcx>,
) -> Vec<QueryRegionConstraint<'tcx>> { ) -> Vec<QueryRegionConstraint<'tcx>> {
debug!( debug!(
"apply_requirements(location={:?}, closure_def_id={:?}, closure_substs={:?})", "apply_requirements(location={:?}, closure_def_id={:?}, closure_substs={:?})",
location, closure_def_id, closure_substs location, closure_def_id, closure_substs
); );
// Get Tu. // Extract the values of the free regions in `closure_substs`
let user_closure_ty = tcx.mk_closure(closure_def_id, closure_substs);
debug!("apply_requirements: user_closure_ty={:?}", user_closure_ty);
// Extract the values of the free regions in `user_closure_ty`
// into a vector. These are the regions that we will be // into a vector. These are the regions that we will be
// relating to one another. // relating to one another.
let closure_mapping = &UniversalRegions::closure_mapping( let closure_mapping = &UniversalRegions::closure_mapping(
tcx, tcx,
user_closure_ty, closure_substs,
self.num_external_vids, self.num_external_vids,
tcx.closure_base_def_id(closure_def_id), tcx.closure_base_def_id(closure_def_id),
); );

View File

@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::traits::{ObligationCause, PredicateObligations};
use rustc::ty::fold::TypeFoldable; use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{Subst, UnpackedKind}; use rustc::ty::subst::{Subst, Substs, UnpackedKind};
use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use std::rc::Rc; use std::rc::Rc;
use std::{fmt, iter}; use std::{fmt, iter};
@ -2075,12 +2075,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
// desugaring. A closure gets desugared to a struct, and // desugaring. A closure gets desugared to a struct, and
// these extra requirements are basically like where // these extra requirements are basically like where
// clauses on the struct. // clauses on the struct.
AggregateKind::Closure(def_id, substs) => { AggregateKind::Closure(def_id, ty::ClosureSubsts { substs })
self.prove_closure_bounds(tcx, *def_id, *substs, location) | AggregateKind::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
} self.prove_closure_bounds(tcx, *def_id, substs, location)
AggregateKind::Generator(def_id, substs, _) => {
tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
} }
AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
@ -2096,7 +2093,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
&mut self, &mut self,
tcx: TyCtxt<'a, 'gcx, 'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>,
def_id: DefId, def_id: DefId,
substs: ty::ClosureSubsts<'tcx>, substs: &'tcx Substs<'tcx>,
location: Location, location: Location,
) -> ty::InstantiatedPredicates<'tcx> { ) -> ty::InstantiatedPredicates<'tcx> {
if let Some(closure_region_requirements) = if let Some(closure_region_requirements) =
@ -2155,7 +2152,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
); );
} }
tcx.predicates_of(def_id).instantiate(tcx, substs.substs) tcx.predicates_of(def_id).instantiate(tcx, substs)
} }
fn prove_trait_ref( fn prove_trait_ref(

View File

@ -232,13 +232,13 @@ impl<'tcx> UniversalRegions<'tcx> {
/// `V[1]: V[2]`. /// `V[1]: V[2]`.
pub fn closure_mapping( pub fn closure_mapping(
tcx: TyCtxt<'_, '_, 'tcx>, tcx: TyCtxt<'_, '_, 'tcx>,
closure_ty: Ty<'tcx>, closure_substs: &'tcx Substs<'tcx>,
expected_num_vars: usize, expected_num_vars: usize,
closure_base_def_id: DefId, closure_base_def_id: DefId,
) -> IndexVec<RegionVid, ty::Region<'tcx>> { ) -> IndexVec<RegionVid, ty::Region<'tcx>> {
let mut region_mapping = IndexVec::with_capacity(expected_num_vars); let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
region_mapping.push(tcx.types.re_static); region_mapping.push(tcx.types.re_static);
tcx.for_each_free_region(&closure_ty, |fr| { tcx.for_each_free_region(&closure_substs, |fr| {
region_mapping.push(fr); region_mapping.push(fr);
}); });

View File

@ -0,0 +1,12 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/generator-region-requirements.rs:15:51
|
LL | fn dangle(x: &mut i32) -> &'static mut i32 {
| -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32`
...
LL | GeneratorState::Complete(c) => return c,
| ^ lifetime `'static` required
error: aborting due to previous error
For more information about this error, try `rustc --explain E0621`.

View File

@ -0,0 +1,12 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/generator-region-requirements.rs:11:9
|
LL | fn dangle(x: &mut i32) -> &'static mut i32 {
| -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32`
...
LL | x
| ^ lifetime `'static` required
error: aborting due to previous error
For more information about this error, try `rustc --explain E0621`.

View File

@ -0,0 +1,21 @@
// revisions: ast nll
// ignore-compare-mode-nll
#![feature(generators, generator_trait)]
#![cfg_attr(nll, feature(nll))]
use std::ops::{Generator, GeneratorState};
fn dangle(x: &mut i32) -> &'static mut i32 {
let mut g = || {
yield;
x
};
loop {
match unsafe { g.resume() } {
GeneratorState::Complete(c) => return c,
GeneratorState::Yielded(_) => (),
}
}
}
fn main() {}