1 //! Helper routines for higher-ranked things. See the `doc` module at
2 //! the end of the file for details.
4 use super::combine
::CombineFields
;
5 use super::{HigherRankedType, InferCtxt}
;
7 use crate::infer
::CombinedSnapshot
;
8 use rustc_middle
::ty
::relate
::{Relate, RelateResult, TypeRelation}
;
9 use rustc_middle
::ty
::{self, Binder, TypeFoldable}
;
11 impl<'a
, 'tcx
> CombineFields
<'a
, 'tcx
> {
12 #[instrument(skip(self), level = "debug")]
13 pub fn higher_ranked_sub
<T
>(
18 ) -> RelateResult
<'tcx
, Binder
<'tcx
, T
>>
22 // Rather than checking the subtype relationship between `a` and `b`
23 // as-is, we need to do some extra work here in order to make sure
24 // that function subtyping works correctly with respect to regions
26 // Note: this is a subtle algorithm. For a full explanation, please see
27 // the rustc dev guide:
28 // <https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html>
30 let span
= self.trace
.cause
.span
;
32 self.infcx
.commit_if_ok(|_
| {
33 // First, we instantiate each bound region in the supertype with a
34 // fresh placeholder region.
35 let b_prime
= self.infcx
.replace_bound_vars_with_placeholders(b
);
37 // Next, we instantiate each bound region in the subtype
38 // with a fresh region variable. These region variables --
39 // but no other pre-existing region variables -- can name
42 self.infcx
.replace_bound_vars_with_fresh_vars(span
, HigherRankedType
, a
);
44 debug
!("a_prime={:?}", a_prime
);
45 debug
!("b_prime={:?}", b_prime
);
47 // Compare types now that bound regions have been replaced.
48 let result
= self.sub(a_is_expected
).relate(a_prime
, b_prime
)?
;
50 debug
!("higher_ranked_sub: OK result={:?}", result
);
52 // We related `a_prime` and `b_prime`, which just had any bound vars
53 // replaced with placeholders or infer vars, respectively. Relating
54 // them should not introduce new bound vars.
55 Ok(ty
::Binder
::dummy(result
))
60 impl<'a
, 'tcx
> InferCtxt
<'a
, 'tcx
> {
61 /// Replaces all bound variables (lifetimes, types, and constants) bound by
62 /// `binder` with placeholder variables.
64 /// This is the first step of checking subtyping when higher-ranked things are involved.
65 /// For more details visit the relevant sections of the [rustc dev guide].
67 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
68 pub fn replace_bound_vars_with_placeholders
<T
>(&self, binder
: ty
::Binder
<'tcx
, T
>) -> T
70 T
: TypeFoldable
<'tcx
>,
72 // Figure out what the next universe will be, but don't actually create
73 // it until after we've done the substitution (in particular there may
74 // be no bound variables). This is a performance optimization, since the
75 // leak check for example can be skipped if no new universes are created
76 // (i.e., if there are no placeholders).
77 let next_universe
= self.universe().next_universe();
79 let fld_r
= |br
: ty
::BoundRegion
| {
80 self.tcx
.mk_region(ty
::RePlaceholder(ty
::PlaceholderRegion
{
81 universe
: next_universe
,
86 let fld_t
= |bound_ty
: ty
::BoundTy
| {
87 self.tcx
.mk_ty(ty
::Placeholder(ty
::PlaceholderType
{
88 universe
: next_universe
,
93 let fld_c
= |bound_var
: ty
::BoundVar
, ty
| {
94 self.tcx
.mk_const(ty
::ConstS
{
95 val
: ty
::ConstKind
::Placeholder(ty
::PlaceholderConst
{
96 universe
: next_universe
,
97 name
: ty
::BoundConst { var: bound_var, ty }
,
103 let (result
, map
) = self.tcx
.replace_bound_vars(binder
, fld_r
, fld_t
, fld_c
);
105 // If there were higher-ranked regions to replace, then actually create
106 // the next universe (this avoids needlessly creating universes).
108 let n_u
= self.create_next_universe();
109 assert_eq
!(n_u
, next_universe
);
113 "replace_bound_vars_with_placeholders(\
114 next_universe={:?}, \
117 next_universe
, result
, map
,
123 /// See [RegionConstraintCollector::leak_check][1].
125 /// [1]: crate::infer::region_constraints::RegionConstraintCollector::leak_check
128 overly_polymorphic
: bool
,
129 snapshot
: &CombinedSnapshot
<'_
, 'tcx
>,
130 ) -> RelateResult
<'tcx
, ()> {
131 // If the user gave `-Zno-leak-check`, or we have been
132 // configured to skip the leak check, then skip the leak check
133 // completely. The leak check is deprecated. Any legitimate
134 // subtyping errors that it would have caught will now be
135 // caught later on, during region checking. However, we
136 // continue to use it for a transition period.
137 if self.tcx
.sess
.opts
.debugging_opts
.no_leak_check
|| self.skip_leak_check
.get() {
141 self.inner
.borrow_mut().unwrap_region_constraints().leak_check(