]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/higher_ranked/mod.rs
Add variance-related information to lifetime error messages
[rust.git] / compiler / rustc_infer / src / infer / higher_ranked / mod.rs
1 //! Helper routines for higher-ranked things. See the `doc` module at
2 //! the end of the file for details.
3
4 use super::combine::CombineFields;
5 use super::{HigherRankedType, InferCtxt};
6
7 use crate::infer::CombinedSnapshot;
8 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
9 use rustc_middle::ty::{self, Binder, TypeFoldable};
10
11 impl<'a, 'tcx> CombineFields<'a, 'tcx> {
12     pub fn higher_ranked_sub<T>(
13         &mut self,
14         a: Binder<'tcx, T>,
15         b: Binder<'tcx, T>,
16         a_is_expected: bool,
17     ) -> RelateResult<'tcx, Binder<'tcx, T>>
18     where
19         T: Relate<'tcx>,
20     {
21         debug!("higher_ranked_sub(a={:?}, b={:?})", a, b);
22
23         // Rather than checking the subtype relationship between `a` and `b`
24         // as-is, we need to do some extra work here in order to make sure
25         // that function subtyping works correctly with respect to regions
26         //
27         // Note: this is a subtle algorithm.  For a full explanation, please see
28         // the rustc dev guide:
29         // <https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html>
30
31         let span = self.trace.cause.span;
32
33         self.infcx.commit_if_ok(|_| {
34             // First, we instantiate each bound region in the supertype with a
35             // fresh placeholder region.
36             let b_prime = self.infcx.replace_bound_vars_with_placeholders(b);
37
38             // Next, we instantiate each bound region in the subtype
39             // with a fresh region variable. These region variables --
40             // but no other pre-existing region variables -- can name
41             // the placeholders.
42             let (a_prime, _) =
43                 self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
44
45             debug!("a_prime={:?}", a_prime);
46             debug!("b_prime={:?}", b_prime);
47
48             // Compare types now that bound regions have been replaced.
49             let result = self.sub(a_is_expected).relate(a_prime, b_prime)?;
50
51             debug!("higher_ranked_sub: OK result={:?}", result);
52
53             // We related `a_prime` and `b_prime`, which just had any bound vars
54             // replaced with placeholders or infer vars, respectively. Relating
55             // them should not introduce new bound vars.
56             Ok(ty::Binder::dummy(result))
57         })
58     }
59 }
60
61 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
62     /// Replaces all regions (resp. types) bound by `binder` with placeholder
63     /// regions (resp. types) and return a map indicating which bound-region
64     /// placeholder region. This is the first step of checking subtyping
65     /// when higher-ranked things are involved.
66     ///
67     /// **Important:** You have to be careful to not leak these placeholders,
68     /// for more information about how placeholders and HRTBs work, see
69     /// the [rustc dev guide].
70     ///
71     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
72     pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
73     where
74         T: TypeFoldable<'tcx>,
75     {
76         // Figure out what the next universe will be, but don't actually create
77         // it until after we've done the substitution (in particular there may
78         // be no bound variables). This is a performance optimization, since the
79         // leak check for example can be skipped if no new universes are created
80         // (i.e., if there are no placeholders).
81         let next_universe = self.universe().next_universe();
82
83         let fld_r = |br: ty::BoundRegion| {
84             self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
85                 universe: next_universe,
86                 name: br.kind,
87             }))
88         };
89
90         let fld_t = |bound_ty: ty::BoundTy| {
91             self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
92                 universe: next_universe,
93                 name: bound_ty.var,
94             }))
95         };
96
97         let fld_c = |bound_var: ty::BoundVar, ty| {
98             self.tcx.mk_const(ty::Const {
99                 val: ty::ConstKind::Placeholder(ty::PlaceholderConst {
100                     universe: next_universe,
101                     name: ty::BoundConst { var: bound_var, ty },
102                 }),
103                 ty,
104             })
105         };
106
107         let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c);
108
109         // If there were higher-ranked regions to replace, then actually create
110         // the next universe (this avoids needlessly creating universes).
111         if !map.is_empty() {
112             let n_u = self.create_next_universe();
113             assert_eq!(n_u, next_universe);
114         }
115
116         debug!(
117             "replace_bound_vars_with_placeholders(\
118              next_universe={:?}, \
119              result={:?}, \
120              map={:?})",
121             next_universe, result, map,
122         );
123
124         result
125     }
126
127     /// See `infer::region_constraints::RegionConstraintCollector::leak_check`.
128     pub fn leak_check(
129         &self,
130         overly_polymorphic: bool,
131         snapshot: &CombinedSnapshot<'_, 'tcx>,
132     ) -> RelateResult<'tcx, ()> {
133         // If the user gave `-Zno-leak-check`, or we have been
134         // configured to skip the leak check, then skip the leak check
135         // completely. The leak check is deprecated. Any legitimate
136         // subtyping errors that it would have caught will now be
137         // caught later on, during region checking. However, we
138         // continue to use it for a transition period.
139         if self.tcx.sess.opts.debugging_opts.no_leak_check || self.skip_leak_check.get() {
140             return Ok(());
141         }
142
143         self.inner.borrow_mut().unwrap_region_constraints().leak_check(
144             self.tcx,
145             overly_polymorphic,
146             self.universe(),
147             snapshot,
148         )
149     }
150 }