1use std::collections::BTreeMap;
2
3use rustc_index::bit_set::SparseBitMatrix;
4use rustc_middle::mir::{Body, Location};
5use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
6use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
7use rustc_mir_dataflow::points::PointIndex;
8
9use super::{
10 ConstraintDirection, LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet,
11 PoloniusLivenessContext,
12};
13use crate::region_infer::values::LivenessValues;
14use crate::universal_regions::UniversalRegions;
15
16impl PoloniusLivenessContext {
17 pub(crate) fn record_live_region_variance<'tcx>(
19 &mut self,
20 tcx: TyCtxt<'tcx>,
21 universal_regions: &UniversalRegions<'tcx>,
22 value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
23 ) {
24 let mut extractor = VarianceExtractor {
25 tcx,
26 ambient_variance: ty::Variance::Covariant,
27 directions: &mut self.live_region_variances,
28 universal_regions,
29 };
30 extractor.relate(value, value).expect("Can't have a type error relating to itself");
31 }
32}
33
34pub(super) fn create_liveness_constraints<'tcx>(
37 body: &Body<'tcx>,
38 liveness: &LivenessValues,
39 live_regions: &SparseBitMatrix<PointIndex, RegionVid>,
40 live_region_variances: &BTreeMap<RegionVid, ConstraintDirection>,
41 universal_regions: &UniversalRegions<'tcx>,
42 localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
43) {
44 for (block, bb) in body.basic_blocks.iter_enumerated() {
45 let statement_count = bb.statements.len();
46 for statement_index in 0..=statement_count {
47 let current_location = Location { block, statement_index };
48 let current_point = liveness.point_from_location(current_location);
49
50 if statement_index < statement_count {
51 let next_location = Location { block, statement_index: statement_index + 1 };
54 let next_point = liveness.point_from_location(next_location);
55 propagate_loans_between_points(
56 current_point,
57 next_point,
58 live_regions,
59 live_region_variances,
60 universal_regions,
61 localized_outlives_constraints,
62 );
63 } else {
64 for successor_block in bb.terminator().successors() {
67 let next_location = Location { block: successor_block, statement_index: 0 };
68 let next_point = liveness.point_from_location(next_location);
69 propagate_loans_between_points(
70 current_point,
71 next_point,
72 live_regions,
73 live_region_variances,
74 universal_regions,
75 localized_outlives_constraints,
76 );
77 }
78 }
79 }
80 }
81}
82
83fn propagate_loans_between_points(
86 current_point: PointIndex,
87 next_point: PointIndex,
88 live_regions: &SparseBitMatrix<PointIndex, RegionVid>,
89 live_region_variances: &BTreeMap<RegionVid, ConstraintDirection>,
90 universal_regions: &UniversalRegions<'_>,
91 localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
92) {
93 for region in universal_regions.universal_regions_iter() {
100 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
101 source: region,
102 from: current_point,
103 target: region,
104 to: next_point,
105 });
106 }
107
108 let Some(next_live_regions) = live_regions.row(next_point) else {
109 return;
111 };
112
113 for region in next_live_regions.iter() {
114 if let Some(&direction) = live_region_variances.get(®ion) {
117 add_liveness_constraint(
118 region,
119 current_point,
120 next_point,
121 direction,
122 localized_outlives_constraints,
123 );
124 } else {
125 let fallback = ConstraintDirection::Bidirectional;
134 add_liveness_constraint(
135 region,
136 current_point,
137 next_point,
138 fallback,
139 localized_outlives_constraints,
140 );
141 }
142 }
143}
144
145fn add_liveness_constraint(
148 region: RegionVid,
149 current_point: PointIndex,
150 next_point: PointIndex,
151 direction: ConstraintDirection,
152 localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
153) {
154 match direction {
155 ConstraintDirection::Forward => {
156 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
159 source: region,
160 from: current_point,
161 target: region,
162 to: next_point,
163 });
164 }
165 ConstraintDirection::Backward => {
166 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
169 source: region,
170 from: next_point,
171 target: region,
172 to: current_point,
173 });
174 }
175 ConstraintDirection::Bidirectional => {
176 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
178 source: region,
179 from: current_point,
180 target: region,
181 to: next_point,
182 });
183 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
184 source: region,
185 from: next_point,
186 target: region,
187 to: current_point,
188 });
189 }
190 }
191}
192
193struct VarianceExtractor<'a, 'tcx> {
197 tcx: TyCtxt<'tcx>,
198 ambient_variance: ty::Variance,
199 directions: &'a mut BTreeMap<RegionVid, ConstraintDirection>,
200 universal_regions: &'a UniversalRegions<'tcx>,
201}
202
203impl<'tcx> VarianceExtractor<'_, 'tcx> {
204 fn record_variance(&mut self, region: ty::Region<'tcx>, variance: ty::Variance) {
205 if region.is_bound() {
215 return;
217 }
218
219 if region.is_erased() {
220 return;
227 }
228
229 let direction = match variance {
230 ty::Covariant => ConstraintDirection::Forward,
231 ty::Contravariant => ConstraintDirection::Backward,
232 ty::Invariant => ConstraintDirection::Bidirectional,
233 ty::Bivariant => {
234 return;
236 }
237 };
238
239 let region = self.universal_regions.to_region_vid(region);
240 self.directions
241 .entry(region)
242 .and_modify(|entry| {
243 if entry != &direction {
247 *entry = ConstraintDirection::Bidirectional;
248 }
249 })
250 .or_insert(direction);
251 }
252}
253
254impl<'tcx> TypeRelation<TyCtxt<'tcx>> for VarianceExtractor<'_, 'tcx> {
255 fn cx(&self) -> TyCtxt<'tcx> {
256 self.tcx
257 }
258
259 fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
260 &mut self,
261 variance: ty::Variance,
262 _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
263 a: T,
264 b: T,
265 ) -> RelateResult<'tcx, T> {
266 let old_ambient_variance = self.ambient_variance;
267 self.ambient_variance = self.ambient_variance.xform(variance);
268 let r = self.relate(a, b)?;
269 self.ambient_variance = old_ambient_variance;
270 Ok(r)
271 }
272
273 fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
274 assert_eq!(a, b); relate::structurally_relate_tys(self, a, b)
276 }
277
278 fn regions(
279 &mut self,
280 a: ty::Region<'tcx>,
281 b: ty::Region<'tcx>,
282 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
283 assert_eq!(a, b); self.record_variance(a, self.ambient_variance);
285 Ok(a)
286 }
287
288 fn consts(
289 &mut self,
290 a: ty::Const<'tcx>,
291 b: ty::Const<'tcx>,
292 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
293 assert_eq!(a, b); relate::structurally_relate_consts(self, a, b)
295 }
296
297 fn binders<T>(
298 &mut self,
299 a: ty::Binder<'tcx, T>,
300 _: ty::Binder<'tcx, T>,
301 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
302 where
303 T: Relate<TyCtxt<'tcx>>,
304 {
305 self.relate(a.skip_binder(), a.skip_binder())?;
306 Ok(a)
307 }
308}