rustc_infer/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_middle::ty::fold::FnMutDelegate;
5use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
6use tracing::{debug, instrument};
7
8use super::RelateResult;
9use crate::infer::InferCtxt;
10use crate::infer::snapshot::CombinedSnapshot;
11
12impl<'tcx> InferCtxt<'tcx> {
13 /// Replaces all bound variables (lifetimes, types, and constants) bound by
14 /// `binder` with placeholder variables in a new universe. This means that the
15 /// new placeholders can only be named by inference variables created after
16 /// this method has been called.
17 ///
18 /// This is the first step of checking subtyping when higher-ranked things are involved.
19 /// For more details visit the relevant sections of the [rustc dev guide].
20 ///
21 /// `fn enter_forall` should be preferred over this method.
22 ///
23 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
24 #[instrument(level = "debug", skip(self), ret)]
25 pub fn enter_forall_and_leak_universe<T>(&self, binder: ty::Binder<'tcx, T>) -> T
26 where
27 T: TypeFoldable<TyCtxt<'tcx>>,
28 {
29 if let Some(inner) = binder.clone().no_bound_vars() {
30 return inner;
31 }
32
33 let next_universe = self.create_next_universe();
34
35 let delegate = FnMutDelegate {
36 regions: &mut |br: ty::BoundRegion| {
37 ty::Region::new_placeholder(
38 self.tcx,
39 ty::PlaceholderRegion { universe: next_universe, bound: br },
40 )
41 },
42 types: &mut |bound_ty: ty::BoundTy| {
43 Ty::new_placeholder(
44 self.tcx,
45 ty::PlaceholderType { universe: next_universe, bound: bound_ty },
46 )
47 },
48 consts: &mut |bound_var: ty::BoundVar| {
49 ty::Const::new_placeholder(
50 self.tcx,
51 ty::PlaceholderConst { universe: next_universe, bound: bound_var },
52 )
53 },
54 };
55
56 debug!(?next_universe);
57 self.tcx.replace_bound_vars_uncached(binder, delegate)
58 }
59
60 /// Replaces all bound variables (lifetimes, types, and constants) bound by
61 /// `binder` with placeholder variables in a new universe and then calls the
62 /// closure `f` with the instantiated value. The new placeholders can only be
63 /// named by inference variables created inside of the closure `f` or afterwards.
64 ///
65 /// This is the first step of checking subtyping when higher-ranked things are involved.
66 /// For more details visit the relevant sections of the [rustc dev guide].
67 ///
68 /// This method should be preferred over `fn enter_forall_and_leak_universe`.
69 ///
70 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
71 #[instrument(level = "debug", skip(self, f))]
72 pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U
73 where
74 T: TypeFoldable<TyCtxt<'tcx>>,
75 {
76 // FIXME: currently we do nothing to prevent placeholders with the new universe being
77 // used after exiting `f`. For example region subtyping can result in outlives constraints
78 // that name placeholders created in this function. Nested goals from type relations can
79 // also contain placeholders created by this function.
80 let value = self.enter_forall_and_leak_universe(forall);
81 debug!(?value);
82 f(value)
83 }
84
85 /// See [RegionConstraintCollector::leak_check][1]. We only check placeholder
86 /// leaking into `outer_universe`, i.e. placeholders which cannot be named by that
87 /// universe.
88 ///
89 /// [1]: crate::infer::region_constraints::RegionConstraintCollector::leak_check
90 pub fn leak_check(
91 &self,
92 outer_universe: ty::UniverseIndex,
93 only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>,
94 ) -> RelateResult<'tcx, ()> {
95 // If the user gave `-Zno-leak-check`, or we have been
96 // configured to skip the leak check, then skip the leak check
97 // completely. The leak check is deprecated. Any legitimate
98 // subtyping errors that it would have caught will now be
99 // caught later on, during region checking. However, we
100 // continue to use it for a transition period.
101 if self.tcx.sess.opts.unstable_opts.no_leak_check || self.skip_leak_check {
102 return Ok(());
103 }
104
105 self.inner.borrow_mut().unwrap_region_constraints().leak_check(
106 self.tcx,
107 outer_universe,
108 self.universe(),
109 only_consider_snapshot,
110 )
111 }
112}