Skip to content

Commit de049e6

Browse files
committed
add variance recording
Following the Generalizer's structure, relating e.g. a type with itself will allow tracking the variance wrt the contained regions.
1 parent 42f28cb commit de049e6

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use std::collections::BTreeMap;
2+
3+
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
4+
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
5+
6+
use super::{ConstraintDirection, PoloniusContext};
7+
use crate::universal_regions::UniversalRegions;
8+
9+
impl PoloniusContext {
10+
/// Record the variance of each region contained within the given value.
11+
pub(crate) fn record_live_region_variance<'tcx>(
12+
&mut self,
13+
tcx: TyCtxt<'tcx>,
14+
universal_regions: &UniversalRegions<'tcx>,
15+
value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
16+
) {
17+
let mut extractor = VarianceExtractor {
18+
tcx,
19+
ambient_variance: ty::Variance::Covariant,
20+
directions: &mut self.live_region_variances,
21+
universal_regions,
22+
};
23+
extractor.relate(value, value).expect("Can't have a type error relating to itself");
24+
}
25+
}
26+
27+
/// Extracts variances for regions contained within types. Follows the same structure as
28+
/// `rustc_infer`'s `Generalizer`: we try to relate a type with itself to track and extract the
29+
/// variances of regions.
30+
struct VarianceExtractor<'a, 'tcx> {
31+
tcx: TyCtxt<'tcx>,
32+
ambient_variance: ty::Variance,
33+
directions: &'a mut BTreeMap<RegionVid, ConstraintDirection>,
34+
universal_regions: &'a UniversalRegions<'tcx>,
35+
}
36+
37+
impl<'tcx> VarianceExtractor<'_, 'tcx> {
38+
fn record_variance(&mut self, region: ty::Region<'tcx>, variance: ty::Variance) {
39+
// We're only interested in the variance of vars and free regions.
40+
41+
if region.is_bound() || region.is_erased() {
42+
// ignore these
43+
return;
44+
}
45+
46+
let direction = match variance {
47+
ty::Variance::Covariant => ConstraintDirection::Forward,
48+
ty::Variance::Contravariant => ConstraintDirection::Backward,
49+
ty::Variance::Invariant => ConstraintDirection::Bidirectional,
50+
ty::Variance::Bivariant => {
51+
// We don't add edges for bivariant cases.
52+
return;
53+
}
54+
};
55+
56+
let region = self.universal_regions.to_region_vid(region);
57+
self.directions
58+
.entry(region)
59+
.and_modify(|entry| {
60+
// If there's already a recorded direction for this region, we combine the two:
61+
// - combining the same direction is idempotent
62+
// - combining different directions is trivially bidirectional
63+
if entry != &direction {
64+
*entry = ConstraintDirection::Bidirectional;
65+
}
66+
})
67+
.or_insert(direction);
68+
}
69+
}
70+
71+
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for VarianceExtractor<'_, 'tcx> {
72+
fn cx(&self) -> TyCtxt<'tcx> {
73+
self.tcx
74+
}
75+
76+
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
77+
&mut self,
78+
variance: ty::Variance,
79+
_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
80+
a: T,
81+
b: T,
82+
) -> RelateResult<'tcx, T> {
83+
let old_ambient_variance = self.ambient_variance;
84+
self.ambient_variance = self.ambient_variance.xform(variance);
85+
let r = self.relate(a, b)?;
86+
self.ambient_variance = old_ambient_variance;
87+
Ok(r)
88+
}
89+
90+
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
91+
assert_eq!(a, b); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
92+
relate::structurally_relate_tys(self, a, b)
93+
}
94+
95+
fn regions(
96+
&mut self,
97+
a: ty::Region<'tcx>,
98+
b: ty::Region<'tcx>,
99+
) -> RelateResult<'tcx, ty::Region<'tcx>> {
100+
assert_eq!(a, b); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
101+
self.record_variance(a, self.ambient_variance);
102+
Ok(a)
103+
}
104+
105+
fn consts(
106+
&mut self,
107+
a: ty::Const<'tcx>,
108+
b: ty::Const<'tcx>,
109+
) -> RelateResult<'tcx, ty::Const<'tcx>> {
110+
assert_eq!(a, b); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
111+
relate::structurally_relate_consts(self, a, b)
112+
}
113+
114+
fn binders<T>(
115+
&mut self,
116+
a: ty::Binder<'tcx, T>,
117+
_: ty::Binder<'tcx, T>,
118+
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
119+
where
120+
T: Relate<TyCtxt<'tcx>>,
121+
{
122+
self.relate(a.skip_binder(), a.skip_binder())?;
123+
Ok(a)
124+
}
125+
}

compiler/rustc_borrowck/src/polonius/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
mod constraints;
3737
mod dump;
3838
pub(crate) mod legacy;
39+
mod liveness_constraints;
3940

4041
use std::collections::BTreeMap;
4142

0 commit comments

Comments
 (0)