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::env::RegionBoundPairs;
6use rustc_infer::infer::region_constraints::GenericKind;
7use rustc_infer::infer::{InferCtxt, outlives};
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::type_check::{Locations, MirTypeckRegionConstraints, constraint_conversion};
18use crate::universal_regions::UniversalRegions;
19
20#[derive(Debug)]
21pub(crate) struct UniversalRegionRelations<'tcx> {
22 pub(crate) universal_regions: UniversalRegions<'tcx>,
23
24 outlives: TransitiveRelation<RegionVid>,
28
29 inverse_outlives: TransitiveRelation<RegionVid>,
34}
35
36type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
41
42pub(crate) struct CreateResult<'tcx> {
43 pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
44 pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
45 pub(crate) known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
46 pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
47}
48
49pub(crate) fn create<'tcx>(
50 infcx: &InferCtxt<'tcx>,
51 param_env: ty::ParamEnv<'tcx>,
52 implicit_region_bound: ty::Region<'tcx>,
53 universal_regions: UniversalRegions<'tcx>,
54 constraints: &mut MirTypeckRegionConstraints<'tcx>,
55) -> CreateResult<'tcx> {
56 UniversalRegionRelationsBuilder {
57 infcx,
58 param_env,
59 implicit_region_bound,
60 constraints,
61 universal_regions,
62 region_bound_pairs: Default::default(),
63 outlives: Default::default(),
64 inverse_outlives: Default::default(),
65 }
66 .create()
67}
68
69impl UniversalRegionRelations<'_> {
70 pub(crate) fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
76 assert!(self.universal_regions.is_universal_region(fr1));
77 assert!(self.universal_regions.is_universal_region(fr2));
78 self.inverse_outlives
79 .postdom_upper_bound(fr1, fr2)
80 .unwrap_or(self.universal_regions.fr_static)
81 }
82
83 pub(crate) fn non_local_upper_bounds(&self, fr: RegionVid) -> Vec<RegionVid> {
89 debug!("non_local_upper_bound(fr={:?})", fr);
90 let res = self.non_local_bounds(&self.inverse_outlives, fr);
91 assert!(!res.is_empty(), "can't find an upper bound!?");
92 res
93 }
94
95 pub(crate) fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
102 debug!("non_local_lower_bound(fr={:?})", fr);
103 let lower_bounds = self.non_local_bounds(&self.outlives, fr);
104
105 let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds);
109
110 debug!("non_local_bound: post_dom={:?}", post_dom);
111
112 post_dom.and_then(|post_dom| {
113 if !self.universal_regions.is_local_free_region(post_dom) {
116 Some(post_dom)
117 } else {
118 None
119 }
120 })
121 }
122
123 fn non_local_bounds(
127 &self,
128 relation: &TransitiveRelation<RegionVid>,
129 fr0: RegionVid,
130 ) -> Vec<RegionVid> {
131 assert!(self.universal_regions.is_universal_region(fr0));
134
135 let mut external_parents = vec![];
136 let mut queue = vec![fr0];
137
138 while let Some(fr) = queue.pop() {
141 if !self.universal_regions.is_local_free_region(fr) {
142 external_parents.push(fr);
143 continue;
144 }
145
146 queue.extend(relation.parents(fr));
147 }
148
149 debug!("non_local_bound: external_parents={:?}", external_parents);
150
151 external_parents
152 }
153
154 pub(crate) fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
158 self.outlives.contains(fr1, fr2)
159 }
160
161 pub(crate) fn equal(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
165 self.outlives.contains(fr1, fr2) && self.outlives.contains(fr2, fr1)
166 }
167
168 pub(crate) fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {
171 self.outlives.reachable_from(fr1)
172 }
173
174 pub(crate) fn known_outlives(&self) -> impl Iterator<Item = (RegionVid, RegionVid)> {
176 self.outlives.base_edges()
177 }
178}
179
180struct UniversalRegionRelationsBuilder<'a, 'tcx> {
181 infcx: &'a InferCtxt<'tcx>,
182 param_env: ty::ParamEnv<'tcx>,
183 universal_regions: UniversalRegions<'tcx>,
184 implicit_region_bound: ty::Region<'tcx>,
185 constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
186
187 outlives: TransitiveRelationBuilder<RegionVid>,
189 inverse_outlives: TransitiveRelationBuilder<RegionVid>,
190 region_bound_pairs: RegionBoundPairs<'tcx>,
191}
192
193impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
194 fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
197 debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
198 self.outlives.add(fr_a, fr_b);
199 self.inverse_outlives.add(fr_b, fr_a);
200 }
201
202 #[instrument(level = "debug", skip(self))]
203 pub(crate) fn create(mut self) -> CreateResult<'tcx> {
204 let tcx = self.infcx.tcx;
205 let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local();
206 let span = tcx.def_span(defining_ty_def_id);
207
208 let param_env = self.param_env;
211 self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
212
213 let fr_static = self.universal_regions.fr_static;
218 let fr_fn_body = self.universal_regions.fr_fn_body;
219 for fr in self.universal_regions.universal_regions_iter() {
220 debug!("build: relating free region {:?} to itself and to 'static", fr);
221 self.relate_universal_regions(fr, fr);
222 self.relate_universal_regions(fr_static, fr);
223 self.relate_universal_regions(fr, fr_fn_body);
224 }
225
226 let mut constraints = vec![];
228 let mut known_type_outlives_obligations = vec![];
229 for bound in param_env.caller_bounds() {
230 if let Some(outlives) = bound.as_type_outlives_clause() {
231 self.normalize_and_push_type_outlives_obligation(
232 outlives,
233 span,
234 &mut known_type_outlives_obligations,
235 &mut constraints,
236 );
237 };
238 }
239
240 let unnormalized_input_output_tys = self
241 .universal_regions
242 .unnormalized_input_tys
243 .iter()
244 .cloned()
245 .chain(Some(self.universal_regions.unnormalized_output_ty));
246
247 let mut normalized_inputs_and_output =
256 Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
257 for ty in unnormalized_input_output_tys {
258 debug!("build: input_or_output={:?}", ty);
259 let constraints_unnorm = self.add_implied_bounds(ty, span);
262 if let Some(c) = constraints_unnorm {
263 constraints.push(c)
264 }
265 let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } =
266 param_env
267 .and(DeeplyNormalize { value: ty })
268 .fully_perform(self.infcx, span)
269 .unwrap_or_else(|guar| TypeOpOutput {
270 output: Ty::new_error(self.infcx.tcx, guar),
271 constraints: None,
272 error_info: None,
273 });
274 if let Some(c) = constraints_normalize {
275 constraints.push(c)
276 }
277
278 if ty != norm_ty {
291 let constraints_norm = self.add_implied_bounds(norm_ty, span);
292 if let Some(c) = constraints_norm {
293 constraints.push(c)
294 }
295 }
296
297 normalized_inputs_and_output.push(norm_ty);
298 }
299
300 if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
302 for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
303 let result: Result<_, ErrorGuaranteed> =
304 param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, span);
305 let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
306 continue;
307 };
308
309 constraints.extend(c);
310
311 let c = self.add_implied_bounds(norm_ty, span);
314 constraints.extend(c);
315 }
316 }
317
318 for c in constraints {
319 constraint_conversion::ConstraintConversion::new(
320 self.infcx,
321 &self.universal_regions,
322 &self.region_bound_pairs,
323 self.implicit_region_bound,
324 param_env,
325 &known_type_outlives_obligations,
326 Locations::All(span),
327 span,
328 ConstraintCategory::Internal,
329 self.constraints,
330 )
331 .convert_all(c);
332 }
333
334 CreateResult {
335 universal_region_relations: Frozen::freeze(UniversalRegionRelations {
336 universal_regions: self.universal_regions,
337 outlives: self.outlives.freeze(),
338 inverse_outlives: self.inverse_outlives.freeze(),
339 }),
340 known_type_outlives_obligations,
341 region_bound_pairs: self.region_bound_pairs,
342 normalized_inputs_and_output,
343 }
344 }
345
346 fn normalize_and_push_type_outlives_obligation(
347 &self,
348 mut outlives: ty::PolyTypeOutlivesPredicate<'tcx>,
349 span: Span,
350 known_type_outlives_obligations: &mut Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
351 constraints: &mut Vec<&QueryRegionConstraints<'tcx>>,
352 ) {
353 if self.infcx.next_trait_solver() {
355 let Ok(TypeOpOutput {
356 output: normalized_outlives,
357 constraints: constraints_normalize,
358 error_info: _,
359 }) = self
360 .param_env
361 .and(DeeplyNormalize { value: outlives })
362 .fully_perform(self.infcx, span)
363 else {
364 self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}"));
365 return;
366 };
367 outlives = normalized_outlives;
368 if let Some(c) = constraints_normalize {
369 constraints.push(c);
370 }
371 }
372
373 known_type_outlives_obligations.push(outlives);
374 }
375
376 #[instrument(level = "debug", skip(self))]
381 fn add_implied_bounds(
382 &mut self,
383 ty: Ty<'tcx>,
384 span: Span,
385 ) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
386 let TypeOpOutput { output: bounds, constraints, .. } = self
387 .param_env
388 .and(type_op::ImpliedOutlivesBounds { ty })
389 .fully_perform(self.infcx, span)
390 .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
391 .ok()?;
392 debug!(?bounds, ?constraints);
393 let bounds = bounds.into_iter().filter(|bound| !bound.has_placeholders());
396 self.add_outlives_bounds(bounds);
397 constraints
398 }
399
400 fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
404 where
405 I: IntoIterator<Item = OutlivesBound<'tcx>>,
406 {
407 for outlives_bound in outlives_bounds {
408 debug!("add_outlives_bounds(bound={:?})", outlives_bound);
409
410 match outlives_bound {
411 OutlivesBound::RegionSubRegion(r1, r2) => {
412 let r1 = self.universal_regions.to_region_vid(r1);
414 let r2 = self.universal_regions.to_region_vid(r2);
415 self.relate_universal_regions(r2, r1);
416 }
417
418 OutlivesBound::RegionSubParam(r_a, param_b) => {
419 self.region_bound_pairs
420 .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
421 }
422
423 OutlivesBound::RegionSubAlias(r_a, alias_b) => {
424 self.region_bound_pairs
425 .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
426 }
427 }
428 }
429 }
430}