33
44use super :: combine:: CombineFields ;
55use super :: { HigherRankedType , InferCtxt } ;
6-
76use crate :: infer:: CombinedSnapshot ;
87use rustc_middle:: ty:: relate:: { Relate , RelateResult , TypeRelation } ;
98use rustc_middle:: ty:: { self , Binder , TypeFoldable } ;
109
1110impl < ' 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
1226 #[ instrument( skip( self ) , level = "debug" ) ]
1327 pub fn higher_ranked_sub < T > (
1428 & 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 , ( ) >
1933 where
2034 T : Relate < ' tcx > ,
2135 {
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-
3036 let span = self . trace . cause . span ;
3137
3238 self . infcx . commit_if_ok ( |_| {
3339 // 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) ;
3643
3744 // Next, we instantiate each bound region in the subtype
3845 // with a fresh region variable. These region variables --
3946 // but no other pre-existing region variables -- can name
4047 // 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 ) ;
4350
44- debug ! ( "a_prime={:?}" , a_prime ) ;
45- debug ! ( "b_prime={:?}" , b_prime ) ;
51+ debug ! ( "a_prime={:?}" , sub_prime ) ;
52+ debug ! ( "b_prime={:?}" , sup_prime ) ;
4653
4754 // 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) ?;
5156
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 ( ( ) )
5661 } )
5762 }
5863}
5964
6065impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
6166 /// 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.
6370 ///
6471 /// This is the first step of checking subtyping when higher-ranked things are involved.
6572 /// For more details visit the relevant sections of the [rustc dev guide].
6673 ///
6774 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
75+ #[ instrument( level = "debug" , skip( self ) ) ]
6876 pub fn replace_bound_vars_with_placeholders < T > ( & self , binder : ty:: Binder < ' tcx , T > ) -> T
6977 where
70- T : TypeFoldable < ' tcx > ,
78+ T : TypeFoldable < ' tcx > + Copy ,
7179 {
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 ( ) ;
7885
7986 let fld_r = |br : ty:: BoundRegion | {
8087 self . tcx . mk_region ( ty:: RePlaceholder ( ty:: PlaceholderRegion {
@@ -100,23 +107,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
100107 } )
101108 } ;
102109
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) ;
120112 result
121113 }
122114
0 commit comments