1use rustc_data_structures::frozen::Frozen;
6use rustc_data_structures::fx::FxIndexMap;
7use rustc_data_structures::graph::scc;
8use rustc_data_structures::graph::scc::Sccs;
9use rustc_index::IndexVec;
10use rustc_infer::infer::RegionVariableOrigin;
11use rustc_middle::mir::ConstraintCategory;
12use rustc_middle::ty::{RegionVid, UniverseIndex};
13use tracing::debug;
14
15use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet};
16use crate::consumers::OutlivesConstraint;
17use crate::diagnostics::UniverseInfo;
18use crate::region_infer::values::{LivenessValues, PlaceholderIndices};
19use crate::region_infer::{ConstraintSccs, RegionDefinition, Representative, TypeTest};
20use crate::ty::VarianceDiagInfo;
21use crate::type_check::free_region_relations::UniversalRegionRelations;
22use crate::type_check::{Locations, MirTypeckRegionConstraints};
23use crate::universal_regions::UniversalRegions;
24use crate::{BorrowckInferCtxt, NllRegionVariableOrigin};
25
26pub(crate) struct LoweredConstraints<'tcx> {
29 pub(crate) constraint_sccs: Sccs<RegionVid, ConstraintSccIndex>,
30 pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
31 pub(crate) scc_annotations: IndexVec<ConstraintSccIndex, RegionTracker>,
32 pub(crate) outlives_constraints: Frozen<OutlivesConstraintSet<'tcx>>,
33 pub(crate) type_tests: Vec<TypeTest<'tcx>>,
34 pub(crate) liveness_constraints: LivenessValues,
35 pub(crate) universe_causes: FxIndexMap<UniverseIndex, UniverseInfo<'tcx>>,
36 pub(crate) placeholder_indices: PlaceholderIndices,
37}
38
39impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> {
40 pub(crate) fn init(definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>) -> Self {
41 Self { scc_to_annotation: IndexVec::new(), definitions }
42 }
43}
44
45pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> {
47 pub(crate) scc_to_annotation: IndexVec<ConstraintSccIndex, A>,
48 definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
49}
50
51impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
52 fn new(&self, element: RegionVid) -> RegionTracker {
53 RegionTracker::new(element, &self.definitions[element])
54 }
55
56 fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) {
57 let idx = self.scc_to_annotation.push(annotation);
58 assert!(idx == scc);
59 }
60
61 type Ann = RegionTracker;
62 type SccIdx = ConstraintSccIndex;
63}
64
65#[derive(Copy, Debug, Clone)]
68pub(crate) struct RegionTracker {
69 max_placeholder_universe_reached: UniverseIndex,
72
73 max_nameable_universe: UniverseIndex,
77
78 pub(crate) representative: Representative,
80}
81
82impl RegionTracker {
83 pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
84 let placeholder_universe =
85 if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) {
86 definition.universe
87 } else {
88 UniverseIndex::ROOT
89 };
90
91 Self {
92 max_placeholder_universe_reached: placeholder_universe,
93 max_nameable_universe: definition.universe,
94 representative: Representative::new(rvid, definition),
95 }
96 }
97
98 pub(crate) fn max_nameable_universe(self) -> UniverseIndex {
101 self.max_nameable_universe
102 }
103
104 pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex {
105 self.max_placeholder_universe_reached
106 }
107
108 fn merge_min_max_seen(&mut self, other: &Self) {
109 self.max_placeholder_universe_reached = std::cmp::max(
110 self.max_placeholder_universe_reached,
111 other.max_placeholder_universe_reached,
112 );
113
114 self.max_nameable_universe =
115 std::cmp::min(self.max_nameable_universe, other.max_nameable_universe);
116 }
117
118 pub(crate) fn has_incompatible_universes(&self) -> bool {
122 self.max_nameable_universe().cannot_name(self.max_placeholder_universe_reached)
123 }
124
125 pub(crate) fn universe_compatible_with(&self, other: Self) -> bool {
127 self.max_nameable_universe().can_name(other.max_nameable_universe())
128 || self.max_nameable_universe().can_name(other.max_placeholder_universe_reached)
129 }
130}
131
132impl scc::Annotation for RegionTracker {
133 fn merge_scc(mut self, other: Self) -> Self {
134 self.representative = self.representative.merge_scc(other.representative);
135 self.merge_min_max_seen(&other);
136 self
137 }
138
139 fn merge_reached(mut self, other: Self) -> Self {
140 self.merge_min_max_seen(&other);
142 self
143 }
144}
145
146pub(super) fn region_definitions<'tcx>(
150 infcx: &BorrowckInferCtxt<'tcx>,
151 universal_regions: &UniversalRegions<'tcx>,
152) -> (Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>, bool) {
153 let var_infos = infcx.get_region_var_infos();
154 let mut definitions = IndexVec::with_capacity(var_infos.len());
158 let mut has_placeholders = false;
159
160 for info in var_infos.iter() {
161 let origin = match info.origin {
162 RegionVariableOrigin::Nll(origin) => origin,
163 _ => NllRegionVariableOrigin::Existential { name: None },
164 };
165
166 let definition = RegionDefinition { origin, universe: info.universe, external_name: None };
167
168 has_placeholders |= matches!(origin, NllRegionVariableOrigin::Placeholder(_));
169 definitions.push(definition);
170 }
171
172 for (external_name, variable) in universal_regions.named_universal_regions_iter() {
175 debug!("region {:?} has external name {:?}", variable, external_name);
176 definitions[variable].external_name = Some(external_name);
177 }
178 (Frozen::freeze(definitions), has_placeholders)
179}
180
181pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
210 constraints: MirTypeckRegionConstraints<'tcx>,
211 universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
212 infcx: &BorrowckInferCtxt<'tcx>,
213) -> LoweredConstraints<'tcx> {
214 let universal_regions = &universal_region_relations.universal_regions;
215 let (definitions, has_placeholders) = region_definitions(infcx, universal_regions);
216
217 let MirTypeckRegionConstraints {
218 placeholder_indices,
219 placeholder_index_to_region: _,
220 liveness_constraints,
221 mut outlives_constraints,
222 universe_causes,
223 type_tests,
224 } = constraints;
225
226 let fr_static = universal_regions.fr_static;
227 let compute_sccs =
228 |constraints: &OutlivesConstraintSet<'tcx>,
229 annotations: &mut SccAnnotations<'_, 'tcx, RegionTracker>| {
230 ConstraintSccs::new_with_annotation(
231 &constraints.graph(definitions.len()).region_graph(constraints, fr_static),
232 annotations,
233 )
234 };
235
236 let mut scc_annotations = SccAnnotations::init(&definitions);
237 let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);
238
239 if !has_placeholders {
243 debug!("No placeholder regions found; skipping rewriting logic!");
244
245 return LoweredConstraints {
246 type_tests,
247 constraint_sccs,
248 scc_annotations: scc_annotations.scc_to_annotation,
249 definitions,
250 outlives_constraints: Frozen::freeze(outlives_constraints),
251 liveness_constraints,
252 universe_causes,
253 placeholder_indices,
254 };
255 }
256 debug!("Placeholders present; activating placeholder handling logic!");
257
258 let added_constraints = rewrite_placeholder_outlives(
259 &constraint_sccs,
260 &scc_annotations,
261 fr_static,
262 &mut outlives_constraints,
263 );
264
265 let (constraint_sccs, scc_annotations) = if added_constraints {
266 let mut annotations = SccAnnotations::init(&definitions);
267
268 (compute_sccs(&outlives_constraints, &mut annotations), annotations.scc_to_annotation)
273 } else {
274 debug!("No constraints rewritten!");
276 (constraint_sccs, scc_annotations.scc_to_annotation)
277 };
278
279 LoweredConstraints {
280 constraint_sccs,
281 definitions,
282 scc_annotations,
283 outlives_constraints: Frozen::freeze(outlives_constraints),
284 type_tests,
285 liveness_constraints,
286 universe_causes,
287 placeholder_indices,
288 }
289}
290
291fn rewrite_placeholder_outlives<'tcx>(
292 sccs: &Sccs<RegionVid, ConstraintSccIndex>,
293 annotations: &SccAnnotations<'_, '_, RegionTracker>,
294 fr_static: RegionVid,
295 outlives_constraints: &mut OutlivesConstraintSet<'tcx>,
296) -> bool {
297 let mut added_constraints = false;
300
301 let annotations = &annotations.scc_to_annotation;
302
303 for scc in sccs.all_sccs() {
304 if scc == sccs.scc(fr_static) {
308 continue;
309 }
310
311 let annotation = annotations[scc];
312
313 if annotation.has_incompatible_universes() {
318 let scc_representative_outlives_static = OutlivesConstraint {
323 sup: annotation.representative.rvid(),
324 sub: fr_static,
325 category: ConstraintCategory::IllegalUniverse,
326 locations: Locations::All(rustc_span::DUMMY_SP),
327 span: rustc_span::DUMMY_SP,
328 variance_info: VarianceDiagInfo::None,
329 from_closure: false,
330 };
331 outlives_constraints.push(scc_representative_outlives_static);
332 added_constraints = true;
333 debug!("Added {:?}: 'static!", annotation.representative.rvid());
334 }
335 }
336 added_constraints
337}