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