@@ -233,44 +233,45 @@ impl<'tcx> AutoTraitFinder<'tcx> {
233
233
}
234
234
235
235
impl AutoTraitFinder < ' tcx > {
236
- // The core logic responsible for computing the bounds for our synthesized impl.
237
- //
238
- // To calculate the bounds, we call `SelectionContext.select` in a loop. Like
239
- // `FulfillmentContext`, we recursively select the nested obligations of predicates we
240
- // encounter. However, whenever we encounter an `UnimplementedError` involving a type parameter,
241
- // we add it to our `ParamEnv`. Since our goal is to determine when a particular type implements
242
- // an auto trait, Unimplemented errors tell us what conditions need to be met.
243
- //
244
- // This method ends up working somewhat similarly to `FulfillmentContext`, but with a few key
245
- // differences. `FulfillmentContext` works under the assumption that it's dealing with concrete
246
- // user code. According, it considers all possible ways that a `Predicate` could be met, which
247
- // isn't always what we want for a synthesized impl. For example, given the predicate `T:
248
- // Iterator`, `FulfillmentContext` can end up reporting an Unimplemented error for `T:
249
- // IntoIterator` -- since there's an implementation of `Iterator` where `T: IntoIterator`,
250
- // `FulfillmentContext` will drive `SelectionContext` to consider that impl before giving up. If
251
- // we were to rely on `FulfillmentContext`'s decision, we might end up synthesizing an impl like
252
- // this:
253
- //
254
- // impl<T> Send for Foo<T> where T: IntoIterator
255
- //
256
- // While it might be technically true that Foo implements Send where `T: IntoIterator`,
257
- // the bound is overly restrictive - it's really only necessary that `T: Iterator`.
258
- //
259
- // For this reason, `evaluate_predicates` handles predicates with type variables specially. When
260
- // we encounter an `Unimplemented` error for a bound such as `T: Iterator`, we immediately add
261
- // it to our `ParamEnv`, and add it to our stack for recursive evaluation. When we later select
262
- // it, we'll pick up any nested bounds, without ever inferring that `T: IntoIterator` needs to
263
- // hold.
264
- //
265
- // One additional consideration is supertrait bounds. Normally, a `ParamEnv` is only ever
266
- // constructed once for a given type. As part of the construction process, the `ParamEnv` will
267
- // have any supertrait bounds normalized -- e.g., if we have a type `struct Foo<T: Copy>`, the
268
- // `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our
269
- // own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or else
270
- // `SelectionContext` will choke on the missing predicates. However, this should never show up
271
- // in the final synthesized generics: we don't want our generated docs page to contain something
272
- // like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a separate
273
- // `user_env`, which only holds the predicates that will actually be displayed to the user.
236
+ /// The core logic responsible for computing the bounds for our synthesized impl.
237
+ ///
238
+ /// To calculate the bounds, we call `SelectionContext.select` in a loop. Like
239
+ /// `FulfillmentContext`, we recursively select the nested obligations of predicates we
240
+ /// encounter. However, whenever we encounter an `UnimplementedError` involving a type
241
+ /// parameter, we add it to our `ParamEnv`. Since our goal is to determine when a particular
242
+ /// type implements an auto trait, Unimplemented errors tell us what conditions need to be met.
243
+ ///
244
+ /// This method ends up working somewhat similarly to `FulfillmentContext`, but with a few key
245
+ /// differences. `FulfillmentContext` works under the assumption that it's dealing with concrete
246
+ /// user code. According, it considers all possible ways that a `Predicate` could be met, which
247
+ /// isn't always what we want for a synthesized impl. For example, given the predicate `T:
248
+ /// Iterator`, `FulfillmentContext` can end up reporting an Unimplemented error for `T:
249
+ /// IntoIterator` -- since there's an implementation of `Iterator` where `T: IntoIterator`,
250
+ /// `FulfillmentContext` will drive `SelectionContext` to consider that impl before giving up.
251
+ /// If we were to rely on `FulfillmentContext`s decision, we might end up synthesizing an impl
252
+ /// like this:
253
+ ///
254
+ /// impl<T> Send for Foo<T> where T: IntoIterator
255
+ ///
256
+ /// While it might be technically true that Foo implements Send where `T: IntoIterator`,
257
+ /// the bound is overly restrictive - it's really only necessary that `T: Iterator`.
258
+ ///
259
+ /// For this reason, `evaluate_predicates` handles predicates with type variables specially.
260
+ /// When we encounter an `Unimplemented` error for a bound such as `T: Iterator`, we immediately
261
+ /// add it to our `ParamEnv`, and add it to our stack for recursive evaluation. When we later
262
+ /// select it, we'll pick up any nested bounds, without ever inferring that `T: IntoIterator`
263
+ /// needs to hold.
264
+ ///
265
+ /// One additional consideration is supertrait bounds. Normally, a `ParamEnv` is only ever
266
+ /// constructed once for a given type. As part of the construction process, the `ParamEnv` will
267
+ /// have any supertrait bounds normalized -- e.g., if we have a type `struct Foo<T: Copy>`, the
268
+ /// `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our
269
+ /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or
270
+ /// else `SelectionContext` will choke on the missing predicates. However, this should never
271
+ /// show up in the final synthesized generics: we don't want our generated docs page to contain
272
+ /// something like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a
273
+ /// separate `user_env`, which only holds the predicates that will actually be displayed to the
274
+ /// user.
274
275
fn evaluate_predicates (
275
276
& self ,
276
277
infcx : & InferCtxt < ' _ , ' tcx > ,
@@ -393,29 +394,29 @@ impl AutoTraitFinder<'tcx> {
393
394
return Some ( ( new_env, final_user_env) ) ;
394
395
}
395
396
396
- // This method is designed to work around the following issue:
397
- // When we compute auto trait bounds, we repeatedly call `SelectionContext.select`,
398
- // progressively building a `ParamEnv` based on the results we get.
399
- // However, our usage of `SelectionContext` differs from its normal use within the compiler,
400
- // in that we capture and re-reprocess predicates from `Unimplemented` errors.
401
- //
402
- // This can lead to a corner case when dealing with region parameters.
403
- // During our selection loop in `evaluate_predicates`, we might end up with
404
- // two trait predicates that differ only in their region parameters:
405
- // one containing a HRTB lifetime parameter, and one containing a 'normal'
406
- // lifetime parameter. For example:
407
- //
408
- // T as MyTrait<'a>
409
- // T as MyTrait<'static>
410
- //
411
- // If we put both of these predicates in our computed `ParamEnv`, we'll
412
- // confuse `SelectionContext`, since it will (correctly) view both as being applicable.
413
- //
414
- // To solve this, we pick the 'more strict' lifetime bound -- i.e., the HRTB
415
- // Our end goal is to generate a user-visible description of the conditions
416
- // under which a type implements an auto trait. A trait predicate involving
417
- // a HRTB means that the type needs to work with any choice of lifetime,
418
- // not just one specific lifetime (e.g., `'static`).
397
+ /// This method is designed to work around the following issue:
398
+ /// When we compute auto trait bounds, we repeatedly call `SelectionContext.select`,
399
+ /// progressively building a `ParamEnv` based on the results we get.
400
+ /// However, our usage of `SelectionContext` differs from its normal use within the compiler,
401
+ /// in that we capture and re-reprocess predicates from `Unimplemented` errors.
402
+ ///
403
+ /// This can lead to a corner case when dealing with region parameters.
404
+ /// During our selection loop in `evaluate_predicates`, we might end up with
405
+ /// two trait predicates that differ only in their region parameters:
406
+ /// one containing a HRTB lifetime parameter, and one containing a 'normal'
407
+ /// lifetime parameter. For example:
408
+ ///
409
+ /// T as MyTrait<'a>
410
+ /// T as MyTrait<'static>
411
+ ///
412
+ /// If we put both of these predicates in our computed `ParamEnv`, we'll
413
+ /// confuse `SelectionContext`, since it will (correctly) view both as being applicable.
414
+ ///
415
+ /// To solve this, we pick the 'more strict' lifetime bound -- i.e., the HRTB
416
+ /// Our end goal is to generate a user-visible description of the conditions
417
+ /// under which a type implements an auto trait. A trait predicate involving
418
+ /// a HRTB means that the type needs to work with any choice of lifetime,
419
+ /// not just one specific lifetime (e.g., `'static`).
419
420
fn add_user_pred < ' c > (
420
421
& self ,
421
422
user_computed_preds : & mut FxHashSet < ty:: Predicate < ' c > > ,
@@ -506,8 +507,8 @@ impl AutoTraitFinder<'tcx> {
506
507
}
507
508
}
508
509
509
- // This is very similar to `handle_lifetimes`. However, instead of matching `ty::Region`' s
510
- // to each other, we match `ty::RegionVid`' s to `ty::Region`' s.
510
+ /// This is very similar to `handle_lifetimes`. However, instead of matching `ty::Region`s
511
+ /// to each other, we match `ty::RegionVid`s to `ty::Region`s.
511
512
fn map_vid_to_region < ' cx > (
512
513
& self ,
513
514
regions : & RegionConstraintData < ' cx > ,
0 commit comments