@@ -272,6 +272,123 @@ nested obligation `int : Bar<U>` to find out that `U=uint`.
272
272
It would be good to only do *just as much* nested resolution as
273
273
necessary. Currently, though, we just do a full resolution.
274
274
275
+ # Higher-ranked trait bounds
276
+
277
+ One of the more subtle concepts at work are *higher-ranked trait
278
+ bounds*. An example of such a bound is `for<'a> MyTrait<&'a int>`.
279
+ Let's walk through how selection on higher-ranked trait references
280
+ works.
281
+
282
+ ## Basic matching and skolemization leaks
283
+
284
+ Let's walk through the test `compile-fail/hrtb-just-for-static.rs` to see
285
+ how it works. The test starts with the trait `Foo`:
286
+
287
+ ```rust
288
+ trait Foo<X> {
289
+ fn foo(&self, x: X) { }
290
+ }
291
+ ```
292
+
293
+ Let's say we have a function `want_hrtb` that wants a type which
294
+ implements `Foo<&'a int>` for any `'a`:
295
+
296
+ ```rust
297
+ fn want_hrtb<T>() where T : for<'a> Foo<&'a int> { ... }
298
+ ```
299
+
300
+ Now we have a struct `AnyInt` that implements `Foo<&'a int>` for any
301
+ `'a`:
302
+
303
+ ```rust
304
+ struct AnyInt;
305
+ impl<'a> Foo<&'a int> for AnyInt { }
306
+ ```
307
+
308
+ And the question is, does `AnyInt : for<'a> Foo<&'a int>`? We want the
309
+ answer to be yes. The algorithm for figuring it out is closely related
310
+ to the subtyping for higher-ranked types (which is described in
311
+ `middle::infer::higher_ranked::doc`, but also in a [paper by SPJ] that
312
+ I recommend you read).
313
+
314
+ 1. Skolemize the obligation.
315
+ 2. Match the impl against the skolemized obligation.
316
+ 3. Check for skolemization leaks.
317
+
318
+ [paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/
319
+
320
+ So let's work through our example. The first thing we would do is to
321
+ skolemize the obligation, yielding `AnyInt : Foo<&'0 int>` (here `'0`
322
+ represents skolemized region #0). Note that now have no quantifiers;
323
+ in terms of the compiler type, this changes from a `ty::PolyTraitRef`
324
+ to a `TraitRef`. We would then create the `TraitRef` from the impl,
325
+ using fresh variables for it's bound regions (and thus getting
326
+ `Foo<&'$a int>`, where `'$a` is the inference variable for `'a`). Next
327
+ we relate the two trait refs, yielding a graph with the constraint
328
+ that `'0 == '$a`. Finally, we check for skolemization "leaks" -- a
329
+ leak is basically any attempt to relate a skolemized region to another
330
+ skolemized region, or to any region that pre-existed the impl match.
331
+ The leak check is done by searching from the skolemized region to find
332
+ the set of regions that it is related to in any way. This is called
333
+ the "taint" set. To pass the check, that set must consist *solely* of
334
+ itself and region variables from the impl. If the taint set includes
335
+ any other region, then the match is a failure. In this case, the taint
336
+ set for `'0` is `{'0, '$a}`, and hence the check will succeed.
337
+
338
+ Let's consider a failure case. Imagine we also have a struct
339
+
340
+ ```rust
341
+ struct StaticInt;
342
+ impl Foo<&'static int> for StaticInt;
343
+ ```
344
+
345
+ We want the obligation `StaticInt : for<'a> Foo<&'a int>` to be
346
+ considered unsatisfied. The check begins just as before. `'a` is
347
+ skolemized to `'0` and the impl trait reference is instantiated to
348
+ `Foo<&'static int>`. When we relate those two, we get a constraint
349
+ like `'static == '0`. This means that the taint set for `'0` is `{'0,
350
+ 'static}`, which fails the leak check.
351
+
352
+ ## Higher-ranked trait obligations
353
+
354
+ Once the basic matching is done, we get to another interesting topic:
355
+ how to deal with impl obligations. I'll work through a simple example
356
+ here. Imagine we have the traits `Foo` and `Bar` and an associated impl:
357
+
358
+ ```
359
+ trait Foo<X> {
360
+ fn foo(&self, x: X) { }
361
+ }
362
+
363
+ trait Bar<X> {
364
+ fn bar(&self, x: X) { }
365
+ }
366
+
367
+ impl<X,F> Foo<X> for F
368
+ where F : Bar<X>
369
+ {
370
+ }
371
+ ```
372
+
373
+ Now let's say we have a obligation `for<'a> Foo<&'a int>` and we match
374
+ this impl. What obligation is generated as a result? We want to get
375
+ `for<'a> Bar<&'a int>`, but how does that happen?
376
+
377
+ After the matching, we are in a position where we have a skolemized
378
+ substitution like `X => &'0 int`. If we apply this substitution to the
379
+ impl obligations, we get `F : Bar<&'0 int>`. Obviously this is not
380
+ directly usable because the skolemized region `'0` cannot leak out of
381
+ our computation.
382
+
383
+ What we do is to create an inverse mapping from the taint set of `'0`
384
+ back to the original bound region (`'a`, here) that `'0` resulted
385
+ from. (This is done in `higher_ranked::plug_leaks`). We know that the
386
+ leak check passed, so this taint set consists solely of the skolemized
387
+ region itself plus various intermediate region variables. We then walk
388
+ the trait-reference and convert every region in that taint set back to
389
+ a late-bound region, so in this case we'd wind up with `for<'a> F :
390
+ Bar<&'a int>`.
391
+
275
392
# Caching and subtle considerations therewith
276
393
277
394
In general we attempt to cache the results of trait selection. This
@@ -400,6 +517,4 @@ there is no other type the user could enter. However, it is not
400
517
future; we wouldn't have to guess types, in particular, we could be
401
518
led by the impls.
402
519
403
-
404
-
405
520
*/
0 commit comments