1 use rustc::mir::ConstraintCategory;
2 use rustc::ty::free_region_map::FreeRegionRelations;
3 use rustc::ty::{self, RegionVid, Ty, TyCtxt};
4 use rustc_data_structures::transitive_relation::TransitiveRelation;
5 use rustc_infer::infer::canonical::QueryRegionConstraints;
6 use rustc_infer::infer::region_constraints::GenericKind;
7 use rustc_infer::infer::InferCtxt;
8 use rustc_infer::traits::query::outlives_bounds::{self, OutlivesBound};
9 use rustc_infer::traits::query::type_op::{self, TypeOp};
10 use rustc_span::DUMMY_SP;
13 use crate::borrow_check::{
15 type_check::constraint_conversion,
16 type_check::{Locations, MirTypeckRegionConstraints},
17 universal_regions::UniversalRegions,
21 crate struct UniversalRegionRelations<'tcx> {
22 universal_regions: Rc<UniversalRegions<'tcx>>,
24 /// Stores the outlives relations that are known to hold from the
25 /// implied bounds, in-scope where-clauses, and that sort of
27 outlives: TransitiveRelation<RegionVid>,
29 /// This is the `<=` relation; that is, if `a: b`, then `b <= a`,
30 /// and we store that here. This is useful when figuring out how
31 /// to express some local region in terms of external regions our
32 /// caller will understand.
33 inverse_outlives: TransitiveRelation<RegionVid>,
36 /// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to
37 /// be true. These encode relationships like `T: 'a` that are
38 /// added via implicit bounds.
40 /// Each region here is guaranteed to be a key in the `indices`
41 /// map. We use the "original" regions (i.e., the keys from the
42 /// map, and not the values) because the code in
43 /// `process_registered_region_obligations` has some special-cased
44 /// logic expecting to see (e.g.) `ReStatic`, and if we supplied
45 /// our special inference variable there, we would mess that up.
46 type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
48 /// As part of computing the free region relations, we also have to
49 /// normalize the input-output types, which we then need later. So we
50 /// return those. This vector consists of first the input types and
51 /// then the output type as the last element.
52 type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
54 crate struct CreateResult<'tcx> {
55 crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
56 crate region_bound_pairs: RegionBoundPairs<'tcx>,
57 crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
61 infcx: &InferCtxt<'_, 'tcx>,
62 param_env: ty::ParamEnv<'tcx>,
63 implicit_region_bound: Option<ty::Region<'tcx>>,
64 universal_regions: &Rc<UniversalRegions<'tcx>>,
65 constraints: &mut MirTypeckRegionConstraints<'tcx>,
66 ) -> CreateResult<'tcx> {
67 UniversalRegionRelationsBuilder {
70 implicit_region_bound,
72 universal_regions: universal_regions.clone(),
73 region_bound_pairs: Vec::new(),
74 relations: UniversalRegionRelations {
75 universal_regions: universal_regions.clone(),
76 outlives: Default::default(),
77 inverse_outlives: Default::default(),
83 impl UniversalRegionRelations<'tcx> {
84 /// Records in the `outlives_relation` (and
85 /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the
87 fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
88 debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
89 self.outlives.add(fr_a, fr_b);
90 self.inverse_outlives.add(fr_b, fr_a);
93 /// Given two universal regions, returns the postdominating
94 /// upper-bound (effectively the least upper bound).
96 /// (See `TransitiveRelation::postdom_upper_bound` for details on
97 /// the postdominating upper bound in general.)
98 crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
99 assert!(self.universal_regions.is_universal_region(fr1));
100 assert!(self.universal_regions.is_universal_region(fr2));
103 .postdom_upper_bound(&fr1, &fr2)
104 .unwrap_or(&self.universal_regions.fr_static)
107 /// Finds an "upper bound" for `fr` that is not local. In other
108 /// words, returns the smallest (*) known region `fr1` that (a)
109 /// outlives `fr` and (b) is not local.
111 /// (*) If there are multiple competing choices, we return all of them.
112 crate fn non_local_upper_bounds(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
113 debug!("non_local_upper_bound(fr={:?})", fr);
114 let res = self.non_local_bounds(&self.inverse_outlives, fr);
115 assert!(!res.is_empty(), "can't find an upper bound!?");
119 /// Returns the "postdominating" bound of the set of
120 /// `non_local_upper_bounds` for the given region.
121 crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
122 let upper_bounds = self.non_local_upper_bounds(&fr);
124 // In case we find more than one, reduce to one for
125 // convenience. This is to prevent us from generating more
126 // complex constraints, but it will cause spurious errors.
127 let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds);
129 debug!("non_local_bound: post_dom={:?}", post_dom);
132 .and_then(|&post_dom| {
133 // If the mutual immediate postdom is not local, then
134 // there is no non-local result we can return.
135 if !self.universal_regions.is_local_free_region(post_dom) {
141 .unwrap_or(self.universal_regions.fr_static)
144 /// Finds a "lower bound" for `fr` that is not local. In other
145 /// words, returns the largest (*) known region `fr1` that (a) is
146 /// outlived by `fr` and (b) is not local.
148 /// (*) If there are multiple competing choices, we pick the "postdominating"
149 /// one. See `TransitiveRelation::postdom_upper_bound` for details.
150 crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
151 debug!("non_local_lower_bound(fr={:?})", fr);
152 let lower_bounds = self.non_local_bounds(&self.outlives, &fr);
154 // In case we find more than one, reduce to one for
155 // convenience. This is to prevent us from generating more
156 // complex constraints, but it will cause spurious errors.
157 let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds);
159 debug!("non_local_bound: post_dom={:?}", post_dom);
161 post_dom.and_then(|&post_dom| {
162 // If the mutual immediate postdom is not local, then
163 // there is no non-local result we can return.
164 if !self.universal_regions.is_local_free_region(post_dom) {
172 /// Helper for `non_local_upper_bounds` and `non_local_lower_bounds`.
173 /// Repeatedly invokes `postdom_parent` until we find something that is not
174 /// local. Returns `None` if we never do so.
175 fn non_local_bounds<'a>(
177 relation: &'a TransitiveRelation<RegionVid>,
179 ) -> Vec<&'a RegionVid> {
180 // This method assumes that `fr0` is one of the universally
181 // quantified region variables.
182 assert!(self.universal_regions.is_universal_region(*fr0));
184 let mut external_parents = vec![];
185 let mut queue = vec![fr0];
187 // Keep expanding `fr` into its parents until we reach
188 // non-local regions.
189 while let Some(fr) = queue.pop() {
190 if !self.universal_regions.is_local_free_region(*fr) {
191 external_parents.push(fr);
195 queue.extend(relation.parents(fr));
198 debug!("non_local_bound: external_parents={:?}", external_parents);
203 /// Returns `true` if fr1 is known to outlive fr2.
205 /// This will only ever be true for universally quantified regions.
206 crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
207 self.outlives.contains(&fr1, &fr2)
210 /// Returns a vector of free regions `x` such that `fr1: x` is
212 crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> {
213 self.outlives.reachable_from(&fr1)
216 /// Returns the _non-transitive_ set of known `outlives` constraints between free regions.
217 crate fn known_outlives(&self) -> impl Iterator<Item = (&RegionVid, &RegionVid)> {
218 self.outlives.base_edges()
222 struct UniversalRegionRelationsBuilder<'this, 'tcx> {
223 infcx: &'this InferCtxt<'this, 'tcx>,
224 param_env: ty::ParamEnv<'tcx>,
225 universal_regions: Rc<UniversalRegions<'tcx>>,
226 implicit_region_bound: Option<ty::Region<'tcx>>,
227 constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
230 relations: UniversalRegionRelations<'tcx>,
231 region_bound_pairs: RegionBoundPairs<'tcx>,
234 impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
235 crate fn create(mut self) -> CreateResult<'tcx> {
236 let unnormalized_input_output_tys = self
238 .unnormalized_input_tys
241 .chain(Some(self.universal_regions.unnormalized_output_ty));
243 // For each of the input/output types:
244 // - Normalize the type. This will create some region
245 // constraints, which we buffer up because we are
246 // not ready to process them yet.
247 // - Then compute the implied bounds. This will adjust
248 // the `region_bound_pairs` and so forth.
249 // - After this is done, we'll process the constraints, once
250 // the `relations` is built.
251 let mut normalized_inputs_and_output =
252 Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
253 let constraint_sets: Vec<_> = unnormalized_input_output_tys
255 debug!("build: input_or_output={:?}", ty);
256 let (ty, constraints1) = self
258 .and(type_op::normalize::Normalize::new(ty))
259 .fully_perform(self.infcx)
260 .unwrap_or_else(|_| bug!("failed to normalize {:?}", ty));
261 let constraints2 = self.add_implied_bounds(ty);
262 normalized_inputs_and_output.push(ty);
263 constraints1.into_iter().chain(constraints2)
267 // Insert the facts we know from the predicates. Why? Why not.
268 let param_env = self.param_env;
269 self.add_outlives_bounds(outlives_bounds::explicit_outlives_bounds(param_env));
272 // - outlives is reflexive, so `'r: 'r` for every region `'r`
273 // - `'static: 'r` for every region `'r`
274 // - `'r: 'fn_body` for every (other) universally quantified
275 // region `'r`, all of which are provided by our caller
276 let fr_static = self.universal_regions.fr_static;
277 let fr_fn_body = self.universal_regions.fr_fn_body;
278 for fr in self.universal_regions.universal_regions() {
279 debug!("build: relating free region {:?} to itself and to 'static", fr);
280 self.relations.relate_universal_regions(fr, fr);
281 self.relations.relate_universal_regions(fr_static, fr);
282 self.relations.relate_universal_regions(fr, fr_fn_body);
285 for data in &constraint_sets {
286 constraint_conversion::ConstraintConversion::new(
288 &self.universal_regions,
289 &self.region_bound_pairs,
290 self.implicit_region_bound,
292 Locations::All(DUMMY_SP),
293 ConstraintCategory::Internal,
294 &mut self.constraints,
300 universal_region_relations: Rc::new(self.relations),
301 region_bound_pairs: self.region_bound_pairs,
302 normalized_inputs_and_output,
306 /// Update the type of a single local, which should represent
307 /// either the return type of the MIR or one of its arguments. At
308 /// the same time, compute and add any implied bounds that come
310 fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
311 debug!("add_implied_bounds(ty={:?})", ty);
312 let (bounds, constraints) = self
314 .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
315 .fully_perform(self.infcx)
316 .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
317 self.add_outlives_bounds(bounds);
321 /// Registers the `OutlivesBound` items from `outlives_bounds` in
322 /// the outlives relation as well as the region-bound pairs
324 fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
326 I: IntoIterator<Item = OutlivesBound<'tcx>>,
328 for outlives_bound in outlives_bounds {
329 debug!("add_outlives_bounds(bound={:?})", outlives_bound);
331 match outlives_bound {
332 OutlivesBound::RegionSubRegion(r1, r2) => {
333 // `where Type:` is lowered to `where Type: 'empty` so that
334 // we check `Type` is well formed, but there's no use for
336 if let ty::ReEmpty(_) = r1 {
340 // The bound says that `r1 <= r2`; we store `r2: r1`.
341 let r1 = self.universal_regions.to_region_vid(r1);
342 let r2 = self.universal_regions.to_region_vid(r2);
343 self.relations.relate_universal_regions(r2, r1);
346 OutlivesBound::RegionSubParam(r_a, param_b) => {
347 self.region_bound_pairs.push((r_a, GenericKind::Param(param_b)));
350 OutlivesBound::RegionSubProjection(r_a, projection_b) => {
351 self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b)));
358 /// This trait is used by the `impl-trait` constraint code to abstract
359 /// over the `FreeRegionMap` from lexical regions and
360 /// `UniversalRegions` (from NLL)`.
361 impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> {
365 shorter: ty::Region<'tcx>,
366 longer: ty::Region<'tcx>,
368 let shorter = shorter.to_region_vid();
369 assert!(self.universal_regions.is_universal_region(shorter));
370 let longer = longer.to_region_vid();
371 assert!(self.universal_regions.is_universal_region(longer));
372 self.outlives(longer, shorter)