@@ -233,44 +233,45 @@ impl<'tcx> AutoTraitFinder<'tcx> {
233233}
234234
235235impl 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.
274275 fn evaluate_predicates (
275276 & self ,
276277 infcx : & InferCtxt < ' _ , ' tcx > ,
@@ -393,29 +394,29 @@ impl AutoTraitFinder<'tcx> {
393394 return Some ( ( new_env, final_user_env) ) ;
394395 }
395396
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`).
419420 fn add_user_pred < ' c > (
420421 & self ,
421422 user_computed_preds : & mut FxHashSet < ty:: Predicate < ' c > > ,
@@ -506,8 +507,8 @@ impl AutoTraitFinder<'tcx> {
506507 }
507508 }
508509
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.
511512 fn map_vid_to_region < ' cx > (
512513 & self ,
513514 regions : & RegionConstraintData < ' cx > ,
0 commit comments