1use rustc_data_structures::frozen::Frozen;
5use rustc_data_structures::fx::FxIndexMap;
6use rustc_data_structures::graph::scc;
7use rustc_data_structures::graph::scc::Sccs;
8use rustc_index::IndexVec;
9use rustc_infer::infer::RegionVariableOrigin;
10use rustc_middle::mir::ConstraintCategory;
11use rustc_middle::ty::{RegionVid, UniverseIndex};
12use tracing::{debug, trace};
13
14use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet};
15use crate::consumers::OutlivesConstraint;
16use crate::diagnostics::UniverseInfo;
17use crate::region_infer::values::{LivenessValues, PlaceholderIndices};
18use crate::region_infer::{ConstraintSccs, RegionDefinition, Representative, TypeTest};
19use crate::ty::VarianceDiagInfo;
20use crate::type_check::free_region_relations::UniversalRegionRelations;
21use crate::type_check::{Locations, MirTypeckRegionConstraints};
22use crate::universal_regions::UniversalRegions;
23use crate::{BorrowckInferCtxt, NllRegionVariableOrigin};
24
25pub(crate) struct LoweredConstraints<'tcx> {
28 pub(crate) constraint_sccs: Sccs<RegionVid, ConstraintSccIndex>,
29 pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
30 pub(crate) scc_annotations: IndexVec<ConstraintSccIndex, RegionTracker>,
31 pub(crate) outlives_constraints: Frozen<OutlivesConstraintSet<'tcx>>,
32 pub(crate) type_tests: Vec<TypeTest<'tcx>>,
33 pub(crate) liveness_constraints: LivenessValues,
34 pub(crate) universe_causes: FxIndexMap<UniverseIndex, UniverseInfo<'tcx>>,
35 pub(crate) placeholder_indices: PlaceholderIndices,
36}
37
38impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> {
39 pub(crate) fn init(definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>) -> Self {
40 Self { scc_to_annotation: IndexVec::new(), definitions }
41 }
42}
43
44pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> {
46 pub(crate) scc_to_annotation: IndexVec<ConstraintSccIndex, A>,
47 definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
48}
49
50impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
51 fn new(&self, element: RegionVid) -> RegionTracker {
52 RegionTracker::new(element, &self.definitions[element])
53 }
54
55 fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) {
56 let idx = self.scc_to_annotation.push(annotation);
57 assert!(idx == scc);
58 }
59
60 type Ann = RegionTracker;
61 type SccIdx = ConstraintSccIndex;
62}
63
64#[derive(Copy, Debug, Clone, PartialEq, Eq)]
65enum PlaceholderReachability {
66 NoPlaceholders,
68 Placeholders {
70 max_universe: (UniverseIndex, RegionVid),
72
73 min_placeholder: RegionVid,
75
76 max_placeholder: RegionVid,
78 },
79}
80
81impl PlaceholderReachability {
82 fn merge(self, other: PlaceholderReachability) -> PlaceholderReachability {
84 use PlaceholderReachability::*;
85 match (self, other) {
86 (NoPlaceholders, NoPlaceholders) => NoPlaceholders,
87 (NoPlaceholders, p @ Placeholders { .. })
88 | (p @ Placeholders { .. }, NoPlaceholders) => p,
89 (
90 Placeholders {
91 min_placeholder: min_pl,
92 max_placeholder: max_pl,
93 max_universe: max_u,
94 },
95 Placeholders { min_placeholder, max_placeholder, max_universe },
96 ) => Placeholders {
97 min_placeholder: min_pl.min(min_placeholder),
98 max_placeholder: max_pl.max(max_placeholder),
99 max_universe: max_u.max(max_universe),
100 },
101 }
102 }
103
104 fn max_universe(&self) -> Option<(UniverseIndex, RegionVid)> {
105 match self {
106 Self::NoPlaceholders => None,
107 Self::Placeholders { max_universe, .. } => Some(*max_universe),
108 }
109 }
110
111 fn can_be_named_by(&self, from: UniverseIndex) -> bool {
114 self.max_universe()
115 .is_none_or(|(max_placeholder_universe, _)| from.can_name(max_placeholder_universe))
116 }
117}
118
119#[derive(Copy, Debug, Clone)]
122pub(crate) struct RegionTracker {
123 reachable_placeholders: PlaceholderReachability,
124
125 max_nameable_universe: (UniverseIndex, RegionVid),
129
130 pub(crate) representative: Representative,
132}
133
134impl RegionTracker {
135 pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
136 let reachable_placeholders =
137 if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) {
138 PlaceholderReachability::Placeholders {
139 max_universe: (definition.universe, rvid),
140 min_placeholder: rvid,
141 max_placeholder: rvid,
142 }
143 } else {
144 PlaceholderReachability::NoPlaceholders
145 };
146
147 Self {
148 reachable_placeholders,
149 max_nameable_universe: (definition.universe, rvid),
150 representative: Representative::new(rvid, definition),
151 }
152 }
153
154 pub(crate) fn max_nameable_universe(self) -> UniverseIndex {
158 self.max_nameable_universe.0
159 }
160
161 pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex {
162 if let Some((universe, _)) = self.reachable_placeholders.max_universe() {
163 universe
164 } else {
165 UniverseIndex::ROOT
166 }
167 }
168
169 pub(crate) fn universe_compatible_with(&self, other: Self) -> bool {
171 self.max_nameable_universe().can_name(other.max_nameable_universe())
175 || other.reachable_placeholders.can_be_named_by(self.max_nameable_universe())
176 }
177
178 fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> {
180 self.reachable_placeholders.max_universe().filter(|&(placeholder_universe, _)| {
181 !self.max_nameable_universe().can_name(placeholder_universe)
182 })
183 }
184}
185
186impl scc::Annotation for RegionTracker {
187 fn merge_scc(self, other: Self) -> Self {
188 trace!("{:?} << {:?}", self.representative, other.representative);
189
190 Self {
191 representative: self.representative.min(other.representative),
192 max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
193 reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
194 }
195 }
196
197 fn merge_reached(self, other: Self) -> Self {
198 Self {
199 max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
200 reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
201 representative: self.representative,
202 }
203 }
204}
205
206pub(super) fn region_definitions<'tcx>(
210 infcx: &BorrowckInferCtxt<'tcx>,
211 universal_regions: &UniversalRegions<'tcx>,
212) -> (Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>, bool) {
213 let var_infos = infcx.get_region_var_infos();
214 let mut definitions = IndexVec::with_capacity(var_infos.len());
218 let mut has_placeholders = false;
219
220 for info in var_infos.iter() {
221 let origin = match info.origin {
222 RegionVariableOrigin::Nll(origin) => origin,
223 _ => NllRegionVariableOrigin::Existential { name: None },
224 };
225
226 let definition = RegionDefinition { origin, universe: info.universe, external_name: None };
227
228 has_placeholders |= matches!(origin, NllRegionVariableOrigin::Placeholder(_));
229 definitions.push(definition);
230 }
231
232 for (external_name, variable) in universal_regions.named_universal_regions_iter() {
235 debug!("region {:?} has external name {:?}", variable, external_name);
236 definitions[variable].external_name = Some(external_name);
237 }
238 (Frozen::freeze(definitions), has_placeholders)
239}
240
241pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
270 constraints: MirTypeckRegionConstraints<'tcx>,
271 universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
272 infcx: &BorrowckInferCtxt<'tcx>,
273) -> LoweredConstraints<'tcx> {
274 let universal_regions = &universal_region_relations.universal_regions;
275 let (definitions, has_placeholders) = region_definitions(infcx, universal_regions);
276
277 let MirTypeckRegionConstraints {
278 placeholder_indices,
279 placeholder_index_to_region: _,
280 liveness_constraints,
281 mut outlives_constraints,
282 universe_causes,
283 type_tests,
284 } = constraints;
285
286 let fr_static = universal_regions.fr_static;
287 let compute_sccs =
288 |constraints: &OutlivesConstraintSet<'tcx>,
289 annotations: &mut SccAnnotations<'_, 'tcx, RegionTracker>| {
290 ConstraintSccs::new_with_annotation(
291 &constraints.graph(definitions.len()).region_graph(constraints, fr_static),
292 annotations,
293 )
294 };
295
296 let mut scc_annotations = SccAnnotations::init(&definitions);
297 let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);
298
299 if !has_placeholders {
303 debug!("No placeholder regions found; skipping rewriting logic!");
304
305 return LoweredConstraints {
306 type_tests,
307 constraint_sccs,
308 scc_annotations: scc_annotations.scc_to_annotation,
309 definitions,
310 outlives_constraints: Frozen::freeze(outlives_constraints),
311 liveness_constraints,
312 universe_causes,
313 placeholder_indices,
314 };
315 }
316 debug!("Placeholders present; activating placeholder handling logic!");
317
318 let added_constraints = rewrite_placeholder_outlives(
319 &constraint_sccs,
320 &scc_annotations,
321 fr_static,
322 &mut outlives_constraints,
323 );
324
325 let (constraint_sccs, scc_annotations) = if added_constraints {
326 let mut annotations = SccAnnotations::init(&definitions);
327
328 (compute_sccs(&outlives_constraints, &mut annotations), annotations.scc_to_annotation)
333 } else {
334 debug!("No constraints rewritten!");
336 (constraint_sccs, scc_annotations.scc_to_annotation)
337 };
338
339 LoweredConstraints {
340 constraint_sccs,
341 definitions,
342 scc_annotations,
343 outlives_constraints: Frozen::freeze(outlives_constraints),
344 type_tests,
345 liveness_constraints,
346 universe_causes,
347 placeholder_indices,
348 }
349}
350
351fn rewrite_placeholder_outlives<'tcx>(
352 sccs: &Sccs<RegionVid, ConstraintSccIndex>,
353 annotations: &SccAnnotations<'_, '_, RegionTracker>,
354 fr_static: RegionVid,
355 outlives_constraints: &mut OutlivesConstraintSet<'tcx>,
356) -> bool {
357 let mut added_constraints = false;
360
361 let annotations = &annotations.scc_to_annotation;
362
363 for scc in sccs.all_sccs() {
364 if scc == sccs.scc(fr_static) {
368 continue;
369 }
370
371 let annotation = annotations[scc];
372
373 let Some((max_u, max_u_rvid)) = annotation.unnameable_placeholder() else {
374 continue;
375 };
376
377 debug!(
378 "Placeholder universe {max_u:?} is too large for its SCC, represented by {:?}",
379 annotation.representative
380 );
381
382 let blame_to = if annotation.representative.rvid() == max_u_rvid {
391 let small_universed_rvid = annotation.max_nameable_universe.1;
396 debug!(
397 "{small_universed_rvid:?} lowered our universe to {:?}",
398 annotation.max_nameable_universe()
399 );
400 small_universed_rvid
401 } else {
402 max_u_rvid
404 };
405
406 added_constraints = true;
410 outlives_constraints.push(OutlivesConstraint {
411 sup: annotation.representative.rvid(),
412 sub: fr_static,
413 category: ConstraintCategory::OutlivesUnnameablePlaceholder(blame_to),
414 locations: Locations::All(rustc_span::DUMMY_SP),
415 span: rustc_span::DUMMY_SP,
416 variance_info: VarianceDiagInfo::None,
417 from_closure: false,
418 });
419 }
420 added_constraints
421}