hir_ty/next_solver/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_type_ir::TypeFoldable;
5use tracing::{debug, instrument};
6
7use crate::next_solver::fold::FnMutDelegate;
8use crate::next_solver::infer::InferCtxt;
9use crate::next_solver::{
10    Binder, BoundConst, BoundRegion, BoundTy, Const, DbInterner, PlaceholderConst,
11    PlaceholderRegion, PlaceholderTy, Region, Ty,
12};
13
14impl<'db> InferCtxt<'db> {
15    /// Replaces all bound variables (lifetimes, types, and constants) bound by
16    /// `binder` with placeholder variables in a new universe. This means that the
17    /// new placeholders can only be named by inference variables created after
18    /// this method has been called.
19    ///
20    /// This is the first step of checking subtyping when higher-ranked things are involved.
21    /// For more details visit the relevant sections of the [rustc dev guide].
22    ///
23    /// `fn enter_forall` should be preferred over this method.
24    ///
25    /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
26    #[instrument(level = "debug", skip(self), ret)]
27    pub fn enter_forall_and_leak_universe<T>(&self, binder: Binder<'db, T>) -> T
28    where
29        T: TypeFoldable<DbInterner<'db>> + Clone,
30    {
31        if let Some(inner) = binder.clone().no_bound_vars() {
32            return inner;
33        }
34
35        let next_universe = self.create_next_universe();
36
37        let delegate = FnMutDelegate {
38            regions: &mut |br: BoundRegion| {
39                Region::new_placeholder(
40                    self.interner,
41                    PlaceholderRegion { universe: next_universe, bound: br },
42                )
43            },
44            types: &mut |bound_ty: BoundTy| {
45                Ty::new_placeholder(
46                    self.interner,
47                    PlaceholderTy { universe: next_universe, bound: bound_ty },
48                )
49            },
50            consts: &mut |bound: BoundConst| {
51                Const::new_placeholder(
52                    self.interner,
53                    PlaceholderConst { universe: next_universe, bound },
54                )
55            },
56        };
57
58        debug!(?next_universe);
59        self.interner.replace_bound_vars_uncached(binder, delegate)
60    }
61
62    /// Replaces all bound variables (lifetimes, types, and constants) bound by
63    /// `binder` with placeholder variables in a new universe and then calls the
64    /// closure `f` with the instantiated value. The new placeholders can only be
65    /// named by inference variables created inside of the closure `f` or afterwards.
66    ///
67    /// This is the first step of checking subtyping when higher-ranked things are involved.
68    /// For more details visit the relevant sections of the [rustc dev guide].
69    ///
70    /// This method should be preferred over `fn enter_forall_and_leak_universe`.
71    ///
72    /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
73    #[instrument(level = "debug", skip(self, f))]
74    pub fn enter_forall<T, U>(&self, forall: Binder<'db, T>, f: impl FnOnce(T) -> U) -> U
75    where
76        T: TypeFoldable<DbInterner<'db>> + Clone,
77    {
78        // FIXME: currently we do nothing to prevent placeholders with the new universe being
79        // used after exiting `f`. For example region subtyping can result in outlives constraints
80        // that name placeholders created in this function. Nested goals from type relations can
81        // also contain placeholders created by this function.
82        let value = self.enter_forall_and_leak_universe(forall);
83        debug!(?value);
84        f(value)
85    }
86}