rustc_infer/infer/relate/
higher_ranked.rs

1//! Helper routines for higher-ranked things. See the `doc` module at
2//! the end of the file for details.
3
4use rustc_middle::ty::fold::FnMutDelegate;
5use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
6use tracing::{debug, instrument};
7
8use super::RelateResult;
9use crate::infer::InferCtxt;
10use crate::infer::snapshot::CombinedSnapshot;
11
12impl<'tcx> InferCtxt<'tcx> {
13    /// Replaces all bound variables (lifetimes, types, and constants) bound by
14    /// `binder` with placeholder variables in a new universe. This means that the
15    /// new placeholders can only be named by inference variables created after
16    /// this method has been called.
17    ///
18    /// This is the first step of checking subtyping when higher-ranked things are involved.
19    /// For more details visit the relevant sections of the [rustc dev guide].
20    ///
21    /// `fn enter_forall` should be preferred over this method.
22    ///
23    /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
24    #[instrument(level = "debug", skip(self), ret)]
25    pub fn enter_forall_and_leak_universe<T>(&self, binder: ty::Binder<'tcx, T>) -> T
26    where
27        T: TypeFoldable<TyCtxt<'tcx>>,
28    {
29        if let Some(inner) = binder.clone().no_bound_vars() {
30            return inner;
31        }
32
33        let next_universe = self.create_next_universe();
34
35        let delegate = FnMutDelegate {
36            regions: &mut |br: ty::BoundRegion| {
37                ty::Region::new_placeholder(
38                    self.tcx,
39                    ty::PlaceholderRegion { universe: next_universe, bound: br },
40                )
41            },
42            types: &mut |bound_ty: ty::BoundTy| {
43                Ty::new_placeholder(
44                    self.tcx,
45                    ty::PlaceholderType { universe: next_universe, bound: bound_ty },
46                )
47            },
48            consts: &mut |bound_var: ty::BoundVar| {
49                ty::Const::new_placeholder(
50                    self.tcx,
51                    ty::PlaceholderConst { universe: next_universe, bound: bound_var },
52                )
53            },
54        };
55
56        debug!(?next_universe);
57        self.tcx.replace_bound_vars_uncached(binder, delegate)
58    }
59
60    /// Replaces all bound variables (lifetimes, types, and constants) bound by
61    /// `binder` with placeholder variables in a new universe and then calls the
62    /// closure `f` with the instantiated value. The new placeholders can only be
63    /// named by inference variables created inside of the closure `f` or afterwards.
64    ///
65    /// This is the first step of checking subtyping when higher-ranked things are involved.
66    /// For more details visit the relevant sections of the [rustc dev guide].
67    ///
68    /// This method should be preferred over `fn enter_forall_and_leak_universe`.
69    ///
70    /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
71    #[instrument(level = "debug", skip(self, f))]
72    pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U
73    where
74        T: TypeFoldable<TyCtxt<'tcx>>,
75    {
76        // FIXME: currently we do nothing to prevent placeholders with the new universe being
77        // used after exiting `f`. For example region subtyping can result in outlives constraints
78        // that name placeholders created in this function. Nested goals from type relations can
79        // also contain placeholders created by this function.
80        let value = self.enter_forall_and_leak_universe(forall);
81        debug!(?value);
82        f(value)
83    }
84
85    /// See [RegionConstraintCollector::leak_check][1]. We only check placeholder
86    /// leaking into `outer_universe`, i.e. placeholders which cannot be named by that
87    /// universe.
88    ///
89    /// [1]: crate::infer::region_constraints::RegionConstraintCollector::leak_check
90    pub fn leak_check(
91        &self,
92        outer_universe: ty::UniverseIndex,
93        only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>,
94    ) -> RelateResult<'tcx, ()> {
95        // If the user gave `-Zno-leak-check`, or we have been
96        // configured to skip the leak check, then skip the leak check
97        // completely. The leak check is deprecated. Any legitimate
98        // subtyping errors that it would have caught will now be
99        // caught later on, during region checking. However, we
100        // continue to use it for a transition period.
101        if self.tcx.sess.opts.unstable_opts.no_leak_check || self.skip_leak_check {
102            return Ok(());
103        }
104
105        self.inner.borrow_mut().unwrap_region_constraints().leak_check(
106            self.tcx,
107            outer_universe,
108            self.universe(),
109            only_consider_snapshot,
110        )
111    }
112}