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}