// The core logic responsible for computing the bounds for our synthesized impl.
//
// To calculate the bounds, we call SelectionContext.select in a loop. Like FulfillmentContext,
// we recursively select the nested obligations of predicates we encounter. However, whenver we
// encounter an UnimplementedError involving a type parameter, we add it to our ParamEnv. Since
// our goal is to determine when a particular type implements an auto trait, Unimplemented
// errors tell us what conditions need to be met.
//
// This method ends up working somewhat similary to FulfillmentContext, but with a few key
// differences. FulfillmentContext works under the assumption that it's dealing with concrete
// user code. According, it considers all possible ways that a Predicate could be met - which
// isn't always what we want for a synthesized impl. For example, given the predicate 'T:
// Iterator', FulfillmentContext can end up reporting an Unimplemented error for T:
// IntoIterator - since there's an implementation of Iteratpr where T: IntoIterator,
// FulfillmentContext will drive SelectionContext to consider that impl before giving up. If we
// were to rely on FulfillmentContext's decision, we might end up synthesizing an impl like
// this:
// 'impl<T> Send for Foo<T> where T: IntoIterator'
//
// While it might be technically true that Foo implements Send where T: IntoIterator,
// the bound is overly restrictive - it's really only necessary that T: Iterator.
//
// For this reason, evaluate_predicates handles predicates with type variables specially. When
// we encounter an Unimplemented error for a bound such as 'T: Iterator', we immediately add it
// to our ParamEnv, and add it to our stack for recursive evaluation. When we later select it,
// we'll pick up any nested bounds, without ever inferring that 'T: IntoIterator' needs to
// hold.
//
// One additonal consideration is supertrait bounds. Normally, a ParamEnv is only ever
// consutrcted once for a given type. As part of the construction process, the ParamEnv will
// have any supertrait bounds normalized - e.g. if we have a type 'struct Foo<T: Copy>', the
// ParamEnv will contain 'T: Copy' and 'T: Clone', since 'Copy: Clone'. When we construct our
// own ParamEnv, we need to do this outselves, through traits::elaborate_predicates, or else
// SelectionContext will choke on the missing predicates. However, this should never show up in
// the final synthesized generics: we don't want our generated docs page to contain something
// like 'T: Copy + Clone', as that's redundant. Therefore, we keep track of a separate
// 'user_env', which only holds the predicates that will actually be displayed to the user.
The core logic responsible for computing the bounds for our synthesized impl.
To calculate the bounds, we call SelectionContext.select in a loop. Like FulfillmentContext,
we recursively select the nested obligations of predicates we encounter. However, whenver we
encounter an UnimplementedError involving a type parameter, we add it to our ParamEnv. Since
our goal is to determine when a particular type implements an auto trait, Unimplemented
errors tell us what conditions need to be met.

This method ends up working somewhat similary to FulfillmentContext, but with a few key
differences. FulfillmentContext works under the assumption that it's dealing with concrete
user code. According, it considers all possible ways that a Predicate could be met - which
isn't always what we want for a synthesized impl. For example, given the predicate 'T:
Iterator', FulfillmentContext can end up reporting an Unimplemented error for T:
IntoIterator - since there's an implementation of Iteratpr where T: IntoIterator,
FulfillmentContext will drive SelectionContext to consider that impl before giving up. If we
were to rely on FulfillmentContext's decision, we might end up synthesizing an impl like
this:
'impl Send for Foo where T: IntoIterator'

While it might be technically true that Foo implements Send where T: IntoIterator,
the bound is overly restrictive - it's really only necessary that T: Iterator.

For this reason, evaluate_predicates handles predicates with type variables specially. When
we encounter an Unimplemented error for a bound such as 'T: Iterator', we immediately add it
to our ParamEnv, and add it to our stack for recursive evaluation. When we later select it,
we'll pick up any nested bounds, without ever inferring that 'T: IntoIterator' needs to
hold.

