1use std::collections::BTreeMap;
2
3use rustc_hir::def_id::DefId;
4use rustc_index::bit_set::SparseBitMatrix;
5use rustc_middle::mir::{Body, Location};
6use rustc_middle::ty::relate::{
7 self, Relate, RelateResult, TypeRelation, relate_args_with_variances,
8};
9use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
10use rustc_mir_dataflow::points::PointIndex;
11
12use super::{
13 ConstraintDirection, LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet,
14 PoloniusLivenessContext,
15};
16use crate::region_infer::values::LivenessValues;
17use crate::universal_regions::UniversalRegions;
18
19impl PoloniusLivenessContext {
20 pub(crate) fn record_live_region_variance<'tcx>(
22 &mut self,
23 tcx: TyCtxt<'tcx>,
24 universal_regions: &UniversalRegions<'tcx>,
25 value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
26 ) {
27 let mut extractor = VarianceExtractor {
28 tcx,
29 ambient_variance: ty::Variance::Covariant,
30 directions: &mut self.live_region_variances,
31 universal_regions,
32 };
33 extractor.relate(value, value).expect("Can't have a type error relating to itself");
34 }
35}
36
37pub(super) fn create_liveness_constraints<'tcx>(
40 body: &Body<'tcx>,
41 liveness: &LivenessValues,
42 live_regions: &SparseBitMatrix<PointIndex, RegionVid>,
43 live_region_variances: &BTreeMap<RegionVid, ConstraintDirection>,
44 universal_regions: &UniversalRegions<'tcx>,
45 localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
46) {
47 for (block, bb) in body.basic_blocks.iter_enumerated() {
48 let statement_count = bb.statements.len();
49 for statement_index in 0..=statement_count {
50 let current_location = Location { block, statement_index };
51 let current_point = liveness.point_from_location(current_location);
52
53 if statement_index < statement_count {
54 let next_location = Location { block, statement_index: statement_index + 1 };
57 let next_point = liveness.point_from_location(next_location);
58 propagate_loans_between_points(
59 current_point,
60 next_point,
61 live_regions,
62 live_region_variances,
63 universal_regions,
64 localized_outlives_constraints,
65 );
66 } else {
67 for successor_block in bb.terminator().successors() {
70 let next_location = Location { block: successor_block, statement_index: 0 };
71 let next_point = liveness.point_from_location(next_location);
72 propagate_loans_between_points(
73 current_point,
74 next_point,
75 live_regions,
76 live_region_variances,
77 universal_regions,
78 localized_outlives_constraints,
79 );
80 }
81 }
82 }
83 }
84}
85
86fn propagate_loans_between_points(
89 current_point: PointIndex,
90 next_point: PointIndex,
91 live_regions: &SparseBitMatrix<PointIndex, RegionVid>,
92 live_region_variances: &BTreeMap<RegionVid, ConstraintDirection>,
93 universal_regions: &UniversalRegions<'_>,
94 localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
95) {
96 for region in universal_regions.universal_regions_iter() {
103 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
104 source: region,
105 from: current_point,
106 target: region,
107 to: next_point,
108 });
109 }
110
111 let Some(next_live_regions) = live_regions.row(next_point) else {
112 return;
114 };
115
116 for region in next_live_regions.iter() {
117 if let Some(&direction) = live_region_variances.get(®ion) {
120 add_liveness_constraint(
121 region,
122 current_point,
123 next_point,
124 direction,
125 localized_outlives_constraints,
126 );
127 } else {
128 let fallback = ConstraintDirection::Bidirectional;
137 add_liveness_constraint(
138 region,
139 current_point,
140 next_point,
141 fallback,
142 localized_outlives_constraints,
143 );
144 }
145 }
146}
147
148fn add_liveness_constraint(
151 region: RegionVid,
152 current_point: PointIndex,
153 next_point: PointIndex,
154 direction: ConstraintDirection,
155 localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
156) {
157 match direction {
158 ConstraintDirection::Forward => {
159 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
162 source: region,
163 from: current_point,
164 target: region,
165 to: next_point,
166 });
167 }
168 ConstraintDirection::Backward => {
169 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
172 source: region,
173 from: next_point,
174 target: region,
175 to: current_point,
176 });
177 }
178 ConstraintDirection::Bidirectional => {
179 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
181 source: region,
182 from: current_point,
183 target: region,
184 to: next_point,
185 });
186 localized_outlives_constraints.push(LocalizedOutlivesConstraint {
187 source: region,
188 from: next_point,
189 target: region,
190 to: current_point,
191 });
192 }
193 }
194}
195
196struct VarianceExtractor<'a, 'tcx> {
200 tcx: TyCtxt<'tcx>,
201 ambient_variance: ty::Variance,
202 directions: &'a mut BTreeMap<RegionVid, ConstraintDirection>,
203 universal_regions: &'a UniversalRegions<'tcx>,
204}
205
206impl<'tcx> VarianceExtractor<'_, 'tcx> {
207 fn record_variance(&mut self, region: ty::Region<'tcx>, variance: ty::Variance) {
208 if region.is_bound() {
218 return;
220 }
221
222 if region.is_erased() {
223 return;
230 }
231
232 let direction = match variance {
233 ty::Covariant => ConstraintDirection::Forward,
234 ty::Contravariant => ConstraintDirection::Backward,
235 ty::Invariant => ConstraintDirection::Bidirectional,
236 ty::Bivariant => {
237 return;
239 }
240 };
241
242 let region = self.universal_regions.to_region_vid(region);
243 self.directions
244 .entry(region)
245 .and_modify(|entry| {
246 if entry != &direction {
250 *entry = ConstraintDirection::Bidirectional;
251 }
252 })
253 .or_insert(direction);
254 }
255}
256
257impl<'tcx> TypeRelation<TyCtxt<'tcx>> for VarianceExtractor<'_, 'tcx> {
258 fn cx(&self) -> TyCtxt<'tcx> {
259 self.tcx
260 }
261
262 fn relate_ty_args(
263 &mut self,
264 a_ty: Ty<'tcx>,
265 _: Ty<'tcx>,
266 def_id: DefId,
267 a_args: ty::GenericArgsRef<'tcx>,
268 b_args: ty::GenericArgsRef<'tcx>,
269 _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
270 ) -> RelateResult<'tcx, Ty<'tcx>> {
271 let variances = self.cx().variances_of(def_id);
272 relate_args_with_variances(self, variances, a_args, b_args)?;
273 Ok(a_ty)
274 }
275
276 fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
277 &mut self,
278 variance: ty::Variance,
279 _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
280 a: T,
281 b: T,
282 ) -> RelateResult<'tcx, T> {
283 let old_ambient_variance = self.ambient_variance;
284 self.ambient_variance = self.ambient_variance.xform(variance);
285 let r = self.relate(a, b)?;
286 self.ambient_variance = old_ambient_variance;
287 Ok(r)
288 }
289
290 fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
291 assert_eq!(a, b); relate::structurally_relate_tys(self, a, b)
293 }
294
295 fn regions(
296 &mut self,
297 a: ty::Region<'tcx>,
298 b: ty::Region<'tcx>,
299 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
300 assert_eq!(a, b); self.record_variance(a, self.ambient_variance);
302 Ok(a)
303 }
304
305 fn consts(
306 &mut self,
307 a: ty::Const<'tcx>,
308 b: ty::Const<'tcx>,
309 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
310 assert_eq!(a, b); relate::structurally_relate_consts(self, a, b)
312 }
313
314 fn binders<T>(
315 &mut self,
316 a: ty::Binder<'tcx, T>,
317 _: ty::Binder<'tcx, T>,
318 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
319 where
320 T: Relate<TyCtxt<'tcx>>,
321 {
322 self.relate(a.skip_binder(), a.skip_binder())?;
323 Ok(a)
324 }
325}