]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/type_check/free_region_relations.rs
Rollup merge of #70038 - DutchGhost:const-forget-tests, r=RalfJung
[rust.git] / src / librustc_mir / borrow_check / type_check / free_region_relations.rs
1 use rustc::mir::ConstraintCategory;
2 use rustc::traits::query::OutlivesBound;
3 use rustc::ty::free_region_map::FreeRegionRelations;
4 use rustc::ty::{self, RegionVid, Ty, TyCtxt};
5 use rustc_data_structures::frozen::Frozen;
6 use rustc_data_structures::transitive_relation::TransitiveRelation;
7 use rustc_infer::infer::canonical::QueryRegionConstraints;
8 use rustc_infer::infer::outlives;
9 use rustc_infer::infer::region_constraints::GenericKind;
10 use rustc_infer::infer::InferCtxt;
11 use rustc_span::DUMMY_SP;
12 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
13 use std::rc::Rc;
14
15 use crate::borrow_check::{
16     nll::ToRegionVid,
17     type_check::constraint_conversion,
18     type_check::{Locations, MirTypeckRegionConstraints},
19     universal_regions::UniversalRegions,
20 };
21
22 #[derive(Debug)]
23 crate struct UniversalRegionRelations<'tcx> {
24     universal_regions: Rc<UniversalRegions<'tcx>>,
25
26     /// Stores the outlives relations that are known to hold from the
27     /// implied bounds, in-scope where-clauses, and that sort of
28     /// thing.
29     outlives: TransitiveRelation<RegionVid>,
30
31     /// This is the `<=` relation; that is, if `a: b`, then `b <= a`,
32     /// and we store that here. This is useful when figuring out how
33     /// to express some local region in terms of external regions our
34     /// caller will understand.
35     inverse_outlives: TransitiveRelation<RegionVid>,
36 }
37
38 /// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to
39 /// be true. These encode relationships like `T: 'a` that are
40 /// added via implicit bounds.
41 ///
42 /// Each region here is guaranteed to be a key in the `indices`
43 /// map. We use the "original" regions (i.e., the keys from the
44 /// map, and not the values) because the code in
45 /// `process_registered_region_obligations` has some special-cased
46 /// logic expecting to see (e.g.) `ReStatic`, and if we supplied
47 /// our special inference variable there, we would mess that up.
48 type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
49
50 /// As part of computing the free region relations, we also have to
51 /// normalize the input-output types, which we then need later. So we
52 /// return those. This vector consists of first the input types and
53 /// then the output type as the last element.
54 type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
55
56 crate struct CreateResult<'tcx> {
57     pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
58     crate region_bound_pairs: RegionBoundPairs<'tcx>,
59     crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
60 }
61
62 crate fn create(
63     infcx: &InferCtxt<'_, 'tcx>,
64     param_env: ty::ParamEnv<'tcx>,
65     implicit_region_bound: Option<ty::Region<'tcx>>,
66     universal_regions: &Rc<UniversalRegions<'tcx>>,
67     constraints: &mut MirTypeckRegionConstraints<'tcx>,
68 ) -> CreateResult<'tcx> {
69     UniversalRegionRelationsBuilder {
70         infcx,
71         param_env,
72         implicit_region_bound,
73         constraints,
74         universal_regions: universal_regions.clone(),
75         region_bound_pairs: Vec::new(),
76         relations: UniversalRegionRelations {
77             universal_regions: universal_regions.clone(),
78             outlives: Default::default(),
79             inverse_outlives: Default::default(),
80         },
81     }
82     .create()
83 }
84
85 impl UniversalRegionRelations<'tcx> {
86     /// Records in the `outlives_relation` (and
87     /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the
88     /// builder below.
89     fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
90         debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
91         self.outlives.add(fr_a, fr_b);
92         self.inverse_outlives.add(fr_b, fr_a);
93     }
94
95     /// Given two universal regions, returns the postdominating
96     /// upper-bound (effectively the least upper bound).
97     ///
98     /// (See `TransitiveRelation::postdom_upper_bound` for details on
99     /// the postdominating upper bound in general.)
100     crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
101         assert!(self.universal_regions.is_universal_region(fr1));
102         assert!(self.universal_regions.is_universal_region(fr2));
103         *self
104             .inverse_outlives
105             .postdom_upper_bound(&fr1, &fr2)
106             .unwrap_or(&self.universal_regions.fr_static)
107     }
108
109     /// Finds an "upper bound" for `fr` that is not local. In other
110     /// words, returns the smallest (*) known region `fr1` that (a)
111     /// outlives `fr` and (b) is not local.
112     ///
113     /// (*) If there are multiple competing choices, we return all of them.
114     crate fn non_local_upper_bounds(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
115         debug!("non_local_upper_bound(fr={:?})", fr);
116         let res = self.non_local_bounds(&self.inverse_outlives, fr);
117         assert!(!res.is_empty(), "can't find an upper bound!?");
118         res
119     }
120
121     /// Returns the "postdominating" bound of the set of
122     /// `non_local_upper_bounds` for the given region.
123     crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
124         let upper_bounds = self.non_local_upper_bounds(&fr);
125
126         // In case we find more than one, reduce to one for
127         // convenience.  This is to prevent us from generating more
128         // complex constraints, but it will cause spurious errors.
129         let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds);
130
131         debug!("non_local_bound: post_dom={:?}", post_dom);
132
133         post_dom
134             .and_then(|&post_dom| {
135                 // If the mutual immediate postdom is not local, then
136                 // there is no non-local result we can return.
137                 if !self.universal_regions.is_local_free_region(post_dom) {
138                     Some(post_dom)
139                 } else {
140                     None
141                 }
142             })
143             .unwrap_or(self.universal_regions.fr_static)
144     }
145
146     /// Finds a "lower bound" for `fr` that is not local. In other
147     /// words, returns the largest (*) known region `fr1` that (a) is
148     /// outlived by `fr` and (b) is not local.
149     ///
150     /// (*) If there are multiple competing choices, we pick the "postdominating"
151     /// one. See `TransitiveRelation::postdom_upper_bound` for details.
152     crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
153         debug!("non_local_lower_bound(fr={:?})", fr);
154         let lower_bounds = self.non_local_bounds(&self.outlives, &fr);
155
156         // In case we find more than one, reduce to one for
157         // convenience.  This is to prevent us from generating more
158         // complex constraints, but it will cause spurious errors.
159         let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds);
160
161         debug!("non_local_bound: post_dom={:?}", post_dom);
162
163         post_dom.and_then(|&post_dom| {
164             // If the mutual immediate postdom is not local, then
165             // there is no non-local result we can return.
166             if !self.universal_regions.is_local_free_region(post_dom) {
167                 Some(post_dom)
168             } else {
169                 None
170             }
171         })
172     }
173
174     /// Helper for `non_local_upper_bounds` and `non_local_lower_bounds`.
175     /// Repeatedly invokes `postdom_parent` until we find something that is not
176     /// local. Returns `None` if we never do so.
177     fn non_local_bounds<'a>(
178         &self,
179         relation: &'a TransitiveRelation<RegionVid>,
180         fr0: &'a RegionVid,
181     ) -> Vec<&'a RegionVid> {
182         // This method assumes that `fr0` is one of the universally
183         // quantified region variables.
184         assert!(self.universal_regions.is_universal_region(*fr0));
185
186         let mut external_parents = vec![];
187         let mut queue = vec![fr0];
188
189         // Keep expanding `fr` into its parents until we reach
190         // non-local regions.
191         while let Some(fr) = queue.pop() {
192             if !self.universal_regions.is_local_free_region(*fr) {
193                 external_parents.push(fr);
194                 continue;
195             }
196
197             queue.extend(relation.parents(fr));
198         }
199
200         debug!("non_local_bound: external_parents={:?}", external_parents);
201
202         external_parents
203     }
204
205     /// Returns `true` if fr1 is known to outlive fr2.
206     ///
207     /// This will only ever be true for universally quantified regions.
208     crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
209         self.outlives.contains(&fr1, &fr2)
210     }
211
212     /// Returns a vector of free regions `x` such that `fr1: x` is
213     /// known to hold.
214     crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> {
215         self.outlives.reachable_from(&fr1)
216     }
217
218     /// Returns the _non-transitive_ set of known `outlives` constraints between free regions.
219     crate fn known_outlives(&self) -> impl Iterator<Item = (&RegionVid, &RegionVid)> {
220         self.outlives.base_edges()
221     }
222 }
223
224 struct UniversalRegionRelationsBuilder<'this, 'tcx> {
225     infcx: &'this InferCtxt<'this, 'tcx>,
226     param_env: ty::ParamEnv<'tcx>,
227     universal_regions: Rc<UniversalRegions<'tcx>>,
228     implicit_region_bound: Option<ty::Region<'tcx>>,
229     constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
230
231     // outputs:
232     relations: UniversalRegionRelations<'tcx>,
233     region_bound_pairs: RegionBoundPairs<'tcx>,
234 }
235
236 impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
237     crate fn create(mut self) -> CreateResult<'tcx> {
238         let unnormalized_input_output_tys = self
239             .universal_regions
240             .unnormalized_input_tys
241             .iter()
242             .cloned()
243             .chain(Some(self.universal_regions.unnormalized_output_ty));
244
245         // For each of the input/output types:
246         // - Normalize the type. This will create some region
247         //   constraints, which we buffer up because we are
248         //   not ready to process them yet.
249         // - Then compute the implied bounds. This will adjust
250         //   the `region_bound_pairs` and so forth.
251         // - After this is done, we'll process the constraints, once
252         //   the `relations` is built.
253         let mut normalized_inputs_and_output =
254             Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
255         let constraint_sets: Vec<_> = unnormalized_input_output_tys
256             .flat_map(|ty| {
257                 debug!("build: input_or_output={:?}", ty);
258                 let (ty, constraints1) = self
259                     .param_env
260                     .and(type_op::normalize::Normalize::new(ty))
261                     .fully_perform(self.infcx)
262                     .unwrap_or_else(|_| bug!("failed to normalize {:?}", ty));
263                 let constraints2 = self.add_implied_bounds(ty);
264                 normalized_inputs_and_output.push(ty);
265                 constraints1.into_iter().chain(constraints2)
266             })
267             .collect();
268
269         // Insert the facts we know from the predicates. Why? Why not.
270         let param_env = self.param_env;
271         self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
272
273         // Finally:
274         // - outlives is reflexive, so `'r: 'r` for every region `'r`
275         // - `'static: 'r` for every region `'r`
276         // - `'r: 'fn_body` for every (other) universally quantified
277         //   region `'r`, all of which are provided by our caller
278         let fr_static = self.universal_regions.fr_static;
279         let fr_fn_body = self.universal_regions.fr_fn_body;
280         for fr in self.universal_regions.universal_regions() {
281             debug!("build: relating free region {:?} to itself and to 'static", fr);
282             self.relations.relate_universal_regions(fr, fr);
283             self.relations.relate_universal_regions(fr_static, fr);
284             self.relations.relate_universal_regions(fr, fr_fn_body);
285         }
286
287         for data in &constraint_sets {
288             constraint_conversion::ConstraintConversion::new(
289                 self.infcx,
290                 &self.universal_regions,
291                 &self.region_bound_pairs,
292                 self.implicit_region_bound,
293                 self.param_env,
294                 Locations::All(DUMMY_SP),
295                 ConstraintCategory::Internal,
296                 &mut self.constraints,
297             )
298             .convert_all(data);
299         }
300
301         CreateResult {
302             universal_region_relations: Frozen::freeze(self.relations),
303             region_bound_pairs: self.region_bound_pairs,
304             normalized_inputs_and_output,
305         }
306     }
307
308     /// Update the type of a single local, which should represent
309     /// either the return type of the MIR or one of its arguments. At
310     /// the same time, compute and add any implied bounds that come
311     /// from this local.
312     fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
313         debug!("add_implied_bounds(ty={:?})", ty);
314         let (bounds, constraints) = self
315             .param_env
316             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
317             .fully_perform(self.infcx)
318             .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
319         self.add_outlives_bounds(bounds);
320         constraints
321     }
322
323     /// Registers the `OutlivesBound` items from `outlives_bounds` in
324     /// the outlives relation as well as the region-bound pairs
325     /// listing.
326     fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
327     where
328         I: IntoIterator<Item = OutlivesBound<'tcx>>,
329     {
330         for outlives_bound in outlives_bounds {
331             debug!("add_outlives_bounds(bound={:?})", outlives_bound);
332
333             match outlives_bound {
334                 OutlivesBound::RegionSubRegion(r1, r2) => {
335                     // `where Type:` is lowered to `where Type: 'empty` so that
336                     // we check `Type` is well formed, but there's no use for
337                     // this bound here.
338                     if let ty::ReEmpty(_) = r1 {
339                         return;
340                     }
341
342                     // The bound says that `r1 <= r2`; we store `r2: r1`.
343                     let r1 = self.universal_regions.to_region_vid(r1);
344                     let r2 = self.universal_regions.to_region_vid(r2);
345                     self.relations.relate_universal_regions(r2, r1);
346                 }
347
348                 OutlivesBound::RegionSubParam(r_a, param_b) => {
349                     self.region_bound_pairs.push((r_a, GenericKind::Param(param_b)));
350                 }
351
352                 OutlivesBound::RegionSubProjection(r_a, projection_b) => {
353                     self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b)));
354                 }
355             }
356         }
357     }
358 }
359
360 /// This trait is used by the `impl-trait` constraint code to abstract
361 /// over the `FreeRegionMap` from lexical regions and
362 /// `UniversalRegions` (from NLL)`.
363 impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> {
364     fn sub_free_regions(
365         &self,
366         _tcx: TyCtxt<'tcx>,
367         shorter: ty::Region<'tcx>,
368         longer: ty::Region<'tcx>,
369     ) -> bool {
370         let shorter = shorter.to_region_vid();
371         assert!(self.universal_regions.is_universal_region(shorter));
372         let longer = longer.to_region_vid();
373         assert!(self.universal_regions.is_universal_region(longer));
374         self.outlives(longer, shorter)
375     }
376 }