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, PlaceholderMap}
;
7 use crate::infer
::CombinedSnapshot
;
8 use crate::ty
::relate
::{Relate, RelateResult, TypeRelation}
;
9 use crate::ty
::{self, Binder, TypeFoldable}
;
11 impl<'a
, 'gcx
, 'tcx
> CombineFields
<'a
, 'gcx
, 'tcx
> {
12 pub fn higher_ranked_sub
<T
>(
17 ) -> RelateResult
<'tcx
, Binder
<T
>>
21 debug
!("higher_ranked_sub(a={:?}, b={:?})", a
, b
);
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
27 // Note: this is a subtle algorithm. For a full explanation,
28 // please see the large comment at the end of the file in the (inlined) module
31 let span
= self.trace
.cause
.span
;
33 return self.infcx
.commit_if_ok(|snapshot
| {
34 // First, we instantiate each bound region in the supertype with a
35 // fresh placeholder region.
36 let (b_prime
, placeholder_map
) = self.infcx
.replace_bound_vars_with_placeholders(b
);
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
44 .replace_bound_vars_with_fresh_vars(span
, HigherRankedType
, a
);
46 debug
!("a_prime={:?}", a_prime
);
47 debug
!("b_prime={:?}", b_prime
);
49 // Compare types now that bound regions have been replaced.
50 let result
= self.sub(a_is_expected
).relate(&a_prime
, &b_prime
)?
;
53 .leak_check(!a_is_expected
, &placeholder_map
, snapshot
)?
;
55 debug
!("higher_ranked_sub: OK result={:?}", result
);
57 Ok(ty
::Binder
::bind(result
))
62 impl<'a
, 'gcx
, 'tcx
> InferCtxt
<'a
, 'gcx
, 'tcx
> {
63 /// Replaces all regions (resp. types) bound by `binder` with placeholder
64 /// regions (resp. types) and return a map indicating which bound-region
65 /// placeholder region. This is the first step of checking subtyping
66 /// when higher-ranked things are involved.
68 /// **Important:** you must call this function from within a snapshot.
69 /// Moreover, before committing the snapshot, you must eventually call
70 /// either `plug_leaks` or `pop_placeholders` to remove the placeholder
71 /// regions. If you rollback the snapshot (or are using a probe), then
72 /// the pop occurs as part of the rollback, so an explicit call is not
73 /// needed (but is also permitted).
75 /// For more information about how placeholders and HRTBs work, see
76 /// the [rustc guide].
78 /// [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html
79 pub fn replace_bound_vars_with_placeholders
<T
>(
81 binder
: &ty
::Binder
<T
>,
82 ) -> (T
, PlaceholderMap
<'tcx
>)
84 T
: TypeFoldable
<'tcx
>,
86 let next_universe
= self.create_next_universe();
89 self.tcx
.mk_region(ty
::RePlaceholder(ty
::PlaceholderRegion
{
90 universe
: next_universe
,
95 let fld_t
= |bound_ty
: ty
::BoundTy
| {
96 self.tcx
.mk_ty(ty
::Placeholder(ty
::PlaceholderType
{
97 universe
: next_universe
,
102 let (result
, map
) = self.tcx
.replace_bound_vars(binder
, fld_r
, fld_t
);
105 "replace_bound_vars_with_placeholders(\
106 next_universe={:?}, \
110 next_universe
, binder
, result
, map
,
116 /// See `infer::region_constraints::RegionConstraintCollector::leak_check`.
119 overly_polymorphic
: bool
,
120 placeholder_map
: &PlaceholderMap
<'tcx
>,
121 snapshot
: &CombinedSnapshot
<'_
, 'tcx
>,
122 ) -> RelateResult
<'tcx
, ()> {
123 self.borrow_region_constraints()
124 .leak_check(self.tcx
, overly_polymorphic
, placeholder_map
, snapshot
)