diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2017-11-12 05:25:13 -0500 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2017-12-04 08:51:13 -0500 |
| commit | c45307fae1f261eac006816329780a7a01b2d0dc (patch) | |
| tree | 83ea1dde39a24d6c6b79c7c5480b2156b8253d27 | |
| parent | 1f33145ae91cbe095616c92ace63c93b61e5b4e9 (diff) | |
| download | rust-c45307fae1f261eac006816329780a7a01b2d0dc.tar.gz rust-c45307fae1f261eac006816329780a7a01b2d0dc.zip | |
extract the code to create `OutlivesBounds` into its own module
Now it can be reused by the NLL code.
| -rw-r--r-- | src/librustc/infer/outlives/env.rs | 105 | ||||
| -rw-r--r-- | src/librustc/infer/outlives/implied_bounds.rs | 103 |
2 files changed, 110 insertions, 98 deletions
diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs index 9f00fc78cc0..43e782ac130 100644 --- a/src/librustc/infer/outlives/env.rs +++ b/src/librustc/infer/outlives/env.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::{InferCtxt, GenericKind}; +use infer::{GenericKind, InferCtxt}; use infer::outlives::free_region_map::FreeRegionMap; -use infer::outlives::implied_bounds::ImpliedBound; +use infer::outlives::implied_bounds::{self, OutlivesBound}; use ty::{self, Ty}; use syntax::ast; @@ -50,7 +50,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> { region_bound_pairs: vec![], }; - env.init_free_regions_from_predicates(); + env.add_outlives_bounds(None, implied_bounds::explicit_outlives_bounds(param_env)); env } @@ -144,65 +144,54 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> { for &ty in fn_sig_tys { let ty = infcx.resolve_type_vars_if_possible(&ty); debug!("add_implied_bounds: ty = {}", ty); - let implied_bounds = infcx.implied_bounds(self.param_env, body_id, ty, span); - - // But also record other relationships, such as `T:'x`, - // that don't go into the free-region-map but which we use - // here. - for implication in implied_bounds { - debug!("add_implied_bounds: implication={:?}", implication); - match implication { - ImpliedBound::RegionSubRegion( - r_a @ &ty::ReEarlyBound(_), - &ty::ReVar(vid_b), - ) | - ImpliedBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => { - infcx.add_given(r_a, vid_b); - } - ImpliedBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs - .push((r_a, GenericKind::Param(param_b))); - } - ImpliedBound::RegionSubProjection(r_a, projection_b) => { - self.region_bound_pairs - .push((r_a, GenericKind::Projection(projection_b))); - } - ImpliedBound::RegionSubRegion(r_a, r_b) => { - // In principle, we could record (and take - // advantage of) every relationship here, but - // we are also free not to -- it simply means - // strictly less that we can successfully type - // check. Right now we only look for things - // relationships between free regions. (It may - // also be that we should revise our inference - // system to be more general and to make use - // of *every* relationship that arises here, - // but presently we do not.) - self.free_region_map.relate_regions(r_a, r_b); - } - } - } + let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); + self.add_outlives_bounds(Some(infcx), implied_bounds) } } - fn init_free_regions_from_predicates(&mut self) { - debug!("init_free_regions_from_predicates()"); - for predicate in self.param_env.caller_bounds { - debug!("init_free_regions_from_predicates: predicate={:?}", predicate); - match *predicate { - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::ConstEvaluatable(..) => { - // No region bounds here + /// Processes outlives bounds that are known to hold, whether from implied or other sources. + /// + /// The `infcx` parameter is optional; if the implied bounds may + /// contain inference variables, it should be supplied, in which + /// case we will register "givens" on the inference context. (See + /// `RegionConstraintData`.) + fn add_outlives_bounds<I>( + &mut self, + infcx: Option<&InferCtxt<'a, 'gcx, 'tcx>>, + outlives_bounds: I, + ) where + I: IntoIterator<Item = OutlivesBound<'tcx>>, + { + // But also record other relationships, such as `T:'x`, + // that don't go into the free-region-map but which we use + // here. + for outlives_bound in outlives_bounds { + debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound); + match outlives_bound { + OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b)) | + OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => { + infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b); + } + OutlivesBound::RegionSubParam(r_a, param_b) => { + self.region_bound_pairs + .push((r_a, GenericKind::Param(param_b))); + } + OutlivesBound::RegionSubProjection(r_a, projection_b) => { + self.region_bound_pairs + .push((r_a, GenericKind::Projection(projection_b))); } - ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { - self.free_region_map.relate_regions(r_b, r_a); + OutlivesBound::RegionSubRegion(r_a, r_b) => { + // In principle, we could record (and take + // advantage of) every relationship here, but + // we are also free not to -- it simply means + // strictly less that we can successfully type + // check. Right now we only look for things + // relationships between free regions. (It may + // also be that we should revise our inference + // system to be more general and to make use + // of *every* relationship that arises here, + // but presently we do not.) + self.free_region_map.relate_regions(r_a, r_b); } } } diff --git a/src/librustc/infer/outlives/implied_bounds.rs b/src/librustc/infer/outlives/implied_bounds.rs index 452ceddd7d6..8a562471ac5 100644 --- a/src/librustc/infer/outlives/implied_bounds.rs +++ b/src/librustc/infer/outlives/implied_bounds.rs @@ -16,28 +16,32 @@ use ty::{self, Ty, TypeFoldable}; use ty::outlives::Component; use ty::wf; -/// Implied bounds are region relationships that we deduce -/// automatically. The idea is that (e.g.) a caller must check that a -/// function's argument types are well-formed immediately before -/// calling that fn, and hence the *callee* can assume that its -/// argument types are well-formed. This may imply certain relationships -/// between generic parameters. For example: -/// -/// fn foo<'a,T>(x: &'a T) -/// -/// can only be called with a `'a` and `T` such that `&'a T` is WF. -/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. +/// Outlives bounds are relationships between generic parameters, +/// whether they both be regions (`'a: 'b`) or whether types are +/// involved (`T: 'a`). These relationships can be extracted from the +/// full set of predicates we understand or also from types (in which +/// case they are called implied bounds). They are fed to the +/// `OutlivesEnv` which in turn is supplied to the region checker and +/// other parts of the inference system. #[derive(Debug)] -pub enum ImpliedBound<'tcx> { +pub enum OutlivesBound<'tcx> { RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), RegionSubParam(ty::Region<'tcx>, ty::ParamTy), RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), } impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { - /// Compute the implied bounds that a callee/impl can assume based on - /// the fact that caller/projector has ensured that `ty` is WF. See - /// the `ImpliedBound` type for more details. + /// Implied bounds are region relationships that we deduce + /// automatically. The idea is that (e.g.) a caller must check that a + /// function's argument types are well-formed immediately before + /// calling that fn, and hence the *callee* can assume that its + /// argument types are well-formed. This may imply certain relationships + /// between generic parameters. For example: + /// + /// fn foo<'a,T>(x: &'a T) + /// + /// can only be called with a `'a` and `T` such that `&'a T` is WF. + /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. /// /// # Parameters /// @@ -48,13 +52,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// - `ty`, the type that we are supposed to assume is WF. /// - `span`, a span to use when normalizing, hopefully not important, /// might be useful if a `bug!` occurs. - pub fn implied_bounds( + pub fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId, ty: Ty<'tcx>, span: Span, - ) -> Vec<ImpliedBound<'tcx>> { + ) -> Vec<OutlivesBound<'tcx>> { let tcx = self.tcx; // Sometimes when we ask what it takes for T: WF, we get back that @@ -76,8 +80,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // than the ultimate set. (Note: normally there won't be // unresolved inference variables here anyway, but there might be // during typeck under some circumstances.) - let obligations = - wf::obligations(self, param_env, body_id, ty, span).unwrap_or(vec![]); + let obligations = wf::obligations(self, param_env, body_id, ty, span).unwrap_or(vec![]); // NB: All of these predicates *ought* to be easily proven // true. In fact, their correctness is (mostly) implied by @@ -105,7 +108,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { obligations .iter() .filter(|o| o.predicate.has_infer_types()) - .cloned()); + .cloned(), + ); // From the full set of obligations, just filter down to the // region relationships. @@ -125,25 +129,21 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { vec![] } - ty::Predicate::RegionOutlives(ref data) => { - match data.no_late_bound_regions() { - None => vec![], - Some(ty::OutlivesPredicate(r_a, r_b)) => { - vec![ImpliedBound::RegionSubRegion(r_b, r_a)] - } + ty::Predicate::RegionOutlives(ref data) => match data.no_late_bound_regions() { + None => vec![], + Some(ty::OutlivesPredicate(r_a, r_b)) => { + vec![OutlivesBound::RegionSubRegion(r_b, r_a)] } - } + }, - ty::Predicate::TypeOutlives(ref data) => { - match data.no_late_bound_regions() { - None => vec![], - Some(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = self.resolve_type_vars_if_possible(&ty_a); - let components = tcx.outlives_components(ty_a); - Self::implied_bounds_from_components(r_b, components) - } + ty::Predicate::TypeOutlives(ref data) => match data.no_late_bound_regions() { + None => vec![], + Some(ty::OutlivesPredicate(ty_a, r_b)) => { + let ty_a = self.resolve_type_vars_if_possible(&ty_a); + let components = tcx.outlives_components(ty_a); + Self::implied_bounds_from_components(r_b, components) } - } + }, } })); } @@ -165,17 +165,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { fn implied_bounds_from_components( sub_region: ty::Region<'tcx>, sup_components: Vec<Component<'tcx>>, - ) -> Vec<ImpliedBound<'tcx>> { + ) -> Vec<OutlivesBound<'tcx>> { sup_components .into_iter() .flat_map(|component| { match component { Component::Region(r) => - vec![ImpliedBound::RegionSubRegion(sub_region, r)], + vec![OutlivesBound::RegionSubRegion(sub_region, r)], Component::Param(p) => - vec![ImpliedBound::RegionSubParam(sub_region, p)], + vec![OutlivesBound::RegionSubParam(sub_region, p)], Component::Projection(p) => - vec![ImpliedBound::RegionSubProjection(sub_region, p)], + vec![OutlivesBound::RegionSubProjection(sub_region, p)], Component::EscapingProjection(_) => // If the projection has escaping regions, don't // try to infer any implied bounds even for its @@ -193,3 +193,26 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { .collect() } } + +pub fn explicit_outlives_bounds<'tcx>( + param_env: ty::ParamEnv<'tcx>, +) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx { + debug!("explicit_outlives_bounds()"); + param_env + .caller_bounds + .into_iter() + .filter_map(move |predicate| match predicate { + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::ClosureKind(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => None, + ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map( + |ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a), + ), + }) +} |
