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