Skip to main content

rustc_infer/infer/outlives/
mod.rs

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