Skip to main content

rustc_borrowck/polonius/
liveness_constraints.rs

1use std::collections::BTreeMap;
2
3use rustc_hir::def_id::DefId;
4use rustc_middle::ty::relate::{
5    self, Relate, RelateResult, TypeRelation, relate_args_with_variances,
6};
7use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
8
9use super::ConstraintDirection;
10use crate::universal_regions::UniversalRegions;
11
12/// Record the variance of each region contained within the given value.
13pub(crate) fn record_live_region_variance<'tcx>(
14    tcx: TyCtxt<'tcx>,
15    live_region_variances: &mut BTreeMap<RegionVid, ConstraintDirection>,
16    universal_regions: &UniversalRegions<'tcx>,
17    value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
18) {
19    let mut extractor = VarianceExtractor {
20        tcx,
21        ambient_variance: ty::Variance::Covariant,
22        directions: live_region_variances,
23        universal_regions,
24    };
25    extractor.relate(value, value).expect("Can't have a type error relating to itself");
26}
27
28/// Extracts variances for regions contained within types. Follows the same structure as
29/// `rustc_infer`'s `Generalizer`: we try to relate a type with itself to track and extract the
30/// variances of regions.
31struct VarianceExtractor<'a, 'tcx> {
32    tcx: TyCtxt<'tcx>,
33    ambient_variance: ty::Variance,
34    directions: &'a mut BTreeMap<RegionVid, ConstraintDirection>,
35    universal_regions: &'a UniversalRegions<'tcx>,
36}
37
38impl<'tcx> VarianceExtractor<'_, 'tcx> {
39    fn record_variance(&mut self, region: ty::Region<'tcx>, variance: ty::Variance) {
40        // We're only interested in the variance of vars and free regions.
41        //
42        // Note: even if we currently bail for two cases of unexpected region kinds here, missing
43        // variance data is not a soundness problem: the regions with missing variance will still be
44        // present in the constraint graph as they are live, and liveness edges construction has a
45        // fallback for this case.
46        //
47        // FIXME: that being said, we need to investigate these cases better to not ignore regions
48        // in general.
49        if region.is_bound() {
50            // We ignore these because they cannot be turned into the vids we need.
51            return;
52        }
53
54        if region.is_erased() {
55            // These cannot be turned into a vid either, and we also ignore them: the fact that they
56            // show up here looks like either an issue upstream or a combination with unexpectedly
57            // continuing compilation too far when we're in a tainted by errors situation.
58            //
59            // FIXME: investigate the `generic_const_exprs` test that triggers this issue,
60            // `ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs`
61            return;
62        }
63
64        let direction = match variance {
65            ty::Covariant => ConstraintDirection::Forward,
66            ty::Contravariant => ConstraintDirection::Backward,
67            ty::Invariant => ConstraintDirection::Bidirectional,
68            ty::Bivariant => {
69                // We don't add edges for bivariant cases.
70                return;
71            }
72        };
73
74        let region = self.universal_regions.to_region_vid(region);
75        self.directions
76            .entry(region)
77            .and_modify(|entry| {
78                // If there's already a recorded direction for this region, we combine the two:
79                // - combining the same direction is idempotent
80                // - combining different directions is trivially bidirectional
81                if entry != &direction {
82                    *entry = ConstraintDirection::Bidirectional;
83                }
84            })
85            .or_insert(direction);
86    }
87}
88
89impl<'tcx> TypeRelation<TyCtxt<'tcx>> for VarianceExtractor<'_, 'tcx> {
90    fn cx(&self) -> TyCtxt<'tcx> {
91        self.tcx
92    }
93
94    fn relate_ty_args(
95        &mut self,
96        a_ty: Ty<'tcx>,
97        _: Ty<'tcx>,
98        def_id: DefId,
99        a_args: ty::GenericArgsRef<'tcx>,
100        b_args: ty::GenericArgsRef<'tcx>,
101        _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
102    ) -> RelateResult<'tcx, Ty<'tcx>> {
103        let variances = self.cx().variances_of(def_id);
104        relate_args_with_variances(self, variances, a_args, b_args)?;
105        Ok(a_ty)
106    }
107
108    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
109        &mut self,
110        variance: ty::Variance,
111        _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
112        a: T,
113        b: T,
114    ) -> RelateResult<'tcx, T> {
115        let old_ambient_variance = self.ambient_variance;
116        self.ambient_variance = self.ambient_variance.xform(variance);
117        let r = self.relate(a, b)?;
118        self.ambient_variance = old_ambient_variance;
119        Ok(r)
120    }
121
122    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
123        {
    match (&a, &b) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(a, b); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
124        relate::structurally_relate_tys(self, a, b)
125    }
126
127    fn regions(
128        &mut self,
129        a: ty::Region<'tcx>,
130        b: ty::Region<'tcx>,
131    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
132        {
    match (&a, &b) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(a, b); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
133        self.record_variance(a, self.ambient_variance);
134        Ok(a)
135    }
136
137    fn consts(
138        &mut self,
139        a: ty::Const<'tcx>,
140        b: ty::Const<'tcx>,
141    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
142        {
    match (&a, &b) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(a, b); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
143        relate::structurally_relate_consts(self, a, b)
144    }
145
146    fn binders<T>(
147        &mut self,
148        a: ty::Binder<'tcx, T>,
149        _: ty::Binder<'tcx, T>,
150    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
151    where
152        T: Relate<TyCtxt<'tcx>>,
153    {
154        self.relate(a.skip_binder(), a.skip_binder())?;
155        Ok(a)
156    }
157}