diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index c236fbc4f721..973568a67f03 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -111,7 +111,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( // Run the MIR type-checker. let liveness_map = NllLivenessMap::compute(&mir); let liveness = LivenessResults::compute(mir, &liveness_map); - let constraint_sets = type_check::type_check( + let (constraint_sets, universal_region_relations) = type_check::type_check( infcx, param_env, mir, @@ -155,6 +155,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( let mut regioncx = RegionInferenceContext::new( var_origins, universal_regions, + universal_region_relations, mir, outlives_constraints, type_tests, diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs index 88b34c767324..d3b4f0a0447a 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs @@ -33,7 +33,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .universal_regions .region_classification(region) .unwrap(); - let outlived_by = self.universal_regions.regions_outlived_by(region); + let outlived_by = self.universal_region_relations.regions_outlived_by(region); writeln!( out, "| {r:rw$} | {c:cw$} | {ob}", diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 9785a544a4dc..6281b5dd4b64 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -15,6 +15,7 @@ use borrow_check::nll::constraints::{ }; use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex}; use borrow_check::nll::type_check::Locations; +use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::region_constraints::{GenericKind, VarInfos}; @@ -80,8 +81,12 @@ pub struct RegionInferenceContext<'tcx> { type_tests: Vec>, /// Information about the universally quantified regions in scope - /// on this function and their (known) relations to one another. + /// on this function. universal_regions: Rc>, + + /// Information about how the universally quantified regions in + /// scope on this function relate to one another. + universal_region_relations: Rc>, } struct RegionDefinition<'tcx> { @@ -207,6 +212,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn new( var_infos: VarInfos, universal_regions: Rc>, + universal_region_relations: Rc>, _mir: &Mir<'tcx>, outlives_constraints: ConstraintSet, type_tests: Vec>, @@ -249,6 +255,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { scc_values, type_tests, universal_regions, + universal_region_relations, }; result.init_free_and_bound_regions(); @@ -766,7 +773,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Grow further to get smallest universal region known to // creator. - let non_local_lub = self.universal_regions.non_local_upper_bound(lub); + let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub); debug!( "non_local_universal_upper_bound: non_local_lub={:?}", @@ -802,7 +809,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut lub = self.universal_regions.fr_fn_body; let r_scc = self.constraint_sccs.scc(r); for ur in self.scc_values.universal_regions_outlived_by(r_scc) { - lub = self.universal_regions.postdom_upper_bound(lub, ur); + lub = self.universal_region_relations.postdom_upper_bound(lub, ur); } debug!("universal_upper_bound: r={:?} lub={:?}", r, lub); @@ -870,7 +877,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .all(|r1| { self.scc_values .universal_regions_outlived_by(sup_region_scc) - .any(|r2| self.universal_regions.outlives(r2, r1)) + .any(|r2| self.universal_region_relations.outlives(r2, r1)) }); if !universal_outlives { @@ -975,7 +982,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // (because `fr` includes `end(o)`). for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) { // If it is known that `fr: o`, carry on. - if self.universal_regions.outlives(longer_fr, shorter_fr) { + if self.universal_region_relations.outlives(longer_fr, shorter_fr) { continue; } @@ -989,14 +996,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `fr` until we find a non-local region (if we do). // We'll call that `fr-` -- it's ever so slightly smaller than `fr`. - if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) { + if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) { debug!("check_universal_region: fr_minus={:?}", fr_minus); // Grow `shorter_fr` until we find a non-local // region. (We always will.) We'll call that // `shorter_fr+` -- it's ever so slightly larger than // `fr`. - let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr); + let shorter_fr_plus = self.universal_region_relations.non_local_upper_bound(shorter_fr); debug!( "check_universal_region: shorter_fr_plus={:?}", shorter_fr_plus diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index 3cf3ae1d166e..d2850f8f3244 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -9,11 +9,13 @@ // except according to those terms. use borrow_check::location::LocationTable; +use borrow_check::nll::ToRegionVid; use borrow_check::nll::facts::AllFacts; -use borrow_check::nll::universal_regions::UniversalRegions; use borrow_check::nll::type_check::constraint_conversion; use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints}; +use borrow_check::nll::universal_regions::UniversalRegions; use rustc::hir::def_id::DefId; +use rustc::infer::outlives::free_region_map::FreeRegionRelations; use rustc::infer::region_constraints::GenericKind; use rustc::infer::InferCtxt; use rustc::traits::query::outlives_bounds::{self, OutlivesBound}; @@ -93,6 +95,107 @@ impl UniversalRegionRelations<'tcx> { self.outlives.add(fr_a, fr_b); self.inverse_outlives.add(fr_b, fr_a); } + + /// Given two universal regions, returns the postdominating + /// upper-bound (effectively the least upper bound). + /// + /// (See `TransitiveRelation::postdom_upper_bound` for details on + /// the postdominating upper bound in general.) + crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { + assert!(self.universal_regions.is_universal_region(fr1)); + assert!(self.universal_regions.is_universal_region(fr2)); + *self + .inverse_outlives + .postdom_upper_bound(&fr1, &fr2) + .unwrap_or(&self.universal_regions.fr_static) + } + + /// Finds an "upper bound" for `fr` that is not local. In other + /// words, returns the smallest (*) known region `fr1` that (a) + /// outlives `fr` and (b) is not local. This cannot fail, because + /// we will always find `'static` at worst. + /// + /// (*) If there are multiple competing choices, we pick the "postdominating" + /// one. See `TransitiveRelation::postdom_upper_bound` for details. + crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { + debug!("non_local_upper_bound(fr={:?})", fr); + self.non_local_bound(&self.inverse_outlives, fr) + .unwrap_or(self.universal_regions.fr_static) + } + + /// Finds a "lower bound" for `fr` that is not local. In other + /// words, returns the largest (*) known region `fr1` that (a) is + /// outlived by `fr` and (b) is not local. This cannot fail, + /// because we will always find `'static` at worst. + /// + /// (*) If there are multiple competing choices, we pick the "postdominating" + /// one. See `TransitiveRelation::postdom_upper_bound` for details. + crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option { + debug!("non_local_lower_bound(fr={:?})", fr); + self.non_local_bound(&self.outlives, fr) + } + + /// Helper for `non_local_upper_bound` and + /// `non_local_lower_bound`. Repeatedly invokes `postdom_parent` + /// until we find something that is not local. Returns None if we + /// never do so. + fn non_local_bound( + &self, + relation: &TransitiveRelation, + fr0: RegionVid, + ) -> Option { + // This method assumes that `fr0` is one of the universally + // quantified region variables. + assert!(self.universal_regions.is_universal_region(fr0)); + + let mut external_parents = vec![]; + let mut queue = vec![&fr0]; + + // Keep expanding `fr` into its parents until we reach + // non-local regions. + while let Some(fr) = queue.pop() { + if !self.universal_regions.is_local_free_region(*fr) { + external_parents.push(fr); + continue; + } + + queue.extend(relation.parents(fr)); + } + + debug!("non_local_bound: external_parents={:?}", external_parents); + + // In case we find more than one, reduce to one for + // convenience. This is to prevent us from generating more + // complex constraints, but it will cause spurious errors. + let post_dom = relation + .mutual_immediate_postdominator(external_parents) + .cloned(); + + debug!("non_local_bound: post_dom={:?}", post_dom); + + post_dom.and_then(|post_dom| { + // If the mutual immediate postdom is not local, then + // there is no non-local result we can return. + if !self.universal_regions.is_local_free_region(post_dom) { + Some(post_dom) + } else { + None + } + }) + } + + /// True if fr1 is known to outlive fr2. + /// + /// This will only ever be true for universally quantified regions. + crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { + self.outlives.contains(&fr1, &fr2) + } + + /// Returns a vector of free regions `x` such that `fr1: x` is + /// known to hold. + crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> { + self.outlives.reachable_from(&fr1) + } } struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> { @@ -223,3 +326,16 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { } } } + +/// This trait is used by the `impl-trait` constraint code to abstract +/// over the `FreeRegionMap` from lexical regions and +/// `UniversalRegions` (from NLL)`. +impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> { + fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool { + let shorter = shorter.to_region_vid(); + assert!(self.universal_regions.is_universal_region(shorter)); + let longer = longer.to_region_vid(); + assert!(self.universal_regions.is_universal_region(longer)); + self.outlives(longer, shorter) + } +} diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index ea0dc200b7df..8571ac3235c3 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -18,6 +18,7 @@ //! contain revealed `impl Trait` values). use borrow_check::nll::renumber; +use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use borrow_check::nll::universal_regions::UniversalRegions; use rustc::hir::def_id::DefId; use rustc::infer::InferOk; @@ -37,6 +38,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { mir: &Mir<'tcx>, mir_def_id: DefId, universal_regions: &UniversalRegions<'tcx>, + universal_region_relations: &UniversalRegionRelations<'tcx>, ) { let tcx = self.infcx.tcx; @@ -160,7 +162,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Locations::All, CustomTypeOp::new( |_cx| { - infcx.constrain_anon_types(&anon_type_map, universal_regions); + infcx.constrain_anon_types(&anon_type_map, universal_region_relations); Ok(InferOk { value: (), obligations: vec![], diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index be14819b6489..15deb5fb2f49 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -17,9 +17,10 @@ use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; use borrow_check::nll::facts::AllFacts; use borrow_check::nll::region_infer::values::{RegionValueElements, LivenessValues}; use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; +use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use borrow_check::nll::universal_regions::UniversalRegions; -use borrow_check::nll::ToRegionVid; use borrow_check::nll::LocalWithRegion; +use borrow_check::nll::ToRegionVid; use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; use dataflow::MaybeInitializedPlaces; @@ -36,12 +37,12 @@ use rustc::traits::query::type_op; use rustc::traits::query::{Fallible, NoSolution}; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; +use rustc_errors::Diagnostic; use std::fmt; use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; use transform::{MirPass, MirSource}; use util::liveness::LivenessResults; -use rustc_errors::Diagnostic; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; @@ -71,7 +72,7 @@ macro_rules! span_mirbug_and_err { } mod constraint_conversion; -mod free_region_relations; +pub mod free_region_relations; mod input_output; mod liveness; mod relate_tys; @@ -120,7 +121,10 @@ pub(crate) fn type_check<'gcx, 'tcx>( move_data: &MoveData<'tcx>, elements: &Rc, errors_buffer: &mut Vec, -) -> MirTypeckRegionConstraints<'tcx> { +) -> ( + MirTypeckRegionConstraints<'tcx>, + Rc>, +) { let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); let mut constraints = MirTypeckRegionConstraints { liveness_constraints: LivenessValues::new(elements), @@ -128,16 +132,17 @@ pub(crate) fn type_check<'gcx, 'tcx>( type_tests: Vec::default(), }; - let _urr = free_region_relations::UniversalRegionRelations::create( - infcx, - mir_def_id, - param_env, - location_table, - Some(implicit_region_bound), - universal_regions, - &mut constraints, - all_facts, - ); + let universal_region_relations = + Rc::new(free_region_relations::UniversalRegionRelations::create( + infcx, + mir_def_id, + param_env, + location_table, + Some(implicit_region_bound), + universal_regions, + &mut constraints, + all_facts, + )); { let mut borrowck_context = BorrowCheckContext { @@ -153,17 +158,23 @@ pub(crate) fn type_check<'gcx, 'tcx>( mir_def_id, param_env, mir, - &universal_regions.region_bound_pairs, + &universal_region_relations.region_bound_pairs, Some(implicit_region_bound), Some(&mut borrowck_context), Some(errors_buffer), |cx| { liveness::generate(cx, mir, liveness, flow_inits, move_data); - cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions); + cx.equate_inputs_and_outputs( + mir, + mir_def_id, + universal_regions, + &universal_region_relations, + ); }, ); } - constraints + + (constraints, universal_region_relations) } fn type_check_internal<'a, 'gcx, 'tcx, F>( @@ -176,8 +187,8 @@ fn type_check_internal<'a, 'gcx, 'tcx, F>( borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, errors_buffer: Option<&mut Vec>, mut extra: F, -) - where F: FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) +) where + F: FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>), { let mut checker = TypeChecker::new( infcx, @@ -319,8 +330,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // don't have a handy function for that, so for // now we just ignore `value.val` regions. - let instantiated_predicates = - tcx.predicates_of(def_id).instantiate(tcx, substs); + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); type_checker.normalize_and_prove_instantiated_predicates( instantiated_predicates, location.boring(), @@ -1035,9 +1045,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // all the inputs that fed into it were live. for &late_bound_region in map.values() { if let Some(ref mut borrowck_context) = self.borrowck_context { - let region_vid = borrowck_context.universal_regions.to_region_vid( - late_bound_region); - borrowck_context.constraints + let region_vid = borrowck_context + .universal_regions + .to_region_vid(late_bound_region); + borrowck_context + .constraints .liveness_constraints .add_element(region_vid, term_location); } @@ -1253,12 +1265,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_local(&mut self, - mir: &Mir<'tcx>, - local: Local, - local_decl: &LocalDecl<'tcx>, - errors_buffer: &mut Option<&mut Vec>) - { + fn check_local( + &mut self, + mir: &Mir<'tcx>, + local: Local, + local_decl: &LocalDecl<'tcx>, + errors_buffer: &mut Option<&mut Vec>, + ) { match mir.local_kind(local) { LocalKind::ReturnPointer | LocalKind::Arg => { // return values of normal functions are required to be @@ -1286,12 +1299,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // slot or local, so to find all unsized rvalues it is enough // to check all temps, return slots and locals. if let None = self.reported_errors.replace((ty, span)) { - let mut diag = struct_span_err!(self.tcx().sess, - span, - E0161, - "cannot move a value of type {0}: the size of {0} \ - cannot be statically determined", - ty); + let mut diag = struct_span_err!( + self.tcx().sess, + span, + E0161, + "cannot move a value of type {0}: the size of {0} \ + cannot be statically determined", + ty + ); if let Some(ref mut errors_buffer) = *errors_buffer { diag.buffer(errors_buffer); } else { @@ -1589,13 +1604,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.sty { ty::TyRef(ref_region, _, mutbl) => { - constraints - .outlives_constraints - .push(OutlivesConstraint { - sup: ref_region.to_region_vid(), - sub: borrow_region.to_region_vid(), - locations: location.boring(), - }); + constraints.outlives_constraints.push(OutlivesConstraint { + sup: ref_region.to_region_vid(), + sub: borrow_region.to_region_vid(), + locations: location.boring(), + }); if let Some(all_facts) = all_facts { all_facts.outlives.push(( @@ -1780,10 +1793,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }) } - fn typeck_mir(&mut self, - mir: &Mir<'tcx>, - mut errors_buffer: Option<&mut Vec>) - { + fn typeck_mir(&mut self, mir: &Mir<'tcx>, mut errors_buffer: Option<&mut Vec>) { self.last_span = mir.span; debug!("run_on_mir: {:?}", mir.span); @@ -1853,7 +1863,17 @@ impl MirPass for TypeckMir { let param_env = tcx.param_env(def_id); tcx.infer_ctxt().enter(|infcx| { - type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, None, |_| ()); + type_check_internal( + &infcx, + def_id, + param_env, + mir, + &[], + None, + None, + None, + |_| (), + ); // For verification purposes, we just ignore the resulting // region constraint sets. Not our problem. =) diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index 9bb7d1231334..765c4cf906e6 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -25,16 +25,12 @@ use either::Either; use rustc::hir::def_id::DefId; use rustc::hir::{self, BodyOwnerKind, HirId}; -use rustc::infer::outlives::free_region_map::FreeRegionRelations; -use rustc::infer::region_constraints::GenericKind; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; -use rustc::traits::query::outlives_bounds::{self, OutlivesBound}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::transitive_relation::TransitiveRelation; use std::iter; use syntax::ast; @@ -85,21 +81,7 @@ pub struct UniversalRegions<'tcx> { /// as the name suggests. =) pub unnormalized_input_tys: &'tcx [Ty<'tcx>], - /// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to - /// be true. These encode relationships like `T: 'a` that are - /// added via implicit bounds. - /// - /// Each region here is guaranteed to be a key in the `indices` - /// map. We use the "original" regions (i.e., the keys from the - /// map, and not the values) because the code in - /// `process_registered_region_obligations` has some special-cased - /// logic expecting to see (e.g.) `ReStatic`, and if we supplied - /// our special inference variable there, we would mess that up. - pub region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, - pub yield_ty: Option>, - - relations: UniversalRegionRelations, } /// The "defining type" for this MIR. The key feature of the "defining @@ -171,20 +153,6 @@ struct UniversalRegionIndices<'tcx> { indices: FxHashMap, RegionVid>, } -#[derive(Debug)] -struct UniversalRegionRelations { - /// Stores the outlives relations that are known to hold from the - /// implied bounds, in-scope where clauses, and that sort of - /// thing. - outlives: TransitiveRelation, - - /// This is the `<=` relation; that is, if `a: b`, then `b <= a`, - /// and we store that here. This is useful when figuring out how - /// to express some local region in terms of external regions our - /// caller will understand. - inverse_outlives: TransitiveRelation, -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum RegionClassification { /// A **global** region is one that can be named from @@ -249,11 +217,6 @@ impl<'tcx> UniversalRegions<'tcx> { mir_node_id, mir_hir_id, param_env, - region_bound_pairs: vec![], - relations: UniversalRegionRelations { - outlives: TransitiveRelation::new(), - inverse_outlives: TransitiveRelation::new(), - }, }.build() } @@ -326,45 +289,6 @@ impl<'tcx> UniversalRegions<'tcx> { self.num_universals } - /// Given two universal regions, returns the postdominating - /// upper-bound (effectively the least upper bound). - /// - /// (See `TransitiveRelation::postdom_upper_bound` for details on - /// the postdominating upper bound in general.) - pub fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { - assert!(self.is_universal_region(fr1)); - assert!(self.is_universal_region(fr2)); - *self.relations - .inverse_outlives - .postdom_upper_bound(&fr1, &fr2) - .unwrap_or(&self.fr_static) - } - - /// Finds an "upper bound" for `fr` that is not local. In other - /// words, returns the smallest (*) known region `fr1` that (a) - /// outlives `fr` and (b) is not local. This cannot fail, because - /// we will always find `'static` at worst. - /// - /// (*) If there are multiple competing choices, we pick the "postdominating" - /// one. See `TransitiveRelation::postdom_upper_bound` for details. - pub fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { - debug!("non_local_upper_bound(fr={:?})", fr); - self.non_local_bound(&self.relations.inverse_outlives, fr) - .unwrap_or(self.fr_static) - } - - /// Finds a "lower bound" for `fr` that is not local. In other - /// words, returns the largest (*) known region `fr1` that (a) is - /// outlived by `fr` and (b) is not local. This cannot fail, - /// because we will always find `'static` at worst. - /// - /// (*) If there are multiple competing choices, we pick the "postdominating" - /// one. See `TransitiveRelation::postdom_upper_bound` for details. - pub fn non_local_lower_bound(&self, fr: RegionVid) -> Option { - debug!("non_local_lower_bound(fr={:?})", fr); - self.non_local_bound(&self.relations.outlives, fr) - } - /// Returns the number of global plus external universal regions. /// For closures, these are the regions that appear free in the /// closure type (versus those bound in the closure @@ -374,68 +298,6 @@ impl<'tcx> UniversalRegions<'tcx> { self.first_local_index } - /// Helper for `non_local_upper_bound` and - /// `non_local_lower_bound`. Repeatedly invokes `postdom_parent` - /// until we find something that is not local. Returns None if we - /// never do so. - fn non_local_bound( - &self, - relation: &TransitiveRelation, - fr0: RegionVid, - ) -> Option { - // This method assumes that `fr0` is one of the universally - // quantified region variables. - assert!(self.is_universal_region(fr0)); - - let mut external_parents = vec![]; - let mut queue = vec![&fr0]; - - // Keep expanding `fr` into its parents until we reach - // non-local regions. - while let Some(fr) = queue.pop() { - if !self.is_local_free_region(*fr) { - external_parents.push(fr); - continue; - } - - queue.extend(relation.parents(fr)); - } - - debug!("non_local_bound: external_parents={:?}", external_parents); - - // In case we find more than one, reduce to one for - // convenience. This is to prevent us from generating more - // complex constraints, but it will cause spurious errors. - let post_dom = relation - .mutual_immediate_postdominator(external_parents) - .cloned(); - - debug!("non_local_bound: post_dom={:?}", post_dom); - - post_dom.and_then(|post_dom| { - // If the mutual immediate postdom is not local, then - // there is no non-local result we can return. - if !self.is_local_free_region(post_dom) { - Some(post_dom) - } else { - None - } - }) - } - - /// True if fr1 is known to outlive fr2. - /// - /// This will only ever be true for universally quantified regions. - pub fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { - self.relations.outlives.contains(&fr1, &fr2) - } - - /// Returns a vector of free regions `x` such that `fr1: x` is - /// known to hold. - pub fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> { - self.relations.outlives.reachable_from(&fr1) - } - /// Get an iterator over all the early-bound regions that have names. pub fn named_universal_regions<'s>( &'s self, @@ -455,14 +317,12 @@ struct UniversalRegionsBuilder<'cx, 'gcx: 'tcx, 'tcx: 'cx> { mir_hir_id: HirId, mir_node_id: ast::NodeId, param_env: ty::ParamEnv<'tcx>, - region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, - relations: UniversalRegionRelations, } const FR: NLLRegionVariableOrigin = NLLRegionVariableOrigin::FreeRegion; impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { - fn build(mut self) -> UniversalRegions<'tcx> { + fn build(self) -> UniversalRegions<'tcx> { debug!("build(mir_def_id={:?})", self.mir_def_id); let param_env = self.param_env; @@ -519,33 +379,6 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid(); let num_universals = self.infcx.num_region_vars(); - // Insert the facts we know from the predicates. Why? Why not. - self.add_outlives_bounds( - &indices, - outlives_bounds::explicit_outlives_bounds(param_env), - ); - - // Add the implied bounds from inputs and outputs. - for ty in inputs_and_output { - debug!("build: input_or_output={:?}", ty); - self.add_implied_bounds(&indices, ty); - } - - // Finally: - // - outlives is reflexive, so `'r: 'r` for every region `'r` - // - `'static: 'r` for every region `'r` - // - `'r: 'fn_body` for every (other) universally quantified - // region `'r`, all of which are provided by our caller - for fr in (FIRST_GLOBAL_INDEX..num_universals).map(RegionVid::new) { - debug!( - "build: relating free region {:?} to itself and to 'static", - fr - ); - self.relations.relate_universal_regions(fr, fr); - self.relations.relate_universal_regions(fr_static, fr); - self.relations.relate_universal_regions(fr, fr_fn_body); - } - let (unnormalized_output_ty, unnormalized_input_tys) = inputs_and_output.split_last().unwrap(); @@ -579,9 +412,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { defining_ty, unnormalized_output_ty, unnormalized_input_tys, - region_bound_pairs: self.region_bound_pairs, yield_ty: yield_ty, - relations: self.relations, } } @@ -730,64 +561,6 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { } } } - - /// Update the type of a single local, which should represent - /// either the return type of the MIR or one of its arguments. At - /// the same time, compute and add any implied bounds that come - /// from this local. - /// - /// Assumes that `universal_regions` indices map is fully constructed. - fn add_implied_bounds(&mut self, indices: &UniversalRegionIndices<'tcx>, ty: Ty<'tcx>) { - debug!("add_implied_bounds(ty={:?})", ty); - let span = self.infcx.tcx.def_span(self.mir_def_id); - let bounds = self.infcx - .implied_outlives_bounds(self.param_env, self.mir_node_id, ty, span); - self.add_outlives_bounds(indices, bounds); - } - - /// Registers the `OutlivesBound` items from `outlives_bounds` in - /// the outlives relation as well as the region-bound pairs - /// listing. - fn add_outlives_bounds(&mut self, indices: &UniversalRegionIndices<'tcx>, outlives_bounds: I) - where - I: IntoIterator>, - { - for outlives_bound in outlives_bounds { - debug!("add_outlives_bounds(bound={:?})", outlives_bound); - - match outlives_bound { - OutlivesBound::RegionSubRegion(r1, r2) => { - // The bound says that `r1 <= r2`; we store `r2: r1`. - let r1 = indices.to_region_vid(r1); - let r2 = indices.to_region_vid(r2); - self.relations.relate_universal_regions(r2, r1); - } - - 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))); - } - } - } - } -} - -impl UniversalRegionRelations { - /// Records in the `outlives_relation` (and - /// `inverse_outlives_relation`) that `fr_a: fr_b`. - fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { - debug!( - "relate_universal_regions: fr_a={:?} outlives fr_b={:?}", - fr_a, fr_b - ); - self.outlives.add(fr_a, fr_b); - self.inverse_outlives.add(fr_b, fr_a); - } } trait InferCtxtExt<'tcx> { @@ -925,19 +698,6 @@ impl<'tcx> UniversalRegionIndices<'tcx> { } } -/// This trait is used by the `impl-trait` constraint code to abstract -/// over the `FreeRegionMap` from lexical regions and -/// `UniversalRegions` (from NLL)`. -impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegions<'tcx> { - fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool { - let shorter = shorter.to_region_vid(); - assert!(self.is_universal_region(shorter)); - let longer = longer.to_region_vid(); - assert!(self.is_universal_region(longer)); - self.outlives(longer, shorter) - } -} - /// Iterates over the late-bound regions defined on fn_def_id and /// invokes `f` with the liberated form of each one. fn for_each_late_bound_region_defined_on<'tcx>(