3
3
4
4
use super :: combine:: CombineFields ;
5
5
use super :: { HigherRankedType , InferCtxt } ;
6
-
7
6
use crate :: infer:: CombinedSnapshot ;
8
7
use rustc_middle:: ty:: relate:: { Relate , RelateResult , TypeRelation } ;
9
8
use rustc_middle:: ty:: { self , Binder , TypeFoldable } ;
10
9
11
10
impl < ' a , ' tcx > CombineFields < ' a , ' tcx > {
11
+ /// Checks whether `for<..> sub <: for<..> sup` holds.
12
+ ///
13
+ /// For this to hold, **all** instantiations of the super type
14
+ /// have to be a super type of **at least one** instantiation of
15
+ /// the subtype.
16
+ ///
17
+ /// This is implemented by first entering a new universe.
18
+ /// We then replace all bound variables in `sup` with placeholders,
19
+ /// and all bound variables in `sup` with inference vars.
20
+ /// We can then just relate the two resulting types as normal.
21
+ ///
22
+ /// Note: this is a subtle algorithm. For a full explanation, please see
23
+ /// the [rustc dev guide][rd]
24
+ ///
25
+ /// [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html
12
26
#[ instrument( skip( self ) , level = "debug" ) ]
13
27
pub fn higher_ranked_sub < T > (
14
28
& mut self ,
15
- a : Binder < ' tcx , T > ,
16
- b : Binder < ' tcx , T > ,
17
- a_is_expected : bool ,
18
- ) -> RelateResult < ' tcx , Binder < ' tcx , T > >
29
+ sub : Binder < ' tcx , T > ,
30
+ sup : Binder < ' tcx , T > ,
31
+ sub_is_expected : bool ,
32
+ ) -> RelateResult < ' tcx , ( ) >
19
33
where
20
34
T : Relate < ' tcx > ,
21
35
{
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
25
- //
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>
29
-
30
36
let span = self . trace . cause . span ;
31
37
32
38
self . infcx . commit_if_ok ( |_| {
33
39
// 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) ;
40
+ // fresh placeholder region. Note that this automatically creates
41
+ // a new universe if needed.
42
+ let sup_prime = self . infcx . replace_bound_vars_with_placeholders ( sup) ;
36
43
37
44
// Next, we instantiate each bound region in the subtype
38
45
// with a fresh region variable. These region variables --
39
46
// but no other pre-existing region variables -- can name
40
47
// the placeholders.
41
- let ( a_prime , _ ) =
42
- self . infcx . replace_bound_vars_with_fresh_vars ( span, HigherRankedType , a ) ;
48
+ let sub_prime =
49
+ self . infcx . replace_bound_vars_with_fresh_vars ( span, HigherRankedType , sub ) ;
43
50
44
- debug ! ( "a_prime={:?}" , a_prime ) ;
45
- debug ! ( "b_prime={:?}" , b_prime ) ;
51
+ debug ! ( "a_prime={:?}" , sub_prime ) ;
52
+ debug ! ( "b_prime={:?}" , sup_prime ) ;
46
53
47
54
// Compare types now that bound regions have been replaced.
48
- let result = self . sub ( a_is_expected) . relate ( a_prime, b_prime) ?;
49
-
50
- debug ! ( "higher_ranked_sub: OK result={:?}" , result) ;
55
+ let result = self . sub ( sub_is_expected) . relate ( sub_prime, sup_prime) ?;
51
56
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 ) )
57
+ debug ! ( "higher_ranked_sub: OK result={result:?}" ) ;
58
+ // NOTE: returning the result here would be dangerous as it contains
59
+ // placeholders which **must not** be named afterwards .
60
+ Ok ( ( ) )
56
61
} )
57
62
}
58
63
}
59
64
60
65
impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
61
66
/// Replaces all bound variables (lifetimes, types, and constants) bound by
62
- /// `binder` with placeholder variables.
67
+ /// `binder` with placeholder variables in a new universe. This means that the
68
+ /// new placeholders can only be named by inference variables created after
69
+ /// this method has been called.
63
70
///
64
71
/// This is the first step of checking subtyping when higher-ranked things are involved.
65
72
/// For more details visit the relevant sections of the [rustc dev guide].
66
73
///
67
74
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
75
+ #[ instrument( level = "debug" , skip( self ) ) ]
68
76
pub fn replace_bound_vars_with_placeholders < T > ( & self , binder : ty:: Binder < ' tcx , T > ) -> T
69
77
where
70
- T : TypeFoldable < ' tcx > ,
78
+ T : TypeFoldable < ' tcx > + Copy ,
71
79
{
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 ( ) ;
80
+ if let Some ( inner) = binder. no_bound_vars ( ) {
81
+ return inner;
82
+ }
83
+
84
+ let next_universe = self . create_next_universe ( ) ;
78
85
79
86
let fld_r = |br : ty:: BoundRegion | {
80
87
self . tcx . mk_region ( ty:: RePlaceholder ( ty:: PlaceholderRegion {
@@ -100,23 +107,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
100
107
} )
101
108
} ;
102
109
103
- let ( result, map) = self . tcx . replace_bound_vars ( binder, fld_r, fld_t, fld_c) ;
104
-
105
- // If there were higher-ranked regions to replace, then actually create
106
- // the next universe (this avoids needlessly creating universes).
107
- if !map. is_empty ( ) {
108
- let n_u = self . create_next_universe ( ) ;
109
- assert_eq ! ( n_u, next_universe) ;
110
- }
111
-
112
- debug ! (
113
- "replace_bound_vars_with_placeholders(\
114
- next_universe={:?}, \
115
- result={:?}, \
116
- map={:?})",
117
- next_universe, result, map,
118
- ) ;
119
-
110
+ let result = self . tcx . replace_bound_vars_uncached ( binder, fld_r, fld_t, fld_c) ;
111
+ debug ! ( ?next_universe, ?result) ;
120
112
result
121
113
}
122
114
0 commit comments