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 can_name_all_placeholders(&self, other: Self) -> bool {
171 other.reachable_placeholders.can_be_named_by(self.max_nameable_universe.0)
172 }
173
174 fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> {
176 self.reachable_placeholders.max_universe().filter(|&(placeholder_universe, _)| {
177 !self.max_nameable_universe().can_name(placeholder_universe)
178 })
179 }
180}
181
182impl scc::Annotation for RegionTracker {
183 fn merge_scc(self, other: Self) -> Self {
184 trace!("{:?} << {:?}", self.representative, other.representative);
185
186 Self {
187 representative: self.representative.min(other.representative),
188 max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
189 reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
190 }
191 }
192
193 fn merge_reached(self, other: Self) -> Self {
194 Self {
195 max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
196 reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
197 representative: self.representative,
198 }
199 }
200}
201
202pub(super) fn region_definitions<'tcx>(
206 infcx: &BorrowckInferCtxt<'tcx>,
207 universal_regions: &UniversalRegions<'tcx>,
208) -> (Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>, bool) {
209 let var_infos = infcx.get_region_var_infos();
210 let mut definitions = IndexVec::with_capacity(var_infos.len());
214 let mut has_placeholders = false;
215
216 for info in var_infos.iter() {
217 let origin = match info.origin {
218 RegionVariableOrigin::Nll(origin) => origin,
219 _ => NllRegionVariableOrigin::Existential { name: None },
220 };
221
222 let definition = RegionDefinition { origin, universe: info.universe, external_name: None };
223
224 has_placeholders |= matches!(origin, NllRegionVariableOrigin::Placeholder(_));
225 definitions.push(definition);
226 }
227
228 for (external_name, variable) in universal_regions.named_universal_regions_iter() {
231 debug!("region {:?} has external name {:?}", variable, external_name);
232 definitions[variable].external_name = Some(external_name);
233 }
234 (Frozen::freeze(definitions), has_placeholders)
235}
236
237pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
266 constraints: MirTypeckRegionConstraints<'tcx>,
267 universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
268 infcx: &BorrowckInferCtxt<'tcx>,
269) -> LoweredConstraints<'tcx> {
270 let universal_regions = &universal_region_relations.universal_regions;
271 let (definitions, has_placeholders) = region_definitions(infcx, universal_regions);
272
273 let MirTypeckRegionConstraints {
274 placeholder_indices,
275 placeholder_index_to_region: _,
276 liveness_constraints,
277 mut outlives_constraints,
278 universe_causes,
279 type_tests,
280 } = constraints;
281
282 let fr_static = universal_regions.fr_static;
283 let compute_sccs =
284 |constraints: &OutlivesConstraintSet<'tcx>,
285 annotations: &mut SccAnnotations<'_, 'tcx, RegionTracker>| {
286 ConstraintSccs::new_with_annotation(
287 &constraints.graph(definitions.len()).region_graph(constraints, fr_static),
288 annotations,
289 )
290 };
291
292 let mut scc_annotations = SccAnnotations::init(&definitions);
293 let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);
294
295 if !has_placeholders {
299 debug!("No placeholder regions found; skipping rewriting logic!");
300
301 return LoweredConstraints {
302 type_tests,
303 constraint_sccs,
304 scc_annotations: scc_annotations.scc_to_annotation,
305 definitions,
306 outlives_constraints: Frozen::freeze(outlives_constraints),
307 liveness_constraints,
308 universe_causes,
309 placeholder_indices,
310 };
311 }
312 debug!("Placeholders present; activating placeholder handling logic!");
313
314 let added_constraints = rewrite_placeholder_outlives(
315 &constraint_sccs,
316 &scc_annotations,
317 fr_static,
318 &mut outlives_constraints,
319 );
320
321 let (constraint_sccs, scc_annotations) = if added_constraints {
322 let mut annotations = SccAnnotations::init(&definitions);
323
324 (compute_sccs(&outlives_constraints, &mut annotations), annotations.scc_to_annotation)
329 } else {
330 debug!("No constraints rewritten!");
332 (constraint_sccs, scc_annotations.scc_to_annotation)
333 };
334
335 LoweredConstraints {
336 constraint_sccs,
337 definitions,
338 scc_annotations,
339 outlives_constraints: Frozen::freeze(outlives_constraints),
340 type_tests,
341 liveness_constraints,
342 universe_causes,
343 placeholder_indices,
344 }
345}
346
347fn rewrite_placeholder_outlives<'tcx>(
348 sccs: &Sccs<RegionVid, ConstraintSccIndex>,
349 annotations: &SccAnnotations<'_, '_, RegionTracker>,
350 fr_static: RegionVid,
351 outlives_constraints: &mut OutlivesConstraintSet<'tcx>,
352) -> bool {
353 let mut added_constraints = false;
356
357 let annotations = &annotations.scc_to_annotation;
358
359 for scc in sccs.all_sccs() {
360 if scc == sccs.scc(fr_static) {
364 continue;
365 }
366
367 let annotation = annotations[scc];
368
369 let Some((max_u, max_u_rvid)) = annotation.unnameable_placeholder() else {
370 continue;
371 };
372
373 debug!(
374 "Placeholder universe {max_u:?} is too large for its SCC, represented by {:?}",
375 annotation.representative
376 );
377
378 let blame_to = if annotation.representative.rvid() == max_u_rvid {
387 let small_universed_rvid = annotation.max_nameable_universe.1;
392 debug!(
393 "{small_universed_rvid:?} lowered our universe to {:?}",
394 annotation.max_nameable_universe()
395 );
396 small_universed_rvid
397 } else {
398 max_u_rvid
400 };
401
402 added_constraints = true;
406 outlives_constraints.push(OutlivesConstraint {
407 sup: annotation.representative.rvid(),
408 sub: fr_static,
409 category: ConstraintCategory::OutlivesUnnameablePlaceholder(blame_to),
410 locations: Locations::All(rustc_span::DUMMY_SP),
411 span: rustc_span::DUMMY_SP,
412 variance_info: VarianceDiagInfo::None,
413 from_closure: false,
414 });
415 }
416 added_constraints
417}