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