1 use crate::infer
::{InferCtxt, TyOrConstInferVar}
;
2 use rustc_data_structures
::fx
::FxHashMap
;
3 use rustc_data_structures
::obligation_forest
::ProcessResult
;
4 use rustc_data_structures
::obligation_forest
::{Error, ForestObligation, Outcome}
;
5 use rustc_data_structures
::obligation_forest
::{ObligationForest, ObligationProcessor}
;
6 use rustc_infer
::traits
::ProjectionCacheKey
;
7 use rustc_infer
::traits
::{SelectionError, TraitEngine, TraitObligation}
;
8 use rustc_middle
::mir
::interpret
::ErrorHandled
;
9 use rustc_middle
::ty
::abstract_const
::NotConstEvaluatable
;
10 use rustc_middle
::ty
::error
::{ExpectedFound, TypeError}
;
11 use rustc_middle
::ty
::subst
::SubstsRef
;
12 use rustc_middle
::ty
::{self, Binder, Const, TypeVisitable}
;
13 use std
::marker
::PhantomData
;
15 use super::const_evaluatable
;
16 use super::project
::{self, ProjectAndUnifyResult}
;
17 use super::select
::SelectionContext
;
19 use super::CodeAmbiguity
;
20 use super::CodeProjectionError
;
21 use super::CodeSelectionError
;
22 use super::EvaluationResult
;
23 use super::PredicateObligation
;
24 use super::Unimplemented
;
25 use super::{FulfillmentError, FulfillmentErrorCode}
;
27 use crate::traits
::project
::PolyProjectionObligation
;
28 use crate::traits
::project
::ProjectionCacheKeyExt
as _
;
29 use crate::traits
::query
::evaluate_obligation
::InferCtxtExt
;
31 impl<'tcx
> ForestObligation
for PendingPredicateObligation
<'tcx
> {
32 /// Note that we include both the `ParamEnv` and the `Predicate`,
33 /// as the `ParamEnv` can influence whether fulfillment succeeds
35 type CacheKey
= ty
::ParamEnvAnd
<'tcx
, ty
::Predicate
<'tcx
>>;
37 fn as_cache_key(&self) -> Self::CacheKey
{
38 self.obligation
.param_env
.and(self.obligation
.predicate
)
42 /// The fulfillment context is used to drive trait resolution. It
43 /// consists of a list of obligations that must be (eventually)
44 /// satisfied. The job is to track which are satisfied, which yielded
45 /// errors, and which are still pending. At any point, users can call
46 /// `select_where_possible`, and the fulfillment context will try to do
47 /// selection, retaining only those obligations that remain
48 /// ambiguous. This may be helpful in pushing type inference
49 /// along. Once all type inference constraints have been generated, the
50 /// method `select_all_or_error` can be used to report any remaining
51 /// ambiguous cases as errors.
52 pub struct FulfillmentContext
<'tcx
> {
53 // A list of all obligations that have been registered with this
54 // fulfillment context.
55 predicates
: ObligationForest
<PendingPredicateObligation
<'tcx
>>,
57 relationships
: FxHashMap
<ty
::TyVid
, ty
::FoundRelationships
>,
59 // Is it OK to register obligations into this infcx inside
62 // The "primary fulfillment" in many cases in typeck lives
63 // outside of any snapshot, so any use of it inside a snapshot
64 // will lead to trouble and therefore is checked against, but
65 // other fulfillment contexts sometimes do live inside of
66 // a snapshot (they don't *straddle* a snapshot, so there
67 // is no trouble there).
68 usable_in_snapshot
: bool
,
71 #[derive(Clone, Debug)]
72 pub struct PendingPredicateObligation
<'tcx
> {
73 pub obligation
: PredicateObligation
<'tcx
>,
74 // This is far more often read than modified, meaning that we
75 // should mostly optimize for reading speed, while modifying is not as relevant.
77 // For whatever reason using a boxed slice is slower than using a `Vec` here.
78 pub stalled_on
: Vec
<TyOrConstInferVar
<'tcx
>>,
81 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
82 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
83 static_assert_size
!(PendingPredicateObligation
<'_
>, 72);
85 impl<'a
, 'tcx
> FulfillmentContext
<'tcx
> {
86 /// Creates a new fulfillment context.
87 pub(super) fn new() -> FulfillmentContext
<'tcx
> {
89 predicates
: ObligationForest
::new(),
90 relationships
: FxHashMap
::default(),
91 usable_in_snapshot
: false,
95 pub(super) fn new_in_snapshot() -> FulfillmentContext
<'tcx
> {
97 predicates
: ObligationForest
::new(),
98 relationships
: FxHashMap
::default(),
99 usable_in_snapshot
: true,
103 /// Attempts to select obligations using `selcx`.
104 fn select(&mut self, selcx
: SelectionContext
<'a
, 'tcx
>) -> Vec
<FulfillmentError
<'tcx
>> {
105 let span
= debug_span
!("select", obligation_forest_size
= ?
self.predicates
.len());
106 let _enter
= span
.enter();
108 // Process pending obligations.
109 let outcome
: Outcome
<_
, _
> =
110 self.predicates
.process_obligations(&mut FulfillProcessor { selcx }
);
112 // FIXME: if we kept the original cache key, we could mark projection
113 // obligations as complete for the projection cache here.
115 let errors
: Vec
<FulfillmentError
<'tcx
>> =
116 outcome
.errors
.into_iter().map(to_fulfillment_error
).collect();
119 "select({} predicates remaining, {} errors) done",
120 self.predicates
.len(),
128 impl<'tcx
> TraitEngine
<'tcx
> for FulfillmentContext
<'tcx
> {
129 fn register_predicate_obligation(
131 infcx
: &InferCtxt
<'tcx
>,
132 obligation
: PredicateObligation
<'tcx
>,
134 // this helps to reduce duplicate errors, as well as making
135 // debug output much nicer to read and so on.
136 let obligation
= infcx
.resolve_vars_if_possible(obligation
);
138 debug
!(?obligation
, "register_predicate_obligation");
140 assert
!(!infcx
.is_in_snapshot() || self.usable_in_snapshot
);
142 super::relationships
::update(self, infcx
, &obligation
);
145 .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }
);
148 fn select_all_or_error(&mut self, infcx
: &InferCtxt
<'tcx
>) -> Vec
<FulfillmentError
<'tcx
>> {
150 let errors
= self.select_where_possible(infcx
);
151 if !errors
.is_empty() {
156 self.predicates
.to_errors(CodeAmbiguity
).into_iter().map(to_fulfillment_error
).collect()
159 fn select_where_possible(&mut self, infcx
: &InferCtxt
<'tcx
>) -> Vec
<FulfillmentError
<'tcx
>> {
160 let selcx
= SelectionContext
::new(infcx
);
164 fn pending_obligations(&self) -> Vec
<PredicateObligation
<'tcx
>> {
165 self.predicates
.map_pending_obligations(|o
| o
.obligation
.clone())
168 fn relationships(&mut self) -> &mut FxHashMap
<ty
::TyVid
, ty
::FoundRelationships
> {
169 &mut self.relationships
173 struct FulfillProcessor
<'a
, 'tcx
> {
174 selcx
: SelectionContext
<'a
, 'tcx
>,
177 fn mk_pending(os
: Vec
<PredicateObligation
<'_
>>) -> Vec
<PendingPredicateObligation
<'_
>> {
179 .map(|o
| PendingPredicateObligation { obligation: o, stalled_on: vec![] }
)
183 impl<'a
, 'tcx
> ObligationProcessor
for FulfillProcessor
<'a
, 'tcx
> {
184 type Obligation
= PendingPredicateObligation
<'tcx
>;
185 type Error
= FulfillmentErrorCode
<'tcx
>;
186 type OUT
= Outcome
<Self::Obligation
, Self::Error
>;
188 /// Identifies whether a predicate obligation needs processing.
190 /// This is always inlined, despite its size, because it has a single
191 /// callsite and it is called *very* frequently.
193 fn needs_process_obligation(&self, pending_obligation
: &Self::Obligation
) -> bool
{
194 // If we were stalled on some unresolved variables, first check whether
195 // any of them have been resolved; if not, don't bother doing more work
197 match pending_obligation
.stalled_on
.len() {
198 // Match arms are in order of frequency, which matters because this
199 // code is so hot. 1 and 0 dominate; 2+ is fairly rare.
201 let infer_var
= pending_obligation
.stalled_on
[0];
202 self.selcx
.infcx
.ty_or_const_infer_var_changed(infer_var
)
205 // In this case we haven't changed, but wish to make a change.
209 // This `for` loop was once a call to `all()`, but this lower-level
210 // form was a perf win. See #64545 for details.
212 for &infer_var
in &pending_obligation
.stalled_on
{
213 if self.selcx
.infcx
.ty_or_const_infer_var_changed(infer_var
) {
223 /// Processes a predicate obligation and returns either:
224 /// - `Changed(v)` if the predicate is true, presuming that `v` are also true
225 /// - `Unchanged` if we don't have enough info to be sure
226 /// - `Error(e)` if the predicate does not hold
228 /// This is called much less often than `needs_process_obligation`, so we
231 #[instrument(level = "debug", skip(self, pending_obligation))]
232 fn process_obligation(
234 pending_obligation
: &mut PendingPredicateObligation
<'tcx
>,
235 ) -> ProcessResult
<PendingPredicateObligation
<'tcx
>, FulfillmentErrorCode
<'tcx
>> {
236 pending_obligation
.stalled_on
.truncate(0);
238 let obligation
= &mut pending_obligation
.obligation
;
240 debug
!(?obligation
, "pre-resolve");
242 if obligation
.predicate
.has_non_region_infer() {
243 obligation
.predicate
= self.selcx
.infcx
.resolve_vars_if_possible(obligation
.predicate
);
246 let obligation
= &pending_obligation
.obligation
;
248 let infcx
= self.selcx
.infcx
;
250 if obligation
.predicate
.has_projections() {
251 let mut obligations
= Vec
::new();
252 let predicate
= crate::traits
::project
::try_normalize_with_depth_to(
254 obligation
.param_env
,
255 obligation
.cause
.clone(),
256 obligation
.recursion_depth
+ 1,
257 obligation
.predicate
,
260 if predicate
!= obligation
.predicate
{
261 obligations
.push(obligation
.with(infcx
.tcx
, predicate
));
262 return ProcessResult
::Changed(mk_pending(obligations
));
265 let binder
= obligation
.predicate
.kind();
266 match binder
.no_bound_vars() {
267 None
=> match binder
.skip_binder() {
268 // Evaluation will discard candidates using the leak check.
269 // This means we need to pass it the bound version of our
271 ty
::PredicateKind
::Clause(ty
::Clause
::Trait(trait_ref
)) => {
272 let trait_obligation
= obligation
.with(infcx
.tcx
, binder
.rebind(trait_ref
));
274 self.process_trait_obligation(
277 &mut pending_obligation
.stalled_on
,
280 ty
::PredicateKind
::Clause(ty
::Clause
::Projection(data
)) => {
281 let project_obligation
= obligation
.with(infcx
.tcx
, binder
.rebind(data
));
283 self.process_projection_obligation(
286 &mut pending_obligation
.stalled_on
,
289 ty
::PredicateKind
::Clause(ty
::Clause
::RegionOutlives(_
))
290 | ty
::PredicateKind
::Clause(ty
::Clause
::TypeOutlives(_
))
291 | ty
::PredicateKind
::WellFormed(_
)
292 | ty
::PredicateKind
::ObjectSafe(_
)
293 | ty
::PredicateKind
::ClosureKind(..)
294 | ty
::PredicateKind
::Subtype(_
)
295 | ty
::PredicateKind
::Coerce(_
)
296 | ty
::PredicateKind
::ConstEvaluatable(..)
297 | ty
::PredicateKind
::ConstEquate(..) => {
299 ty
::Binder
::dummy(infcx
.replace_bound_vars_with_placeholders(binder
));
300 ProcessResult
::Changed(mk_pending(vec
![obligation
.with(infcx
.tcx
, pred
)]))
302 ty
::PredicateKind
::Ambiguous
=> ProcessResult
::Unchanged
,
303 ty
::PredicateKind
::TypeWellFormedFromEnv(..) => {
304 bug
!("TypeWellFormedFromEnv is only used for Chalk")
307 Some(pred
) => match pred
{
308 ty
::PredicateKind
::Clause(ty
::Clause
::Trait(data
)) => {
309 let trait_obligation
= obligation
.with(infcx
.tcx
, Binder
::dummy(data
));
311 self.process_trait_obligation(
314 &mut pending_obligation
.stalled_on
,
318 ty
::PredicateKind
::Clause(ty
::Clause
::RegionOutlives(data
)) => {
319 if infcx
.considering_regions
{
320 infcx
.region_outlives_predicate(&obligation
.cause
, Binder
::dummy(data
));
323 ProcessResult
::Changed(vec
![])
326 ty
::PredicateKind
::Clause(ty
::Clause
::TypeOutlives(ty
::OutlivesPredicate(
330 if infcx
.considering_regions
{
331 infcx
.register_region_obligation_with_cause(t_a
, r_b
, &obligation
.cause
);
333 ProcessResult
::Changed(vec
![])
336 ty
::PredicateKind
::Clause(ty
::Clause
::Projection(ref data
)) => {
337 let project_obligation
= obligation
.with(infcx
.tcx
, Binder
::dummy(*data
));
339 self.process_projection_obligation(
342 &mut pending_obligation
.stalled_on
,
346 ty
::PredicateKind
::ObjectSafe(trait_def_id
) => {
347 if !self.selcx
.tcx().is_object_safe(trait_def_id
) {
348 ProcessResult
::Error(CodeSelectionError(Unimplemented
))
350 ProcessResult
::Changed(vec
![])
354 ty
::PredicateKind
::ClosureKind(_
, closure_substs
, kind
) => {
355 match self.selcx
.infcx
.closure_kind(closure_substs
) {
356 Some(closure_kind
) => {
357 if closure_kind
.extends(kind
) {
358 ProcessResult
::Changed(vec
![])
360 ProcessResult
::Error(CodeSelectionError(Unimplemented
))
363 None
=> ProcessResult
::Unchanged
,
367 ty
::PredicateKind
::WellFormed(arg
) => {
368 match wf
::obligations(
370 obligation
.param_env
,
371 obligation
.cause
.body_id
,
372 obligation
.recursion_depth
+ 1,
374 obligation
.cause
.span
,
377 pending_obligation
.stalled_on
=
378 vec
![TyOrConstInferVar
::maybe_from_generic_arg(arg
).unwrap()];
379 ProcessResult
::Unchanged
381 Some(os
) => ProcessResult
::Changed(mk_pending(os
)),
385 ty
::PredicateKind
::Subtype(subtype
) => {
386 match self.selcx
.infcx
.subtype_predicate(
388 obligation
.param_env
,
389 Binder
::dummy(subtype
),
392 // None means that both are unresolved.
393 pending_obligation
.stalled_on
=
394 vec
![TyOrConstInferVar
::Ty(a
), TyOrConstInferVar
::Ty(b
)];
395 ProcessResult
::Unchanged
397 Ok(Ok(ok
)) => ProcessResult
::Changed(mk_pending(ok
.obligations
)),
400 ExpectedFound
::new(subtype
.a_is_expected
, subtype
.a
, subtype
.b
);
401 ProcessResult
::Error(FulfillmentErrorCode
::CodeSubtypeError(
409 ty
::PredicateKind
::Coerce(coerce
) => {
410 match self.selcx
.infcx
.coerce_predicate(
412 obligation
.param_env
,
413 Binder
::dummy(coerce
),
416 // None means that both are unresolved.
417 pending_obligation
.stalled_on
=
418 vec
![TyOrConstInferVar
::Ty(a
), TyOrConstInferVar
::Ty(b
)];
419 ProcessResult
::Unchanged
421 Ok(Ok(ok
)) => ProcessResult
::Changed(mk_pending(ok
.obligations
)),
423 let expected_found
= ExpectedFound
::new(false, coerce
.a
, coerce
.b
);
424 ProcessResult
::Error(FulfillmentErrorCode
::CodeSubtypeError(
432 ty
::PredicateKind
::ConstEvaluatable(uv
) => {
433 match const_evaluatable
::is_const_evaluatable(
436 obligation
.param_env
,
437 obligation
.cause
.span
,
439 Ok(()) => ProcessResult
::Changed(vec
![]),
440 Err(NotConstEvaluatable
::MentionsInfer
) => {
441 pending_obligation
.stalled_on
.clear();
442 pending_obligation
.stalled_on
.extend(
443 uv
.walk().filter_map(TyOrConstInferVar
::maybe_from_generic_arg
),
445 ProcessResult
::Unchanged
448 e @ NotConstEvaluatable
::MentionsParam
449 | e @ NotConstEvaluatable
::Error(_
),
450 ) => ProcessResult
::Error(CodeSelectionError(
451 SelectionError
::NotConstEvaluatable(e
),
456 ty
::PredicateKind
::ConstEquate(c1
, c2
) => {
457 let tcx
= self.selcx
.tcx();
459 tcx
.features().generic_const_exprs
,
460 "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
462 // FIXME: we probably should only try to unify abstract constants
463 // if the constants depend on generic parameters.
465 // Let's just see where this breaks :shrug:
467 let c1
= tcx
.expand_abstract_consts(c1
);
468 let c2
= tcx
.expand_abstract_consts(c2
);
469 debug
!("equating consts:\nc1= {:?}\nc2= {:?}", c1
, c2
);
471 use rustc_hir
::def
::DefKind
;
472 use ty
::ConstKind
::Unevaluated
;
473 match (c1
.kind(), c2
.kind()) {
474 (Unevaluated(a
), Unevaluated(b
))
475 if a
.def
.did
== b
.def
.did
476 && tcx
.def_kind(a
.def
.did
) == DefKind
::AssocConst
=>
478 if let Ok(new_obligations
) = infcx
479 .at(&obligation
.cause
, obligation
.param_env
)
481 .eq(a
.substs
, b
.substs
)
483 return ProcessResult
::Changed(mk_pending(
484 new_obligations
.into_obligations(),
488 (_
, Unevaluated(_
)) | (Unevaluated(_
), _
) => (),
490 if let Ok(new_obligations
) =
491 infcx
.at(&obligation
.cause
, obligation
.param_env
).eq(c1
, c2
)
493 return ProcessResult
::Changed(mk_pending(
494 new_obligations
.into_obligations(),
501 let stalled_on
= &mut pending_obligation
.stalled_on
;
503 let mut evaluate
= |c
: Const
<'tcx
>| {
504 if let ty
::ConstKind
::Unevaluated(unevaluated
) = c
.kind() {
505 match self.selcx
.infcx
.try_const_eval_resolve(
506 obligation
.param_env
,
509 Some(obligation
.cause
.span
),
513 ErrorHandled
::TooGeneric
=> {
515 unevaluated
.substs
.iter().filter_map(
516 TyOrConstInferVar
::maybe_from_generic_arg
,
519 Err(ErrorHandled
::TooGeneric
)
529 match (evaluate(c1
), evaluate(c2
)) {
530 (Ok(c1
), Ok(c2
)) => {
534 .at(&obligation
.cause
, obligation
.param_env
)
538 ProcessResult
::Changed(mk_pending(inf_ok
.into_obligations()))
540 Err(err
) => ProcessResult
::Error(
541 FulfillmentErrorCode
::CodeConstEquateError(
542 ExpectedFound
::new(true, c1
, c2
),
548 (Err(ErrorHandled
::Reported(reported
)), _
)
549 | (_
, Err(ErrorHandled
::Reported(reported
))) => ProcessResult
::Error(
550 CodeSelectionError(SelectionError
::NotConstEvaluatable(
551 NotConstEvaluatable
::Error(reported
),
554 (Err(ErrorHandled
::TooGeneric
), _
) | (_
, Err(ErrorHandled
::TooGeneric
)) => {
555 if c1
.has_non_region_infer() || c2
.has_non_region_infer() {
556 ProcessResult
::Unchanged
558 // Two different constants using generic parameters ~> error.
559 let expected_found
= ExpectedFound
::new(true, c1
, c2
);
560 ProcessResult
::Error(FulfillmentErrorCode
::CodeConstEquateError(
562 TypeError
::ConstMismatch(expected_found
),
568 ty
::PredicateKind
::Ambiguous
=> ProcessResult
::Unchanged
,
569 ty
::PredicateKind
::TypeWellFormedFromEnv(..) => {
570 bug
!("TypeWellFormedFromEnv is only used for Chalk")
577 fn process_backedge
<'c
, I
>(
580 _marker
: PhantomData
<&'c PendingPredicateObligation
<'tcx
>>,
581 ) -> Result
<(), FulfillmentErrorCode
<'tcx
>>
583 I
: Clone
+ Iterator
<Item
= &'c PendingPredicateObligation
<'tcx
>>,
585 if self.selcx
.coinductive_match(cycle
.clone().map(|s
| s
.obligation
.predicate
)) {
586 debug
!("process_child_obligations: coinductive match");
589 let cycle
: Vec
<_
> = cycle
.map(|c
| c
.obligation
.clone()).collect();
590 Err(FulfillmentErrorCode
::CodeCycle(cycle
))
595 impl<'a
, 'tcx
> FulfillProcessor
<'a
, 'tcx
> {
596 #[instrument(level = "debug", skip(self, obligation, stalled_on))]
597 fn process_trait_obligation(
599 obligation
: &PredicateObligation
<'tcx
>,
600 trait_obligation
: TraitObligation
<'tcx
>,
601 stalled_on
: &mut Vec
<TyOrConstInferVar
<'tcx
>>,
602 ) -> ProcessResult
<PendingPredicateObligation
<'tcx
>, FulfillmentErrorCode
<'tcx
>> {
603 let infcx
= self.selcx
.infcx
;
604 if obligation
.predicate
.is_global() {
605 // no type variables present, can use evaluation for better caching.
606 // FIXME: consider caching errors too.
607 if infcx
.predicate_must_hold_considering_regions(obligation
) {
609 "selecting trait at depth {} evaluated to holds",
610 obligation
.recursion_depth
612 return ProcessResult
::Changed(vec
![]);
616 match self.selcx
.select(&trait_obligation
) {
617 Ok(Some(impl_source
)) => {
618 debug
!("selecting trait at depth {} yielded Ok(Some)", obligation
.recursion_depth
);
619 ProcessResult
::Changed(mk_pending(impl_source
.nested_obligations()))
622 debug
!("selecting trait at depth {} yielded Ok(None)", obligation
.recursion_depth
);
624 // This is a bit subtle: for the most part, the
625 // only reason we can fail to make progress on
626 // trait selection is because we don't have enough
627 // information about the types in the trait.
629 stalled_on
.extend(substs_infer_vars(
631 trait_obligation
.predicate
.map_bound(|pred
| pred
.trait_ref
.substs
),
635 "process_predicate: pending obligation {:?} now stalled on {:?}",
636 infcx
.resolve_vars_if_possible(obligation
.clone()),
640 ProcessResult
::Unchanged
642 Err(selection_err
) => {
643 debug
!("selecting trait at depth {} yielded Err", obligation
.recursion_depth
);
645 ProcessResult
::Error(CodeSelectionError(selection_err
))
650 fn process_projection_obligation(
652 obligation
: &PredicateObligation
<'tcx
>,
653 project_obligation
: PolyProjectionObligation
<'tcx
>,
654 stalled_on
: &mut Vec
<TyOrConstInferVar
<'tcx
>>,
655 ) -> ProcessResult
<PendingPredicateObligation
<'tcx
>, FulfillmentErrorCode
<'tcx
>> {
656 let tcx
= self.selcx
.tcx();
658 if obligation
.predicate
.is_global() {
659 // no type variables present, can use evaluation for better caching.
660 // FIXME: consider caching errors too.
661 if self.selcx
.infcx
.predicate_must_hold_considering_regions(obligation
) {
662 if let Some(key
) = ProjectionCacheKey
::from_poly_projection_predicate(
664 project_obligation
.predicate
,
666 // If `predicate_must_hold_considering_regions` succeeds, then we've
667 // evaluated all sub-obligations. We can therefore mark the 'root'
668 // obligation as complete, and skip evaluating sub-obligations.
674 .complete(key
, EvaluationResult
::EvaluatedToOk
);
676 return ProcessResult
::Changed(vec
![]);
678 debug
!("Does NOT hold: {:?}", obligation
);
682 match project
::poly_project_and_unify_type(&mut self.selcx
, &project_obligation
) {
683 ProjectAndUnifyResult
::Holds(os
) => ProcessResult
::Changed(mk_pending(os
)),
684 ProjectAndUnifyResult
::FailedNormalization
=> {
686 stalled_on
.extend(substs_infer_vars(
688 project_obligation
.predicate
.map_bound(|pred
| pred
.projection_ty
.substs
),
690 ProcessResult
::Unchanged
692 // Let the caller handle the recursion
693 ProjectAndUnifyResult
::Recursive
=> ProcessResult
::Changed(mk_pending(vec
![
694 project_obligation
.with(tcx
, project_obligation
.predicate
),
696 ProjectAndUnifyResult
::MismatchedProjectionTypes(e
) => {
697 ProcessResult
::Error(CodeProjectionError(e
))
703 /// Returns the set of inference variables contained in `substs`.
704 fn substs_infer_vars
<'a
, 'tcx
>(
705 selcx
: &SelectionContext
<'a
, 'tcx
>,
706 substs
: ty
::Binder
<'tcx
, SubstsRef
<'tcx
>>,
707 ) -> impl Iterator
<Item
= TyOrConstInferVar
<'tcx
>> {
710 .resolve_vars_if_possible(substs
)
711 .skip_binder() // ok because this check doesn't care about regions
713 .filter(|arg
| arg
.has_non_region_infer())
715 let mut walker
= arg
.walk();
716 while let Some(c
) = walker
.next() {
717 if !c
.has_non_region_infer() {
718 walker
.visited
.remove(&c
);
719 walker
.skip_current_subtree();
722 walker
.visited
.into_iter()
724 .filter_map(TyOrConstInferVar
::maybe_from_generic_arg
)
727 fn to_fulfillment_error
<'tcx
>(
728 error
: Error
<PendingPredicateObligation
<'tcx
>, FulfillmentErrorCode
<'tcx
>>,
729 ) -> FulfillmentError
<'tcx
> {
730 let mut iter
= error
.backtrace
.into_iter();
731 let obligation
= iter
.next().unwrap().obligation
;
732 // The root obligation is the last item in the backtrace - if there's only
733 // one item, then it's the same as the main obligation
734 let root_obligation
= iter
.next_back().map_or_else(|| obligation
.clone(), |e
| e
.obligation
);
735 FulfillmentError
::new(obligation
, error
.error
, root_obligation
)