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, PlaceholderType, 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<'db>| {
39 Region::new_placeholder(self.interner, PlaceholderRegion::new(next_universe, br))
40 },
41 types: &mut |bound_ty: BoundTy<'db>| {
42 Ty::new_placeholder(self.interner, PlaceholderType::new(next_universe, bound_ty))
43 },
44 consts: &mut |bound: BoundConst<'db>| {
45 Const::new_placeholder(self.interner, PlaceholderConst::new(next_universe, bound))
46 },
47 };
48
49 debug!(?next_universe);
50 self.interner.replace_bound_vars_uncached(binder, delegate)
51 }
52
53 /// Replaces all bound variables (lifetimes, types, and constants) bound by
54 /// `binder` with placeholder variables in a new universe and then calls the
55 /// closure `f` with the instantiated value. The new placeholders can only be
56 /// named by inference variables created inside of the closure `f` or afterwards.
57 ///
58 /// This is the first step of checking subtyping when higher-ranked things are involved.
59 /// For more details visit the relevant sections of the [rustc dev guide].
60 ///
61 /// This method should be preferred over `fn enter_forall_and_leak_universe`.
62 ///
63 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
64 #[instrument(level = "debug", skip(self, f))]
65 pub fn enter_forall<T, U>(&self, forall: Binder<'db, T>, f: impl FnOnce(T) -> U) -> U
66 where
67 T: TypeFoldable<DbInterner<'db>> + Clone,
68 {
69 // FIXME: currently we do nothing to prevent placeholders with the new universe being
70 // used after exiting `f`. For example region subtyping can result in outlives constraints
71 // that name placeholders created in this function. Nested goals from type relations can
72 // also contain placeholders created by this function.
73 let value = self.enter_forall_and_leak_universe(forall);
74 debug!(?value);
75 f(value)
76 }
77}