Skip to main content

rustc_borrowck/polonius/
liveness_constraints.rs

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