@@ -15,6 +15,7 @@ use super::{CombinedSnapshot,
15
15
InferCtxt ,
16
16
LateBoundRegion ,
17
17
HigherRankedType ,
18
+ SubregionOrigin ,
18
19
SkolemizationMap } ;
19
20
use super :: combine:: CombineFields ;
20
21
use super :: region_inference:: { TaintDirections } ;
@@ -25,6 +26,19 @@ use ty::relate::{Relate, RelateResult, TypeRelation};
25
26
use syntax:: codemap:: Span ;
26
27
use util:: nodemap:: { FnvHashMap , FnvHashSet } ;
27
28
29
+ pub struct HrMatchResult < U > {
30
+ pub value : U ,
31
+
32
+ /// Normally, when we do a higher-ranked match operation, we
33
+ /// expect all higher-ranked regions to be constrained as part of
34
+ /// the match operation. However, in the transition period for
35
+ /// #32330, it can happen that we sometimes have unconstrained
36
+ /// regions that get instantiated with fresh variables. In that
37
+ /// case, we collect the set of unconstrained bound regions here
38
+ /// and replace them with fresh variables.
39
+ pub unconstrained_regions : Vec < ty:: BoundRegion > ,
40
+ }
41
+
28
42
impl < ' a , ' gcx , ' tcx > CombineFields < ' a , ' gcx , ' tcx > {
29
43
pub fn higher_ranked_sub < T > ( & self , a : & Binder < T > , b : & Binder < T > )
30
44
-> RelateResult < ' tcx , Binder < T > >
@@ -79,6 +93,134 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
79
93
} ) ;
80
94
}
81
95
96
+ /// The value consists of a pair `(t, u)` where `t` is the
97
+ /// *matcher* and `u` is a *value*. The idea is to find a
98
+ /// substitution `S` such that `S(t) == b`, and then return
99
+ /// `S(u)`. In other words, find values for the late-bound regions
100
+ /// in `a` that can make `t == b` and then replace the LBR in `u`
101
+ /// with those values.
102
+ ///
103
+ /// This routine is (as of this writing) used in trait matching,
104
+ /// particularly projection.
105
+ ///
106
+ /// NB. It should not happen that there are LBR appearing in `U`
107
+ /// that do not appear in `T`. If that happens, those regions are
108
+ /// unconstrained, and this routine replaces them with `'static`.
109
+ pub fn higher_ranked_match < T , U > ( & self ,
110
+ span : Span ,
111
+ a_pair : & Binder < ( T , U ) > ,
112
+ b_match : & T )
113
+ -> RelateResult < ' tcx , HrMatchResult < U > >
114
+ where T : Relate < ' tcx > ,
115
+ U : TypeFoldable < ' tcx >
116
+ {
117
+ debug ! ( "higher_ranked_match(a={:?}, b={:?})" ,
118
+ a_pair, b_match) ;
119
+
120
+ // Start a snapshot so we can examine "all bindings that were
121
+ // created as part of this type comparison".
122
+ return self . infcx . commit_if_ok ( |snapshot| {
123
+ // First, we instantiate each bound region in the matcher
124
+ // with a skolemized region.
125
+ let ( ( a_match, a_value) , skol_map) =
126
+ self . infcx . skolemize_late_bound_regions ( a_pair, snapshot) ;
127
+
128
+ debug ! ( "higher_ranked_match: a_match={:?}" , a_match) ;
129
+ debug ! ( "higher_ranked_match: skol_map={:?}" , skol_map) ;
130
+
131
+ // Equate types now that bound regions have been replaced.
132
+ try!( self . equate ( ) . relate ( & a_match, & b_match) ) ;
133
+
134
+ // Map each skolemized region to a vector of other regions that it
135
+ // must be equated with. (Note that this vector may include other
136
+ // skolemized regions from `skol_map`.)
137
+ let skol_resolution_map: FnvHashMap < _ , _ > =
138
+ skol_map
139
+ . iter ( )
140
+ . map ( |( & br, & skol) | {
141
+ let tainted_regions =
142
+ self . infcx . tainted_regions ( snapshot,
143
+ skol,
144
+ TaintDirections :: incoming ( ) ) ; // [1]
145
+
146
+ // [1] this routine executes after the skolemized
147
+ // regions have been *equated* with something
148
+ // else, so examining the incoming edges ought to
149
+ // be enough to collect all constraints
150
+
151
+ ( skol, ( br, tainted_regions) )
152
+ } )
153
+ . collect ( ) ;
154
+
155
+ // For each skolemized region, pick a representative -- which can
156
+ // be any region from the sets above, except for other members of
157
+ // `skol_map`. There should always be a representative if things
158
+ // are properly well-formed.
159
+ let mut unconstrained_regions = vec ! [ ] ;
160
+ let skol_representatives: FnvHashMap < _ , _ > =
161
+ skol_resolution_map
162
+ . iter ( )
163
+ . map ( |( & skol, & ( br, ref regions) ) | {
164
+ let representative =
165
+ regions. iter ( )
166
+ . filter ( |r| !skol_resolution_map. contains_key ( r) )
167
+ . cloned ( )
168
+ . next ( )
169
+ . unwrap_or_else ( || { // [1]
170
+ unconstrained_regions. push ( br) ;
171
+ self . infcx . next_region_var (
172
+ LateBoundRegion ( span, br, HigherRankedType ) )
173
+ } ) ;
174
+
175
+ // [1] There should always be a representative,
176
+ // unless the higher-ranked region did not appear
177
+ // in the values being matched. We should reject
178
+ // as ill-formed cases that can lead to this, but
179
+ // right now we sometimes issue warnings (see
180
+ // #32330).
181
+
182
+ ( skol, representative)
183
+ } )
184
+ . collect ( ) ;
185
+
186
+ // Equate all the members of each skolemization set with the
187
+ // representative.
188
+ for ( skol, & ( _br, ref regions) ) in & skol_resolution_map {
189
+ let representative = & skol_representatives[ skol] ;
190
+ debug ! ( "higher_ranked_match: \
191
+ skol={:?} representative={:?} regions={:?}",
192
+ skol, representative, regions) ;
193
+ for region in regions. iter ( )
194
+ . filter ( |& r| !skol_resolution_map. contains_key ( r) )
195
+ . filter ( |& r| r != representative)
196
+ {
197
+ let origin = SubregionOrigin :: Subtype ( self . trace . clone ( ) ) ;
198
+ self . infcx . region_vars . make_eqregion ( origin,
199
+ * representative,
200
+ * region) ;
201
+ }
202
+ }
203
+
204
+ // Replace the skolemized regions appearing in value with
205
+ // their representatives
206
+ let a_value =
207
+ fold_regions_in (
208
+ self . tcx ( ) ,
209
+ & a_value,
210
+ |r, _| skol_representatives. get ( & r) . cloned ( ) . unwrap_or ( r) ) ;
211
+
212
+ debug ! ( "higher_ranked_match: value={:?}" , a_value) ;
213
+
214
+ // We are now done with these skolemized variables.
215
+ self . infcx . pop_skolemized ( skol_map, snapshot) ;
216
+
217
+ Ok ( HrMatchResult {
218
+ value : a_value,
219
+ unconstrained_regions : unconstrained_regions,
220
+ } )
221
+ } ) ;
222
+ }
223
+
82
224
pub fn higher_ranked_lub < T > ( & self , a : & Binder < T > , b : & Binder < T > )
83
225
-> RelateResult < ' tcx , Binder < T > >
84
226
where T : Relate < ' tcx >
0 commit comments