rustc_infer/infer/outlives/
mod.rs

1//! Various code related to computing outlives relations.
2
3use rustc_data_structures::undo_log::UndoLogs;
4use rustc_middle::traits::query::{NoSolution, OutlivesBound};
5use rustc_middle::ty;
6use tracing::instrument;
7
8use self::env::OutlivesEnvironment;
9use super::region_constraints::{RegionConstraintData, UndoLog};
10use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
11use crate::infer::free_regions::RegionRelations;
12use crate::infer::lexical_region_resolve;
13use crate::infer::region_constraints::Constraint;
14
15pub mod env;
16pub mod for_liveness;
17pub mod obligations;
18pub mod test_type_match;
19pub(crate) mod verify;
20
21#[instrument(level = "debug", skip(param_env), ret)]
22pub fn explicit_outlives_bounds<'tcx>(
23    param_env: ty::ParamEnv<'tcx>,
24) -> impl Iterator<Item = OutlivesBound<'tcx>> {
25    param_env
26        .caller_bounds()
27        .into_iter()
28        .filter_map(ty::Clause::as_region_outlives_clause)
29        .filter_map(ty::Binder::no_bound_vars)
30        .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a))
31}
32
33impl<'tcx> InferCtxt<'tcx> {
34    /// Process the region constraints and return any errors that
35    /// result. After this, no more unification operations should be
36    /// done -- or the compiler will panic -- but it is legal to use
37    /// `resolve_vars_if_possible` as well as `fully_resolve`.
38    ///
39    /// If you are in a crate that has access to `rustc_trait_selection`,
40    /// then it's probably better to use `resolve_regions`,
41    /// which knows how to normalize registered region obligations.
42    #[must_use]
43    pub fn resolve_regions_with_normalize(
44        &self,
45        outlives_env: &OutlivesEnvironment<'tcx>,
46        deeply_normalize_ty: impl Fn(
47            ty::PolyTypeOutlivesPredicate<'tcx>,
48            SubregionOrigin<'tcx>,
49        ) -> Result<ty::PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
50    ) -> Vec<RegionResolutionError<'tcx>> {
51        match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) {
52            Ok(()) => {}
53            Err((clause, origin)) => {
54                return vec![RegionResolutionError::CannotNormalize(clause, origin)];
55            }
56        };
57
58        let mut storage = {
59            let mut inner = self.inner.borrow_mut();
60            let inner = &mut *inner;
61            assert!(
62                self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(),
63                "region_obligations not empty: {:#?}",
64                inner.region_obligations,
65            );
66            assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&inner.undo_log));
67            inner.region_constraint_storage.take().expect("regions already resolved")
68        };
69
70        // Filter out any region-region outlives assumptions that are implied by
71        // coroutine well-formedness.
72        if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions {
73            storage.data.constraints.retain(|(constraint, _)| match *constraint {
74                Constraint::RegSubReg(r1, r2) => !outlives_env
75                    .higher_ranked_assumptions()
76                    .contains(&ty::OutlivesPredicate(r2.into(), r1)),
77                _ => true,
78            });
79        }
80
81        let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
82
83        let (lexical_region_resolutions, errors) =
84            lexical_region_resolve::resolve(region_rels, storage.var_infos, storage.data);
85
86        let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
87        assert!(old_value.is_none());
88
89        errors
90    }
91
92    /// Obtains (and clears) the current set of region
93    /// constraints. The inference context is still usable: further
94    /// unifications will simply add new constraints.
95    ///
96    /// This method is not meant to be used with normal lexical region
97    /// resolution. Rather, it is used in the NLL mode as a kind of
98    /// interim hack: basically we run normal type-check and generate
99    /// region constraints as normal, but then we take them and
100    /// translate them into the form that the NLL solver
101    /// understands. See the NLL module for mode details.
102    pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
103        assert!(
104            self.inner.borrow().region_obligations.is_empty(),
105            "region_obligations not empty: {:#?}",
106            self.inner.borrow().region_obligations
107        );
108        assert!(
109            self.inner.borrow().region_assumptions.is_empty(),
110            "region_assumptions not empty: {:#?}",
111            self.inner.borrow().region_assumptions
112        );
113
114        self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
115    }
116
117    /// Gives temporary access to the region constraint data.
118    pub fn with_region_constraints<R>(
119        &self,
120        op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
121    ) -> R {
122        let mut inner = self.inner.borrow_mut();
123        op(inner.unwrap_region_constraints().data())
124    }
125}