One additonal consideration is supertrait bounds. Normally, a ParamEnv is only ever
consutrcted once for a given type. As part of the construction process, the ParamEnv will
have any supertrait bounds normalized - e.g.
The core logic responsible for computing the bounds for our synthesized impl . To calculate the bounds we call SelectionContext . select in a loop . Like FulfillmentContext we recursively select the nested obligations of predicates we encounter . However whenver we encounter an UnimplementedError involving a type parameter we add it to our ParamEnv . Since our goal is to determine when a particular type implements an auto trait Unimplemented errors tell us what conditions need to be met . This method ends up working somewhat similary to FulfillmentContext but with a few key differences . FulfillmentContext works under the assumption that it ' s dealing with concrete user code . According it considers all possible ways that a Predicate could be met - which isn ' t always what we want for a synthesized impl . For example given the predicate ' T : Iterator ' FulfillmentContext can end up reporting an Unimplemented error for T : IntoIterator - since there ' s an implementation of Iteratpr where T : IntoIterator FulfillmentContext will drive SelectionContext to consider that impl before giving up . If we were to rely on FulfillmentContext ' s decision we might end up synthesizing an impl like this : ' impl Send for Foo where T : IntoIterator ' While it might be technically true that Foo implements Send where T : IntoIterator the bound is overly restrictive - it ' s really only necessary that T : Iterator . For this reason evaluate_predicates handles predicates with type variables specially . When we encounter an Unimplemented error for a bound such as ' T : Iterator ' we immediately add it to our ParamEnv and add it to our stack for recursive evaluation . When we later select it we ' ll pick up any nested bounds without ever inferring that ' T : IntoIterator ' needs to hold . One additonal consideration is supertrait bounds . Normally a ParamEnv is only ever consutrcted once for a given type . As part of the construction process the ParamEnv will have any supertrait bounds normalized - e . g .
pub fn evaluate_predicates<'b, 'gcx, 'c>(
        &self,
        infcx: &InferCtxt<'b, 'tcx, 'c>,
        ty_did: DefId,
        trait_did: DefId,
        ty: ty::Ty<'c>,
        param_env: ty::ParamEnv<'c>,
        user_env: ty::ParamEnv<'c>,
        fresh_preds: &mut FxHashSet<ty::Predicate<'c>>,
        only_projections: bool,
    ) -> Option<(ty::ParamEnv<'c>, ty::ParamEnv<'c>)> {
        let tcx = infcx.tcx;
        let mut select = SelectionContext::new(&infcx);
        let mut already_visited = FxHashSet();
        let mut predicates = VecDeque::new();
        predicates.push_back(ty::Binder::bind(ty::TraitPredicate {
            trait_ref: ty::TraitRef {
                def_id: trait_did,
                substs: infcx.tcx.mk_substs_trait(ty, &[]),
            },
        }));
        let mut computed_preds: FxHashSet<_> = param_env.caller_bounds.iter().cloned().collect();
        let mut user_computed_preds: FxHashSet<_> =
            user_env.caller_bounds.iter().cloned().collect();
        let mut new_env = param_env.clone();
        let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
        while let Some(pred) = predicates.pop_front() {
            infcx.clear_caches();
            if !already_visited.insert(pred.clone()) {
                continue;
            }
            let result = select.select(&Obligation::new(dummy_cause.clone(), new_env, pred));
            match &result {
                &Ok(Some(ref vtable)) => {
                    let obligations = vtable.clone().nested_obligations().into_iter();
                    if !self.evaluate_nested_obligations(
                        ty,
                        obligations,
                        &mut user_computed_preds,
                        fresh_preds,
                        &mut predicates,
                        &mut select,
                        only_projections,
                    ) {
                        return None;
                    }
                }
                &Ok(None) => {}
                &Err(SelectionError::Unimplemented) => {
                    if self.is_of_param(pred.skip_binder().trait_ref.substs) {
                        already_visited.remove(&pred);
                        self.add_user_pred(&mut user_computed_preds,
                                           ty::Predicate::Trait(pred.clone()));
                        predicates.push_back(pred);
                    } else {
                        debug!(
                            "evaluate_nested_obligations: Unimplemented found, bailing: \
                             {:?} {:?} {:?}",
                            ty,
                            pred,
                            pred.skip_binder().trait_ref.substs
                        );
                        return None;
                    }
                }
                _ => panic!("Unexpected error for '{:?}': {:?}", ty, result),
            };
            computed_preds.extend(user_computed_preds.iter().cloned());
            let normalized_preds =
                elaborate_predicates(tcx, computed_preds.clone().into_iter().collect());
            new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal);
        }
        let final_user_env = ty::ParamEnv::new(
            tcx.mk_predicates(user_computed_preds.into_iter()),
            user_env.reveal,
        );
        debug!(
            "evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \
             '{:?}'",
            ty_did, trait_did, new_env, final_user_env
        );
        return Some((new_env, final_user_env));
    }
