// 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,
let mut regioncx = RegionInferenceContext::new(
var_origins,
universal_regions,
+ universal_region_relations,
mir,
outlives_constraints,
type_tests,
.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}",
};
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};
type_tests: Vec<TypeTest<'tcx>>,
/// Information about the universally quantified regions in scope
- /// on this function and their (known) relations to one another.
+ /// on this function.
universal_regions: Rc<UniversalRegions<'tcx>>,
+
+ /// Information about how the universally quantified regions in
+ /// scope on this function relate to one another.
+ universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
}
struct RegionDefinition<'tcx> {
pub(crate) fn new(
var_infos: VarInfos,
universal_regions: Rc<UniversalRegions<'tcx>>,
+ universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
_mir: &Mir<'tcx>,
outlives_constraints: ConstraintSet,
type_tests: Vec<TypeTest<'tcx>>,
scc_values,
type_tests,
universal_regions,
+ universal_region_relations,
};
result.init_free_and_bound_regions();
// 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={:?}",
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);
.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 {
// (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;
}
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
// 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};
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<RegionVid> {
+ 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<RegionVid>,
+ fr0: RegionVid,
+ ) -> Option<RegionVid> {
+ // 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> {
}
}
}
+
+/// 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)
+ }
+}
//! 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;
mir: &Mir<'tcx>,
mir_def_id: DefId,
universal_regions: &UniversalRegions<'tcx>,
+ universal_region_relations: &UniversalRegionRelations<'tcx>,
) {
let tcx = self.infcx.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![],
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;
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;
}
mod constraint_conversion;
-mod free_region_relations;
+pub mod free_region_relations;
mod input_output;
mod liveness;
mod relate_tys;
move_data: &MoveData<'tcx>,
elements: &Rc<RegionValueElements>,
errors_buffer: &mut Vec<Diagnostic>,
-) -> MirTypeckRegionConstraints<'tcx> {
+) -> (
+ MirTypeckRegionConstraints<'tcx>,
+ Rc<UniversalRegionRelations<'tcx>>,
+) {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
let mut constraints = MirTypeckRegionConstraints {
liveness_constraints: LivenessValues::new(elements),
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 {
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>(
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
errors_buffer: Option<&mut Vec<Diagnostic>>,
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,
// 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(),
// 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);
}
}
}
- fn check_local(&mut self,
- mir: &Mir<'tcx>,
- local: Local,
- local_decl: &LocalDecl<'tcx>,
- errors_buffer: &mut Option<&mut Vec<Diagnostic>>)
- {
+ fn check_local(
+ &mut self,
+ mir: &Mir<'tcx>,
+ local: Local,
+ local_decl: &LocalDecl<'tcx>,
+ errors_buffer: &mut Option<&mut Vec<Diagnostic>>,
+ ) {
match mir.local_kind(local) {
LocalKind::ReturnPointer | LocalKind::Arg => {
// return values of normal functions are required to be
// 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 {
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((
})
}
- fn typeck_mir(&mut self,
- mir: &Mir<'tcx>,
- mut errors_buffer: Option<&mut Vec<Diagnostic>>)
- {
+ fn typeck_mir(&mut self, mir: &Mir<'tcx>, mut errors_buffer: Option<&mut Vec<Diagnostic>>) {
self.last_span = mir.span;
debug!("run_on_mir: {:?}", mir.span);
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. =)
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;
/// 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<Ty<'tcx>>,
-
- relations: UniversalRegionRelations,
}
/// The "defining type" for this MIR. The key feature of the "defining
indices: FxHashMap<ty::Region<'tcx>, 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<RegionVid>,
-
- /// 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<RegionVid>,
-}
-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum RegionClassification {
/// A **global** region is one that can be named from
mir_node_id,
mir_hir_id,
param_env,
- region_bound_pairs: vec![],
- relations: UniversalRegionRelations {
- outlives: TransitiveRelation::new(),
- inverse_outlives: TransitiveRelation::new(),
- },
}.build()
}
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<RegionVid> {
- 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
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<RegionVid>,
- fr0: RegionVid,
- ) -> Option<RegionVid> {
- // 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,
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;
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();
defining_ty,
unnormalized_output_ty,
unnormalized_input_tys,
- region_bound_pairs: self.region_bound_pairs,
yield_ty: yield_ty,
- relations: self.relations,
}
}
}
}
}
-
- /// 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<I>(&mut self, indices: &UniversalRegionIndices<'tcx>, outlives_bounds: I)
- where
- I: IntoIterator<Item = OutlivesBound<'tcx>>,
- {
- 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> {
}
}
-/// 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>(