11
11
//! Helper routines for higher-ranked things. See the `doc` module at
12
12
//! the end of the file for details.
13
13
14
- use super :: { CombinedSnapshot ,
15
- InferCtxt ,
16
- HigherRankedType ,
17
- SkolemizationMap } ;
14
+ use super :: { InferCtxt ,
15
+ HigherRankedType } ;
18
16
use super :: combine:: CombineFields ;
19
- use super :: region_constraints:: { TaintDirections } ;
20
17
21
18
use ty:: { self , Binder , TypeFoldable } ;
22
- use ty:: error:: TypeError ;
23
19
use ty:: relate:: { Relate , RelateResult , TypeRelation } ;
24
- use syntax_pos:: Span ;
25
- use util:: nodemap:: { FxHashMap , FxHashSet } ;
26
20
27
21
impl < ' a , ' gcx , ' tcx > CombineFields < ' a , ' gcx , ' tcx > {
28
22
pub fn higher_ranked_sub < T > ( & mut self ,
@@ -46,36 +40,28 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
46
40
47
41
// Start a snapshot so we can examine "all bindings that were
48
42
// created as part of this type comparison".
49
- return self . infcx . commit_if_ok ( |snapshot | {
43
+ return self . infcx . commit_if_ok ( |_snapshot | {
50
44
let span = self . trace . cause . span ;
51
45
52
- // First, we instantiate each bound region in the subtype with a fresh
46
+ // First, we instantiate each bound region in the supertype with a
47
+ // fresh concrete region.
48
+ let b_prime =
49
+ self . infcx . skolemize_late_bound_regions ( b) ;
50
+
51
+ // Second, we instantiate each bound region in the subtype with a fresh
53
52
// region variable.
54
53
let ( a_prime, _) =
55
54
self . infcx . replace_late_bound_regions_with_fresh_var (
56
55
span,
57
56
HigherRankedType ,
58
57
a) ;
59
58
60
- // Second, we instantiate each bound region in the supertype with a
61
- // fresh concrete region.
62
- let ( b_prime, skol_map) =
63
- self . infcx . skolemize_late_bound_regions ( b) ;
64
-
65
59
debug ! ( "a_prime={:?}" , a_prime) ;
66
60
debug ! ( "b_prime={:?}" , b_prime) ;
67
61
68
62
// Compare types now that bound regions have been replaced.
69
63
let result = self . sub ( param_env, a_is_expected) . relate ( & a_prime, & b_prime) ?;
70
64
71
- // Presuming type comparison succeeds, we need to check
72
- // that the skolemized regions do not "leak".
73
- self . infcx . leak_check ( !a_is_expected, span, & skol_map, snapshot) ?;
74
-
75
- // We are finished with the skolemized regions now so pop
76
- // them off.
77
- self . infcx . pop_skolemized ( skol_map, snapshot) ;
78
-
79
65
debug ! ( "higher_ranked_sub: OK result={:?}" , result) ;
80
66
81
67
Ok ( ty:: Binder ( result) )
@@ -84,306 +70,26 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
84
70
}
85
71
86
72
impl < ' a , ' gcx , ' tcx > InferCtxt < ' a , ' gcx , ' tcx > {
87
- fn tainted_regions ( & self ,
88
- snapshot : & CombinedSnapshot < ' a , ' tcx > ,
89
- r : ty:: Region < ' tcx > ,
90
- directions : TaintDirections )
91
- -> FxHashSet < ty:: Region < ' tcx > > {
92
- self . borrow_region_constraints ( ) . tainted (
93
- self . tcx ,
94
- & snapshot. region_constraints_snapshot ,
95
- r,
96
- directions)
97
- }
98
-
99
- fn region_vars_confined_to_snapshot ( & self ,
100
- snapshot : & CombinedSnapshot < ' a , ' tcx > )
101
- -> Vec < ty:: RegionVid >
102
- {
103
- /*!
104
- * Returns the set of region variables that do not affect any
105
- * types/regions which existed before `snapshot` was
106
- * started. This is used in the sub/lub/glb computations. The
107
- * idea here is that when we are computing lub/glb of two
108
- * regions, we sometimes create intermediate region variables.
109
- * Those region variables may touch some of the skolemized or
110
- * other "forbidden" regions we created to replace bound
111
- * regions, but they don't really represent an "external"
112
- * constraint.
113
- *
114
- * However, sometimes fresh variables are created for other
115
- * purposes too, and those *may* represent an external
116
- * constraint. In particular, when a type variable is
117
- * instantiated, we create region variables for all the
118
- * regions that appear within, and if that type variable
119
- * pre-existed the snapshot, then those region variables
120
- * represent external constraints.
121
- *
122
- * An example appears in the unit test
123
- * `sub_free_bound_false_infer`. In this test, we want to
124
- * know whether
125
- *
126
- * ```rust
127
- * fn(_#0t) <: for<'a> fn(&'a int)
128
- * ```
129
- *
130
- * Note that the subtype has a type variable. Because the type
131
- * variable can't be instantiated with a region that is bound
132
- * in the fn signature, this comparison ought to fail. But if
133
- * we're not careful, it will succeed.
134
- *
135
- * The reason is that when we walk through the subtyping
136
- * algorith, we begin by replacing `'a` with a skolemized
137
- * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
138
- * can be made true by unifying `_#0t` with `&'1 int`. In the
139
- * process, we create a fresh variable for the skolemized
140
- * region, `'$2`, and hence we have that `_#0t == &'$2
141
- * int`. However, because `'$2` was created during the sub
142
- * computation, if we're not careful we will erroneously
143
- * assume it is one of the transient region variables
144
- * representing a lub/glb internally. Not good.
145
- *
146
- * To prevent this, we check for type variables which were
147
- * unified during the snapshot, and say that any region
148
- * variable created during the snapshot but which finds its
149
- * way into a type variable is considered to "escape" the
150
- * snapshot.
151
- */
152
-
153
- let mut region_vars =
154
- self . borrow_region_constraints ( ) . vars_created_since_snapshot (
155
- & snapshot. region_constraints_snapshot ) ;
156
-
157
- let escaping_types =
158
- self . type_variables . borrow_mut ( ) . types_escaping_snapshot ( & snapshot. type_snapshot ) ;
159
-
160
- let mut escaping_region_vars = FxHashSet ( ) ;
161
- for ty in & escaping_types {
162
- self . tcx . collect_regions ( ty, & mut escaping_region_vars) ;
163
- }
164
-
165
- region_vars. retain ( |& region_vid| {
166
- let r = ty:: ReVar ( region_vid) ;
167
- !escaping_region_vars. contains ( & r)
168
- } ) ;
169
-
170
- debug ! ( "region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}" ,
171
- region_vars,
172
- escaping_types) ;
173
-
174
- region_vars
175
- }
176
-
177
73
/// Replace all regions bound by `binder` with skolemized regions and
178
74
/// return a map indicating which bound-region was replaced with what
179
75
/// skolemized region. This is the first step of checking subtyping
180
76
/// when higher-ranked things are involved.
181
77
///
182
- /// **Important:** you must call this function from within a snapshot.
183
- /// Moreover, before committing the snapshot, you must eventually call
184
- /// either `plug_leaks` or `pop_skolemized` to remove the skolemized
185
- /// regions. If you rollback the snapshot (or are using a probe), then
186
- /// the pop occurs as part of the rollback, so an explicit call is not
187
- /// needed (but is also permitted).
188
- ///
189
78
/// See `README.md` for more details.
190
79
pub fn skolemize_late_bound_regions < T > ( & self ,
191
80
binder : & ty:: Binder < T > )
192
- -> ( T , SkolemizationMap < ' tcx > )
81
+ -> T
193
82
where T : TypeFoldable < ' tcx >
194
83
{
195
- let ( result, map ) = self . tcx . replace_late_bound_regions ( binder, |br| {
84
+ let ( result, _ ) = self . tcx . replace_late_bound_regions ( binder, |br| {
196
85
self . universe . set ( self . universe ( ) . subuniverse ( ) ) ;
197
86
self . tcx . mk_region ( ty:: ReSkolemized ( self . universe ( ) , br) )
198
87
} ) ;
199
88
200
- debug ! ( "skolemize_bound_regions(binder={:?}, result={:?}, map={:?} )" ,
89
+ debug ! ( "skolemize_bound_regions(binder={:?}, result={:?})" ,
201
90
binder,
202
- result,
203
- map) ;
204
-
205
- ( result, map)
206
- }
207
-
208
- /// Searches the region constraints created since `snapshot` was started
209
- /// and checks to determine whether any of the skolemized regions created
210
- /// in `skol_map` would "escape" -- meaning that they are related to
211
- /// other regions in some way. If so, the higher-ranked subtyping doesn't
212
- /// hold. See `README.md` for more details.
213
- pub fn leak_check ( & self ,
214
- overly_polymorphic : bool ,
215
- _span : Span ,
216
- skol_map : & SkolemizationMap < ' tcx > ,
217
- snapshot : & CombinedSnapshot < ' a , ' tcx > )
218
- -> RelateResult < ' tcx , ( ) >
219
- {
220
- debug ! ( "leak_check: skol_map={:?}" ,
221
- skol_map) ;
222
-
223
- let new_vars = self . region_vars_confined_to_snapshot ( snapshot) ;
224
- for ( & skol_br, & skol) in skol_map {
225
- // The inputs to a skolemized variable can only
226
- // be itself or other new variables.
227
- let incoming_taints = self . tainted_regions ( snapshot,
228
- skol,
229
- TaintDirections :: both ( ) ) ;
230
- for & tainted_region in & incoming_taints {
231
- // Each skolemized should only be relatable to itself
232
- // or new variables:
233
- match * tainted_region {
234
- ty:: ReVar ( vid) => {
235
- if new_vars. contains ( & vid) {
236
- continue ;
237
- }
238
- }
239
- _ => {
240
- if tainted_region == skol { continue ; }
241
- }
242
- } ;
243
-
244
- debug ! ( "{:?} (which replaced {:?}) is tainted by {:?}" ,
245
- skol,
246
- skol_br,
247
- tainted_region) ;
248
-
249
- return Err ( if overly_polymorphic {
250
- debug ! ( "Overly polymorphic!" ) ;
251
- TypeError :: RegionsOverlyPolymorphic ( skol_br, tainted_region)
252
- } else {
253
- debug ! ( "Not as polymorphic!" ) ;
254
- TypeError :: RegionsInsufficientlyPolymorphic ( skol_br, tainted_region)
255
- } )
256
- }
257
- }
258
-
259
- Ok ( ( ) )
260
- }
261
-
262
- /// This code converts from skolemized regions back to late-bound
263
- /// regions. It works by replacing each region in the taint set of a
264
- /// skolemized region with a bound-region. The bound region will be bound
265
- /// by the outer-most binder in `value`; the caller must ensure that there is
266
- /// such a binder and it is the right place.
267
- ///
268
- /// This routine is only intended to be used when the leak-check has
269
- /// passed; currently, it's used in the trait matching code to create
270
- /// a set of nested obligations frmo an impl that matches against
271
- /// something higher-ranked. More details can be found in
272
- /// `librustc/middle/traits/README.md`.
273
- ///
274
- /// As a brief example, consider the obligation `for<'a> Fn(&'a int)
275
- /// -> &'a int`, and the impl:
276
- ///
277
- /// impl<A,R> Fn<A,R> for SomethingOrOther
278
- /// where A : Clone
279
- /// { ... }
280
- ///
281
- /// Here we will have replaced `'a` with a skolemized region
282
- /// `'0`. This means that our substitution will be `{A=>&'0
283
- /// int, R=>&'0 int}`.
284
- ///
285
- /// When we apply the substitution to the bounds, we will wind up with
286
- /// `&'0 int : Clone` as a predicate. As a last step, we then go and
287
- /// replace `'0` with a late-bound region `'a`. The depth is matched
288
- /// to the depth of the predicate, in this case 1, so that the final
289
- /// predicate is `for<'a> &'a int : Clone`.
290
- pub fn plug_leaks < T > ( & self ,
291
- skol_map : SkolemizationMap < ' tcx > ,
292
- snapshot : & CombinedSnapshot < ' a , ' tcx > ,
293
- value : T ) -> T
294
- where T : TypeFoldable < ' tcx >
295
- {
296
- debug ! ( "plug_leaks(skol_map={:?}, value={:?})" ,
297
- skol_map,
298
- value) ;
299
-
300
- if skol_map. is_empty ( ) {
301
- return value;
302
- }
303
-
304
- // Compute a mapping from the "taint set" of each skolemized
305
- // region back to the `ty::BoundRegion` that it originally
306
- // represented. Because `leak_check` passed, we know that
307
- // these taint sets are mutually disjoint.
308
- let inv_skol_map: FxHashMap < ty:: Region < ' tcx > , ty:: BoundRegion > =
309
- skol_map
310
- . iter ( )
311
- . flat_map ( |( & skol_br, & skol) | {
312
- self . tainted_regions ( snapshot, skol, TaintDirections :: both ( ) )
313
- . into_iter ( )
314
- . map ( move |tainted_region| ( tainted_region, skol_br) )
315
- } )
316
- . collect ( ) ;
317
-
318
- debug ! ( "plug_leaks: inv_skol_map={:?}" ,
319
- inv_skol_map) ;
320
-
321
- // Remove any instantiated type variables from `value`; those can hide
322
- // references to regions from the `fold_regions` code below.
323
- let value = self . resolve_type_vars_if_possible ( & value) ;
324
-
325
- // Map any skolemization byproducts back to a late-bound
326
- // region. Put that late-bound region at whatever the outermost
327
- // binder is that we encountered in `value`. The caller is
328
- // responsible for ensuring that (a) `value` contains at least one
329
- // binder and (b) that binder is the one we want to use.
330
- let result = self . tcx . fold_regions ( & value, & mut false , |r, current_depth| {
331
- match inv_skol_map. get ( & r) {
332
- None => r,
333
- Some ( br) => {
334
- // It is the responsibility of the caller to ensure
335
- // that each skolemized region appears within a
336
- // binder. In practice, this routine is only used by
337
- // trait checking, and all of the skolemized regions
338
- // appear inside predicates, which always have
339
- // binders, so this assert is satisfied.
340
- assert ! ( current_depth > 1 ) ;
341
-
342
- // since leak-check passed, this skolemized region
343
- // should only have incoming edges from variables
344
- // (which ought not to escape the snapshot, but we
345
- // don't check that) or itself
346
- assert ! (
347
- match * r {
348
- ty:: ReVar ( _) => true ,
349
- ty:: ReSkolemized ( _, ref br1) => br == br1,
350
- _ => false ,
351
- } ,
352
- "leak-check would have us replace {:?} with {:?}" ,
353
- r, br) ;
354
-
355
- self . tcx . mk_region ( ty:: ReLateBound (
356
- ty:: DebruijnIndex :: new ( current_depth - 1 ) , br. clone ( ) ) )
357
- }
358
- }
359
- } ) ;
360
-
361
- self . pop_skolemized ( skol_map, snapshot) ;
362
-
363
- debug ! ( "plug_leaks: result={:?}" , result) ;
91
+ result) ;
364
92
365
93
result
366
94
}
367
-
368
- /// Pops the skolemized regions found in `skol_map` from the region
369
- /// inference context. Whenever you create skolemized regions via
370
- /// `skolemize_late_bound_regions`, they must be popped before you
371
- /// commit the enclosing snapshot (if you do not commit, e.g. within a
372
- /// probe or as a result of an error, then this is not necessary, as
373
- /// popping happens as part of the rollback).
374
- ///
375
- /// Note: popping also occurs implicitly as part of `leak_check`.
376
- pub fn pop_skolemized ( & self ,
377
- skol_map : SkolemizationMap < ' tcx > ,
378
- snapshot : & CombinedSnapshot < ' a , ' tcx > ) {
379
- debug ! ( "pop_skolemized({:?})" , skol_map) ;
380
- let skol_regions: FxHashSet < _ > = skol_map. values ( ) . cloned ( ) . collect ( ) ;
381
- self . borrow_region_constraints ( )
382
- . pop_skolemized ( self . universe ( ) , & skol_regions, & snapshot. region_constraints_snapshot ) ;
383
- self . universe . set ( snapshot. universe ) ;
384
- if !skol_map. is_empty ( ) {
385
- self . projection_cache . borrow_mut ( ) . rollback_skolemized (
386
- & snapshot. projection_cache_snapshot ) ;
387
- }
388
- }
389
95
}
0 commit comments