Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs')
-rw-r--r--crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs89
1 files changed, 89 insertions, 0 deletions
diff --git a/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs b/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs
new file mode 100644
index 0000000000..62028e0e70
--- /dev/null
+++ b/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs
@@ -0,0 +1,89 @@
+//! Helper routines for higher-ranked things. See the `doc` module at
+//! the end of the file for details.
+
+use rustc_type_ir::TypeFoldable;
+use rustc_type_ir::{BoundVar, UniverseIndex};
+use tracing::{debug, instrument};
+
+use super::RelateResult;
+use crate::next_solver::fold::FnMutDelegate;
+use crate::next_solver::infer::InferCtxt;
+use crate::next_solver::infer::snapshot::CombinedSnapshot;
+use crate::next_solver::{
+ Binder, BoundConst, BoundRegion, BoundTy, Const, DbInterner, PlaceholderConst,
+ PlaceholderRegion, PlaceholderTy, Region, Ty,
+};
+
+impl<'db> InferCtxt<'db> {
+ /// Replaces all bound variables (lifetimes, types, and constants) bound by
+ /// `binder` with placeholder variables in a new universe. This means that the
+ /// new placeholders can only be named by inference variables created after
+ /// this method has been called.
+ ///
+ /// This is the first step of checking subtyping when higher-ranked things are involved.
+ /// For more details visit the relevant sections of the [rustc dev guide].
+ ///
+ /// `fn enter_forall` should be preferred over this method.
+ ///
+ /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
+ #[instrument(level = "debug", skip(self), ret)]
+ pub fn enter_forall_and_leak_universe<T>(&self, binder: Binder<'db, T>) -> T
+ where
+ T: TypeFoldable<DbInterner<'db>> + Clone,
+ {
+ if let Some(inner) = binder.clone().no_bound_vars() {
+ return inner;
+ }
+
+ let next_universe = self.create_next_universe();
+
+ let delegate = FnMutDelegate {
+ regions: &mut |br: BoundRegion| {
+ Region::new_placeholder(
+ self.interner,
+ PlaceholderRegion { universe: next_universe, bound: br },
+ )
+ },
+ types: &mut |bound_ty: BoundTy| {
+ Ty::new_placeholder(
+ self.interner,
+ PlaceholderTy { universe: next_universe, bound: bound_ty },
+ )
+ },
+ consts: &mut |bound: BoundConst| {
+ Const::new_placeholder(
+ self.interner,
+ PlaceholderConst { universe: next_universe, bound },
+ )
+ },
+ };
+
+ debug!(?next_universe);
+ self.interner.replace_bound_vars_uncached(binder, delegate)
+ }
+
+ /// Replaces all bound variables (lifetimes, types, and constants) bound by
+ /// `binder` with placeholder variables in a new universe and then calls the
+ /// closure `f` with the instantiated value. The new placeholders can only be
+ /// named by inference variables created inside of the closure `f` or afterwards.
+ ///
+ /// This is the first step of checking subtyping when higher-ranked things are involved.
+ /// For more details visit the relevant sections of the [rustc dev guide].
+ ///
+ /// This method should be preferred over `fn enter_forall_and_leak_universe`.
+ ///
+ /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
+ #[instrument(level = "debug", skip(self, f))]
+ pub fn enter_forall<T, U>(&self, forall: Binder<'db, T>, f: impl FnOnce(T) -> U) -> U
+ where
+ T: TypeFoldable<DbInterner<'db>> + Clone,
+ {
+ // FIXME: currently we do nothing to prevent placeholders with the new universe being
+ // used after exiting `f`. For example region subtyping can result in outlives constraints
+ // that name placeholders created in this function. Nested goals from type relations can
+ // also contain placeholders created by this function.
+ let value = self.enter_forall_and_leak_universe(forall);
+ debug!(?value);
+ f(value)
+ }
+}