rustc_borrowck/type_check/
free_region_relations.rs1use rustc_data_structures::frozen::Frozen;
2use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
3use rustc_hir::def::DefKind;
4use rustc_infer::infer::canonical::QueryRegionConstraints;
5use rustc_infer::infer::outlives;
6use rustc_infer::infer::outlives::env::RegionBoundPairs;
7use rustc_infer::infer::region_constraints::GenericKind;
8use rustc_infer::traits::query::type_op::DeeplyNormalize;
9use rustc_middle::mir::ConstraintCategory;
10use rustc_middle::traits::query::OutlivesBound;
11use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
12use rustc_span::{ErrorGuaranteed, Span};
13use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
14use tracing::{debug, instrument};
15use type_op::TypeOpOutput;
16
17use crate::BorrowckInferCtxt;
18use crate::type_check::{Locations, MirTypeckRegionConstraints, constraint_conversion};
19use crate::universal_regions::UniversalRegions;
20
21#[derive(Debug)]
22#[derive(Clone)] pub(crate) struct UniversalRegionRelations<'tcx> {
24 pub(crate) universal_regions: UniversalRegions<'tcx>,
25
26 outlives: TransitiveRelation<RegionVid>,
30
31 inverse_outlives: TransitiveRelation<RegionVid>,
36}
37
38type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
43
44pub(crate) struct CreateResult<'tcx> {
45 pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
46 pub(crate) region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>,
47 pub(crate) known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>,
48 pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
49}
50
51pub(crate) fn create<'tcx>(
52 infcx: &BorrowckInferCtxt<'tcx>,
53 universal_regions: UniversalRegions<'tcx>,
54 constraints: &mut MirTypeckRegionConstraints<'tcx>,
55) -> CreateResult<'tcx> {
56 UniversalRegionRelationsBuilder {
57 infcx,
58 constraints,
59 universal_regions,
60 region_bound_pairs: Default::default(),
61 outlives: Default::default(),
62 inverse_outlives: Default::default(),
63 }
64 .create()
65}
66
67impl UniversalRegionRelations<'_> {
68 pub(crate) fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
74 assert!(self.universal_regions.is_universal_region(fr1));
75 assert!(self.universal_regions.is_universal_region(fr2));
76 self.inverse_outlives
77 .postdom_upper_bound(fr1, fr2)
78 .unwrap_or(self.universal_regions.fr_static)
79 }
80
81 pub(crate) fn non_local_upper_bounds(&self, fr: RegionVid) -> Vec<RegionVid> {
87 debug!("non_local_upper_bound(fr={:?})", fr);
88 let res = self.non_local_bounds(&self.inverse_outlives, fr);
89 assert!(!res.is_empty(), "can't find an upper bound!?");
90 res
91 }
92
93 pub(crate) fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
100 debug!("non_local_lower_bound(fr={:?})", fr);
101 let lower_bounds = self.non_local_bounds(&self.outlives, fr);
102
103 let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds);
107
108 debug!("non_local_bound: post_dom={:?}", post_dom);
109
110 post_dom.and_then(|post_dom| {
111 if !self.universal_regions.is_local_free_region(post_dom) {
114 Some(post_dom)
115 } else {
116 None
117 }
118 })
119 }
120
121 fn non_local_bounds(
125 &self,
126 relation: &TransitiveRelation<RegionVid>,
127 fr0: RegionVid,
128 ) -> Vec<RegionVid> {
129 assert!(self.universal_regions.is_universal_region(fr0));
132
133 let mut external_parents = vec![];
134
135 let mut queue = vec![relation.minimal_scc_representative(fr0)];
136
137 while let Some(fr) = queue.pop() {
140 if !self.universal_regions.is_local_free_region(fr) {
141 external_parents.push(fr);
142 continue;
143 }
144
145 queue.extend(relation.parents(fr));
146 }
147
148 debug!("non_local_bound: external_parents={:?}", external_parents);
149
150 external_parents
151 }
152
153 pub(crate) fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
157 self.outlives.contains(fr1, fr2)
158 }
159
160 pub(crate) fn equal(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
164 self.outlives.contains(fr1, fr2) && self.outlives.contains(fr2, fr1)
165 }
166
167 pub(crate) fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {
170 self.outlives.reachable_from(fr1)
171 }
172
173 pub(crate) fn known_outlives(&self) -> impl Iterator<Item = (RegionVid, RegionVid)> {
175 self.outlives.base_edges()
176 }
177}
178
179struct UniversalRegionRelationsBuilder<'a, 'tcx> {
180 infcx: &'a BorrowckInferCtxt<'tcx>,
181 universal_regions: UniversalRegions<'tcx>,
182 constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
183
184 outlives: TransitiveRelationBuilder<RegionVid>,
186 inverse_outlives: TransitiveRelationBuilder<RegionVid>,
187 region_bound_pairs: RegionBoundPairs<'tcx>,
188}
189
190impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
191 fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
194 debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
195 self.outlives.add(fr_a, fr_b);
196 self.inverse_outlives.add(fr_b, fr_a);
197 }
198
199 #[instrument(level = "debug", skip(self))]
200 pub(crate) fn create(mut self) -> CreateResult<'tcx> {
201 let tcx = self.infcx.tcx;
202 let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local();
203 let span = tcx.def_span(defining_ty_def_id);
204
205 let param_env = self.infcx.param_env;
208 self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
209
210 let fr_static = self.universal_regions.fr_static;
215 let fr_fn_body = self.universal_regions.fr_fn_body;
216 for fr in self.universal_regions.universal_regions_iter() {
217 debug!("build: relating free region {:?} to itself and to 'static", fr);
218 self.relate_universal_regions(fr, fr);
219 self.relate_universal_regions(fr_static, fr);
220 self.relate_universal_regions(fr, fr_fn_body);
221 }
222
223 let mut constraints = vec![];
225 let mut known_type_outlives_obligations = vec![];
226 for bound in param_env.caller_bounds() {
227 if let Some(outlives) = bound.as_type_outlives_clause() {
228 self.normalize_and_push_type_outlives_obligation(
229 outlives,
230 span,
231 &mut known_type_outlives_obligations,
232 &mut constraints,
233 );
234 };
235 }
236
237 let unnormalized_input_output_tys = self
238 .universal_regions
239 .unnormalized_input_tys
240 .iter()
241 .cloned()
242 .chain(Some(self.universal_regions.unnormalized_output_ty));
243
244 let mut normalized_inputs_and_output =
253 Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
254 for ty in unnormalized_input_output_tys {
255 debug!("build: input_or_output={:?}", ty);
256 let constraints_unnorm = self.add_implied_bounds(ty, span);
259 if let Some(c) = constraints_unnorm {
260 constraints.push(c)
261 }
262 let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } =
263 param_env
264 .and(DeeplyNormalize { value: ty })
265 .fully_perform(self.infcx, self.infcx.root_def_id, span)
266 .unwrap_or_else(|guar| TypeOpOutput {
267 output: Ty::new_error(self.infcx.tcx, guar),
268 constraints: None,
269 error_info: None,
270 });
271 if let Some(c) = constraints_normalize {
272 constraints.push(c)
273 }
274
275 if ty != norm_ty {
288 let constraints_norm = self.add_implied_bounds(norm_ty, span);
289 if let Some(c) = constraints_norm {
290 constraints.push(c)
291 }
292 }
293
294 normalized_inputs_and_output.push(norm_ty);
295 }
296
297 if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
299 for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
300 let result: Result<_, ErrorGuaranteed> = param_env
301 .and(DeeplyNormalize { value: ty })
302 .fully_perform(self.infcx, self.infcx.root_def_id, span);
303 let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
304 continue;
305 };
306
307 constraints.extend(c);
308
309 let c = self.add_implied_bounds(norm_ty, span);
312 constraints.extend(c);
313 }
314 }
315
316 for c in constraints {
317 constraint_conversion::ConstraintConversion::new(
318 self.infcx,
319 &self.universal_regions,
320 &self.region_bound_pairs,
321 &known_type_outlives_obligations,
322 Locations::All(span),
323 span,
324 ConstraintCategory::Internal,
325 self.constraints,
326 )
327 .convert_all(c);
328 }
329
330 CreateResult {
331 universal_region_relations: Frozen::freeze(UniversalRegionRelations {
332 universal_regions: self.universal_regions,
333 outlives: self.outlives.freeze(),
334 inverse_outlives: self.inverse_outlives.freeze(),
335 }),
336 known_type_outlives_obligations: Frozen::freeze(known_type_outlives_obligations),
337 region_bound_pairs: Frozen::freeze(self.region_bound_pairs),
338 normalized_inputs_and_output,
339 }
340 }
341
342 fn normalize_and_push_type_outlives_obligation(
343 &self,
344 mut outlives: ty::PolyTypeOutlivesPredicate<'tcx>,
345 span: Span,
346 known_type_outlives_obligations: &mut Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
347 constraints: &mut Vec<&QueryRegionConstraints<'tcx>>,
348 ) {
349 if self.infcx.next_trait_solver() {
351 let Ok(TypeOpOutput {
352 output: normalized_outlives,
353 constraints: constraints_normalize,
354 error_info: _,
355 }) = self.infcx.param_env.and(DeeplyNormalize { value: outlives }).fully_perform(
356 self.infcx,
357 self.infcx.root_def_id,
358 span,
359 )
360 else {
361 self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}"));
362 return;
363 };
364 outlives = normalized_outlives;
365 if let Some(c) = constraints_normalize {
366 constraints.push(c);
367 }
368 }
369
370 known_type_outlives_obligations.push(outlives);
371 }
372
373 #[instrument(level = "debug", skip(self))]
378 fn add_implied_bounds(
379 &mut self,
380 ty: Ty<'tcx>,
381 span: Span,
382 ) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
383 let TypeOpOutput { output: bounds, constraints, .. } = self
384 .infcx
385 .param_env
386 .and(type_op::ImpliedOutlivesBounds { ty })
387 .fully_perform(self.infcx, self.infcx.root_def_id, span)
388 .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
389 .ok()?;
390 debug!(?bounds, ?constraints);
391 let bounds = bounds.into_iter().filter(|bound| !bound.has_placeholders());
394 self.add_outlives_bounds(bounds);
395 constraints
396 }
397
398 fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
402 where
403 I: IntoIterator<Item = OutlivesBound<'tcx>>,
404 {
405 for outlives_bound in outlives_bounds {
406 debug!("add_outlives_bounds(bound={:?})", outlives_bound);
407
408 match outlives_bound {
409 OutlivesBound::RegionSubRegion(r1, r2) => {
410 let r1 = self.universal_regions.to_region_vid(r1);
412 let r2 = self.universal_regions.to_region_vid(r2);
413 self.relate_universal_regions(r2, r1);
414 }
415
416 OutlivesBound::RegionSubParam(r_a, param_b) => {
417 self.region_bound_pairs
418 .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
419 }
420
421 OutlivesBound::RegionSubAlias(r_a, alias_b) => {
422 self.region_bound_pairs
423 .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
424 }
425 }
426 }
427 }
428}