pub fn evaluate_predicates < ' b , ' gcx , ' c > ( & self , infcx : & InferCtxt < ' b , ' tcx , ' c > , ty_did : DefId , trait_did : DefId , ty : ty :: Ty < ' c > , param_env : ty :: ParamEnv < ' c > , user_env : ty :: ParamEnv < ' c > , fresh_preds : & mut FxHashSet < ty :: Predicate < ' c > > , only_projections : bool , ) -> Option < ( ty :: ParamEnv < ' c > , ty :: ParamEnv < ' c > ) > { let tcx = infcx . tcx ; let mut select = SelectionContext :: new ( & infcx ) ; let mut already_visited = FxHashSet ( ) ; let mut predicates = VecDeque :: new ( ) ; predicates . push_back ( ty :: Binder :: bind ( ty :: TraitPredicate { trait_ref : ty :: TraitRef { def_id : trait_did , substs : infcx . tcx . mk_substs_trait ( ty , & [ ] ) , } , } ) ) ; let mut computed_preds : FxHashSet < _ > = param_env . caller_bounds . iter ( ) . cloned ( ) . collect ( ) ; let mut user_computed_preds : FxHashSet < _ > = user_env . caller_bounds . iter ( ) . cloned ( ) . collect ( ) ; let mut new_env = param_env . clone ( ) ; let dummy_cause = ObligationCause :: misc ( DUMMY_SP , ast :: DUMMY_NODE_ID ) ; while let Some ( pred ) = predicates . pop_front ( ) { infcx . clear_caches ( ) ; if ! already_visited . insert ( pred . clone ( ) ) { continue ; } let result = select . select ( & Obligation :: new ( dummy_cause . clone ( ) , new_env , pred ) ) ; match & result { & Ok ( Some ( ref vtable ) ) => { let obligations = vtable . clone ( ) . nested_obligations ( ) . into_iter ( ) ; if ! self . evaluate_nested_obligations ( ty , obligations , & mut user_computed_preds , fresh_preds , & mut predicates , & mut select , only_projections , ) { return None ; } } & Ok ( None ) => { } & Err ( SelectionError :: Unimplemented ) => { if self . is_of_param ( pred . skip_binder ( ) . trait_ref . substs ) { already_visited . remove ( & pred ) ; self . add_user_pred ( & mut user_computed_preds , ty :: Predicate :: Trait ( pred . clone ( ) ) ) ; predicates . push_back ( pred ) ; } else { debug ! ( " \
 " ty pred pred skip_binder ( ) trait_ref substs ) ; return None ; } } _ => panic ! ( " " ty result ) , } ; computed_preds . extend ( user_computed_preds . iter ( ) . cloned ( ) ) ; let normalized_preds = elaborate_predicates ( tcx , computed_preds . clone ( ) . into_iter ( ) . collect ( ) ) ; new_env = ty :: ParamEnv :: new ( tcx . mk_predicates ( normalized_preds ) , param_env . reveal ) ; } let final_user_env = ty :: ParamEnv :: new ( tcx . mk_predicates ( user_computed_preds . into_iter ( ) ) , user_env . reveal , ) ; debug ! ( " \
 " ty_did trait_did new_env final_user_env ) ; return Some ( ( new_env , final_user_env ) ) ; }
The core logic responsible for computing the bounds for our synthesized impl.
The core logic responsible for computing the bounds for our synthesized impl .
&self
infcx
&InferCtxt<'b, 'tcx, 'c>
ty_did
DefId
trait_did
DefId
ty
ty::Ty<'c>
param_env
ty::ParamEnv<'c>
user_env
ty::ParamEnv<'c>
fresh_preds
&mut FxHashSet<ty::Predicate<'c>>
only_projections
bool