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