1 use crate::infer
::{InferCtxt, TyOrConstInferVar}
;
2 use rustc_data_structures
::obligation_forest
::ProcessResult
;
3 use rustc_data_structures
::obligation_forest
::{Error, ForestObligation, Outcome}
;
4 use rustc_data_structures
::obligation_forest
::{ObligationForest, ObligationProcessor}
;
5 use rustc_errors
::ErrorReported
;
6 use rustc_infer
::traits
::{TraitEngine, TraitEngineExt as _, TraitObligation}
;
7 use rustc_middle
::mir
::interpret
::ErrorHandled
;
8 use rustc_middle
::ty
::error
::ExpectedFound
;
9 use rustc_middle
::ty
::subst
::SubstsRef
;
10 use rustc_middle
::ty
::ToPredicate
;
11 use rustc_middle
::ty
::{self, Binder, Const, Ty, TypeFoldable}
;
12 use std
::marker
::PhantomData
;
14 use super::const_evaluatable
;
16 use super::select
::SelectionContext
;
18 use super::CodeAmbiguity
;
19 use super::CodeProjectionError
;
20 use super::CodeSelectionError
;
21 use super::{ConstEvalFailure, Unimplemented}
;
22 use super::{FulfillmentError, FulfillmentErrorCode}
;
23 use super::{ObligationCause, PredicateObligation}
;
25 use crate::traits
::error_reporting
::InferCtxtExt
as _
;
26 use crate::traits
::project
::PolyProjectionObligation
;
27 use crate::traits
::query
::evaluate_obligation
::InferCtxtExt
as _
;
29 impl<'tcx
> ForestObligation
for PendingPredicateObligation
<'tcx
> {
30 /// Note that we include both the `ParamEnv` and the `Predicate`,
31 /// as the `ParamEnv` can influence whether fulfillment succeeds
33 type CacheKey
= ty
::ParamEnvAnd
<'tcx
, ty
::Predicate
<'tcx
>>;
35 fn as_cache_key(&self) -> Self::CacheKey
{
36 self.obligation
.param_env
.and(self.obligation
.predicate
)
40 /// The fulfillment context is used to drive trait resolution. It
41 /// consists of a list of obligations that must be (eventually)
42 /// satisfied. The job is to track which are satisfied, which yielded
43 /// errors, and which are still pending. At any point, users can call
44 /// `select_where_possible`, and the fulfillment context will try to do
45 /// selection, retaining only those obligations that remain
46 /// ambiguous. This may be helpful in pushing type inference
47 /// along. Once all type inference constraints have been generated, the
48 /// method `select_all_or_error` can be used to report any remaining
49 /// ambiguous cases as errors.
50 pub struct FulfillmentContext
<'tcx
> {
51 // A list of all obligations that have been registered with this
52 // fulfillment context.
53 predicates
: ObligationForest
<PendingPredicateObligation
<'tcx
>>,
54 // Should this fulfillment context register type-lives-for-region
55 // obligations on its parent infcx? In some cases, region
56 // obligations are either already known to hold (normalization) or
57 // hopefully verifed elsewhere (type-impls-bound), and therefore
58 // should not be checked.
60 // Note that if we are normalizing a type that we already
61 // know is well-formed, there should be no harm setting this
62 // to true - all the region variables should be determinable
63 // using the RFC 447 rules, which don't depend on
64 // type-lives-for-region constraints, and because the type
65 // is well-formed, the constraints should hold.
66 register_region_obligations
: bool
,
67 // Is it OK to register obligations into this infcx inside
70 // The "primary fulfillment" in many cases in typeck lives
71 // outside of any snapshot, so any use of it inside a snapshot
72 // will lead to trouble and therefore is checked against, but
73 // other fulfillment contexts sometimes do live inside of
74 // a snapshot (they don't *straddle* a snapshot, so there
75 // is no trouble there).
76 usable_in_snapshot
: bool
,
79 #[derive(Clone, Debug)]
80 pub struct PendingPredicateObligation
<'tcx
> {
81 pub obligation
: PredicateObligation
<'tcx
>,
82 // This is far more often read than modified, meaning that we
83 // should mostly optimize for reading speed, while modifying is not as relevant.
85 // For whatever reason using a boxed slice is slower than using a `Vec` here.
86 pub stalled_on
: Vec
<TyOrConstInferVar
<'tcx
>>,
89 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
90 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
91 static_assert_size
!(PendingPredicateObligation
<'_
>, 56);
93 impl<'a
, 'tcx
> FulfillmentContext
<'tcx
> {
94 /// Creates a new fulfillment context.
95 pub fn new() -> FulfillmentContext
<'tcx
> {
97 predicates
: ObligationForest
::new(),
98 register_region_obligations
: true,
99 usable_in_snapshot
: false,
103 pub fn new_in_snapshot() -> FulfillmentContext
<'tcx
> {
105 predicates
: ObligationForest
::new(),
106 register_region_obligations
: true,
107 usable_in_snapshot
: true,
111 pub fn new_ignoring_regions() -> FulfillmentContext
<'tcx
> {
113 predicates
: ObligationForest
::new(),
114 register_region_obligations
: false,
115 usable_in_snapshot
: false,
119 /// Attempts to select obligations using `selcx`.
122 selcx
: &mut SelectionContext
<'a
, 'tcx
>,
123 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
124 let span
= debug_span
!("select", obligation_forest_size
= ?
self.predicates
.len());
125 let _enter
= span
.enter();
127 let mut errors
= Vec
::new();
130 debug
!("select: starting another iteration");
132 // Process pending obligations.
133 let outcome
: Outcome
<_
, _
> =
134 self.predicates
.process_obligations(&mut FulfillProcessor
{
136 register_region_obligations
: self.register_region_obligations
,
138 debug
!("select: outcome={:#?}", outcome
);
140 // FIXME: if we kept the original cache key, we could mark projection
141 // obligations as complete for the projection cache here.
143 errors
.extend(outcome
.errors
.into_iter().map(to_fulfillment_error
));
145 // If nothing new was added, no need to keep looping.
152 "select({} predicates remaining, {} errors) done",
153 self.predicates
.len(),
157 if errors
.is_empty() { Ok(()) }
else { Err(errors) }
161 impl<'tcx
> TraitEngine
<'tcx
> for FulfillmentContext
<'tcx
> {
162 /// "Normalize" a projection type `<SomeType as SomeTrait>::X` by
163 /// creating a fresh type variable `$0` as well as a projection
164 /// predicate `<SomeType as SomeTrait>::X == $0`. When the
165 /// inference engine runs, it will attempt to find an impl of
166 /// `SomeTrait` or a where-clause that lets us unify `$0` with
167 /// something concrete. If this fails, we'll unify `$0` with
168 /// `projection_ty` again.
169 fn normalize_projection_type(
171 infcx
: &InferCtxt
<'_
, 'tcx
>,
172 param_env
: ty
::ParamEnv
<'tcx
>,
173 projection_ty
: ty
::ProjectionTy
<'tcx
>,
174 cause
: ObligationCause
<'tcx
>,
176 debug
!(?projection_ty
, "normalize_projection_type");
178 debug_assert
!(!projection_ty
.has_escaping_bound_vars());
180 // FIXME(#20304) -- cache
182 let mut selcx
= SelectionContext
::new(infcx
);
183 let mut obligations
= vec
![];
184 let normalized_ty
= project
::normalize_projection_type(
192 self.register_predicate_obligations(infcx
, obligations
);
194 debug
!(?normalized_ty
);
199 fn register_predicate_obligation(
201 infcx
: &InferCtxt
<'_
, 'tcx
>,
202 obligation
: PredicateObligation
<'tcx
>,
204 // this helps to reduce duplicate errors, as well as making
205 // debug output much nicer to read and so on.
206 let obligation
= infcx
.resolve_vars_if_possible(obligation
);
208 debug
!(?obligation
, "register_predicate_obligation");
210 assert
!(!infcx
.is_in_snapshot() || self.usable_in_snapshot
);
213 .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }
);
216 fn select_all_or_error(
218 infcx
: &InferCtxt
<'_
, 'tcx
>,
219 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
220 self.select_where_possible(infcx
)?
;
222 let errors
: Vec
<_
> = self
224 .to_errors(CodeAmbiguity
)
226 .map(to_fulfillment_error
)
228 if errors
.is_empty() { Ok(()) }
else { Err(errors) }
231 fn select_where_possible(
233 infcx
: &InferCtxt
<'_
, 'tcx
>,
234 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
235 let mut selcx
= SelectionContext
::new(infcx
);
236 self.select(&mut selcx
)
239 fn pending_obligations(&self) -> Vec
<PredicateObligation
<'tcx
>> {
240 self.predicates
.map_pending_obligations(|o
| o
.obligation
.clone())
244 struct FulfillProcessor
<'a
, 'b
, 'tcx
> {
245 selcx
: &'a
mut SelectionContext
<'b
, 'tcx
>,
246 register_region_obligations
: bool
,
249 fn mk_pending(os
: Vec
<PredicateObligation
<'tcx
>>) -> Vec
<PendingPredicateObligation
<'tcx
>> {
251 .map(|o
| PendingPredicateObligation { obligation: o, stalled_on: vec![] }
)
255 impl<'a
, 'b
, 'tcx
> ObligationProcessor
for FulfillProcessor
<'a
, 'b
, 'tcx
> {
256 type Obligation
= PendingPredicateObligation
<'tcx
>;
257 type Error
= FulfillmentErrorCode
<'tcx
>;
259 /// Processes a predicate obligation and returns either:
260 /// - `Changed(v)` if the predicate is true, presuming that `v` are also true
261 /// - `Unchanged` if we don't have enough info to be sure
262 /// - `Error(e)` if the predicate does not hold
264 /// This is always inlined, despite its size, because it has a single
265 /// callsite and it is called *very* frequently.
267 fn process_obligation(
269 pending_obligation
: &mut Self::Obligation
,
270 ) -> ProcessResult
<Self::Obligation
, Self::Error
> {
271 // If we were stalled on some unresolved variables, first check whether
272 // any of them have been resolved; if not, don't bother doing more work
274 let change
= match pending_obligation
.stalled_on
.len() {
275 // Match arms are in order of frequency, which matters because this
276 // code is so hot. 1 and 0 dominate; 2+ is fairly rare.
278 let infer_var
= pending_obligation
.stalled_on
[0];
279 self.selcx
.infcx().ty_or_const_infer_var_changed(infer_var
)
282 // In this case we haven't changed, but wish to make a change.
286 // This `for` loop was once a call to `all()`, but this lower-level
287 // form was a perf win. See #64545 for details.
289 for &infer_var
in &pending_obligation
.stalled_on
{
290 if self.selcx
.infcx().ty_or_const_infer_var_changed(infer_var
) {
301 "process_predicate: pending obligation {:?} still stalled on {:?}",
302 self.selcx
.infcx().resolve_vars_if_possible(pending_obligation
.obligation
.clone()),
303 pending_obligation
.stalled_on
305 return ProcessResult
::Unchanged
;
308 self.progress_changed_obligations(pending_obligation
)
311 fn process_backedge
<'c
, I
>(
314 _marker
: PhantomData
<&'c PendingPredicateObligation
<'tcx
>>,
316 I
: Clone
+ Iterator
<Item
= &'c PendingPredicateObligation
<'tcx
>>,
318 if self.selcx
.coinductive_match(cycle
.clone().map(|s
| s
.obligation
.predicate
)) {
319 debug
!("process_child_obligations: coinductive match");
321 let cycle
: Vec
<_
> = cycle
.map(|c
| c
.obligation
.clone()).collect();
322 self.selcx
.infcx().report_overflow_error_cycle(&cycle
);
327 impl<'a
, 'b
, 'tcx
> FulfillProcessor
<'a
, 'b
, 'tcx
> {
328 // The code calling this method is extremely hot and only rarely
329 // actually uses this, so move this part of the code
332 fn progress_changed_obligations(
334 pending_obligation
: &mut PendingPredicateObligation
<'tcx
>,
335 ) -> ProcessResult
<PendingPredicateObligation
<'tcx
>, FulfillmentErrorCode
<'tcx
>> {
336 pending_obligation
.stalled_on
.truncate(0);
338 let obligation
= &mut pending_obligation
.obligation
;
340 if obligation
.predicate
.has_infer_types_or_consts() {
341 obligation
.predicate
=
342 self.selcx
.infcx().resolve_vars_if_possible(obligation
.predicate
);
345 debug
!(?obligation
, ?obligation
.cause
, "process_obligation");
347 let infcx
= self.selcx
.infcx();
349 let binder
= obligation
.predicate
.kind();
350 match binder
.no_bound_vars() {
351 None
=> match binder
.skip_binder() {
352 // Evaluation will discard candidates using the leak check.
353 // This means we need to pass it the bound version of our
355 ty
::PredicateKind
::Trait(trait_ref
, _constness
) => {
356 let trait_obligation
= obligation
.with(binder
.rebind(trait_ref
));
358 self.process_trait_obligation(
361 &mut pending_obligation
.stalled_on
,
364 ty
::PredicateKind
::Projection(data
) => {
365 let project_obligation
= obligation
.with(binder
.rebind(data
));
367 self.process_projection_obligation(
369 &mut pending_obligation
.stalled_on
,
372 ty
::PredicateKind
::RegionOutlives(_
)
373 | ty
::PredicateKind
::TypeOutlives(_
)
374 | ty
::PredicateKind
::WellFormed(_
)
375 | ty
::PredicateKind
::ObjectSafe(_
)
376 | ty
::PredicateKind
::ClosureKind(..)
377 | ty
::PredicateKind
::Subtype(_
)
378 | ty
::PredicateKind
::ConstEvaluatable(..)
379 | ty
::PredicateKind
::ConstEquate(..) => {
380 let pred
= infcx
.replace_bound_vars_with_placeholders(binder
);
381 ProcessResult
::Changed(mk_pending(vec
![
382 obligation
.with(pred
.to_predicate(self.selcx
.tcx())),
385 ty
::PredicateKind
::TypeWellFormedFromEnv(..) => {
386 bug
!("TypeWellFormedFromEnv is only used for Chalk")
389 Some(pred
) => match pred
{
390 ty
::PredicateKind
::Trait(data
, _
) => {
391 let trait_obligation
= obligation
.with(Binder
::dummy(data
));
393 self.process_trait_obligation(
396 &mut pending_obligation
.stalled_on
,
400 ty
::PredicateKind
::RegionOutlives(data
) => {
401 match infcx
.region_outlives_predicate(&obligation
.cause
, Binder
::dummy(data
)) {
402 Ok(()) => ProcessResult
::Changed(vec
![]),
403 Err(_
) => ProcessResult
::Error(CodeSelectionError(Unimplemented
)),
407 ty
::PredicateKind
::TypeOutlives(ty
::OutlivesPredicate(t_a
, r_b
)) => {
408 if self.register_region_obligations
{
409 self.selcx
.infcx().register_region_obligation_with_cause(
415 ProcessResult
::Changed(vec
![])
418 ty
::PredicateKind
::Projection(ref data
) => {
419 let project_obligation
= obligation
.with(Binder
::dummy(*data
));
421 self.process_projection_obligation(
423 &mut pending_obligation
.stalled_on
,
427 ty
::PredicateKind
::ObjectSafe(trait_def_id
) => {
428 if !self.selcx
.tcx().is_object_safe(trait_def_id
) {
429 ProcessResult
::Error(CodeSelectionError(Unimplemented
))
431 ProcessResult
::Changed(vec
![])
435 ty
::PredicateKind
::ClosureKind(_
, closure_substs
, kind
) => {
436 match self.selcx
.infcx().closure_kind(closure_substs
) {
437 Some(closure_kind
) => {
438 if closure_kind
.extends(kind
) {
439 ProcessResult
::Changed(vec
![])
441 ProcessResult
::Error(CodeSelectionError(Unimplemented
))
444 None
=> ProcessResult
::Unchanged
,
448 ty
::PredicateKind
::WellFormed(arg
) => {
449 match wf
::obligations(
451 obligation
.param_env
,
452 obligation
.cause
.body_id
,
453 obligation
.recursion_depth
+ 1,
455 obligation
.cause
.span
,
458 pending_obligation
.stalled_on
=
459 vec
![TyOrConstInferVar
::maybe_from_generic_arg(arg
).unwrap()];
460 ProcessResult
::Unchanged
462 Some(os
) => ProcessResult
::Changed(mk_pending(os
)),
466 ty
::PredicateKind
::Subtype(subtype
) => {
467 match self.selcx
.infcx().subtype_predicate(
469 obligation
.param_env
,
470 Binder
::dummy(subtype
),
473 // None means that both are unresolved.
474 pending_obligation
.stalled_on
= vec
![
475 TyOrConstInferVar
::maybe_from_ty(subtype
.a
).unwrap(),
476 TyOrConstInferVar
::maybe_from_ty(subtype
.b
).unwrap(),
478 ProcessResult
::Unchanged
480 Some(Ok(ok
)) => ProcessResult
::Changed(mk_pending(ok
.obligations
)),
483 ExpectedFound
::new(subtype
.a_is_expected
, subtype
.a
, subtype
.b
);
484 ProcessResult
::Error(FulfillmentErrorCode
::CodeSubtypeError(
492 ty
::PredicateKind
::ConstEvaluatable(def_id
, substs
) => {
493 match const_evaluatable
::is_const_evaluatable(
497 obligation
.param_env
,
498 obligation
.cause
.span
,
500 Ok(()) => ProcessResult
::Changed(vec
![]),
501 Err(ErrorHandled
::TooGeneric
) => {
502 pending_obligation
.stalled_on
.clear();
503 pending_obligation
.stalled_on
.extend(
504 substs
.iter().filter_map(TyOrConstInferVar
::maybe_from_generic_arg
),
506 ProcessResult
::Unchanged
508 Err(e
) => ProcessResult
::Error(CodeSelectionError(ConstEvalFailure(e
))),
512 ty
::PredicateKind
::ConstEquate(c1
, c2
) => {
513 debug
!(?c1
, ?c2
, "equating consts");
514 if self.selcx
.tcx().features().const_evaluatable_checked
{
515 // FIXME: we probably should only try to unify abstract constants
516 // if the constants depend on generic parameters.
518 // Let's just see where this breaks :shrug:
520 ty
::ConstKind
::Unevaluated(a_def
, a_substs
, None
),
521 ty
::ConstKind
::Unevaluated(b_def
, b_substs
, None
),
527 .try_unify_abstract_consts(((a_def
, a_substs
), (b_def
, b_substs
)))
529 return ProcessResult
::Changed(vec
![]);
534 let stalled_on
= &mut pending_obligation
.stalled_on
;
536 let mut evaluate
= |c
: &'tcx Const
<'tcx
>| {
537 if let ty
::ConstKind
::Unevaluated(def
, substs
, promoted
) = c
.val
{
538 match self.selcx
.infcx().const_eval_resolve(
539 obligation
.param_env
,
543 Some(obligation
.cause
.span
),
545 Ok(val
) => Ok(Const
::from_value(self.selcx
.tcx(), val
, c
.ty
)),
546 Err(ErrorHandled
::TooGeneric
) => {
550 .filter_map(TyOrConstInferVar
::maybe_from_generic_arg
),
552 Err(ErrorHandled
::TooGeneric
)
554 Err(err
) => Err(err
),
561 match (evaluate(c1
), evaluate(c2
)) {
562 (Ok(c1
), Ok(c2
)) => {
566 .at(&obligation
.cause
, obligation
.param_env
)
569 Ok(_
) => ProcessResult
::Changed(vec
![]),
570 Err(err
) => ProcessResult
::Error(
571 FulfillmentErrorCode
::CodeConstEquateError(
572 ExpectedFound
::new(true, c1
, c2
),
578 (Err(ErrorHandled
::Reported(ErrorReported
)), _
)
579 | (_
, Err(ErrorHandled
::Reported(ErrorReported
))) => {
580 ProcessResult
::Error(CodeSelectionError(ConstEvalFailure(
581 ErrorHandled
::Reported(ErrorReported
),
584 (Err(ErrorHandled
::Linted
), _
) | (_
, Err(ErrorHandled
::Linted
)) => {
586 obligation
.cause
.span(self.selcx
.tcx()),
587 "ConstEquate: const_eval_resolve returned an unexpected error"
590 (Err(ErrorHandled
::TooGeneric
), _
) | (_
, Err(ErrorHandled
::TooGeneric
)) => {
591 ProcessResult
::Unchanged
595 ty
::PredicateKind
::TypeWellFormedFromEnv(..) => {
596 bug
!("TypeWellFormedFromEnv is only used for Chalk")
602 #[instrument(level = "debug", skip(self, obligation, stalled_on))]
603 fn process_trait_obligation(
605 obligation
: &PredicateObligation
<'tcx
>,
606 trait_obligation
: TraitObligation
<'tcx
>,
607 stalled_on
: &mut Vec
<TyOrConstInferVar
<'tcx
>>,
608 ) -> ProcessResult
<PendingPredicateObligation
<'tcx
>, FulfillmentErrorCode
<'tcx
>> {
609 let infcx
= self.selcx
.infcx();
610 if obligation
.predicate
.is_global() {
611 // no type variables present, can use evaluation for better caching.
612 // FIXME: consider caching errors too.
613 if infcx
.predicate_must_hold_considering_regions(obligation
) {
615 "selecting trait at depth {} evaluated to holds",
616 obligation
.recursion_depth
618 return ProcessResult
::Changed(vec
![]);
622 match self.selcx
.select(&trait_obligation
) {
623 Ok(Some(impl_source
)) => {
624 debug
!("selecting trait at depth {} yielded Ok(Some)", obligation
.recursion_depth
);
625 ProcessResult
::Changed(mk_pending(impl_source
.nested_obligations()))
628 debug
!("selecting trait at depth {} yielded Ok(None)", obligation
.recursion_depth
);
630 // This is a bit subtle: for the most part, the
631 // only reason we can fail to make progress on
632 // trait selection is because we don't have enough
633 // information about the types in the trait.
635 stalled_on
.extend(substs_infer_vars(
637 trait_obligation
.predicate
.map_bound(|pred
| pred
.trait_ref
.substs
),
641 "process_predicate: pending obligation {:?} now stalled on {:?}",
642 infcx
.resolve_vars_if_possible(obligation
.clone()),
646 ProcessResult
::Unchanged
648 Err(selection_err
) => {
649 debug
!("selecting trait at depth {} yielded Err", obligation
.recursion_depth
);
651 ProcessResult
::Error(CodeSelectionError(selection_err
))
656 fn process_projection_obligation(
658 project_obligation
: PolyProjectionObligation
<'tcx
>,
659 stalled_on
: &mut Vec
<TyOrConstInferVar
<'tcx
>>,
660 ) -> ProcessResult
<PendingPredicateObligation
<'tcx
>, FulfillmentErrorCode
<'tcx
>> {
661 let tcx
= self.selcx
.tcx();
662 match project
::poly_project_and_unify_type(self.selcx
, &project_obligation
) {
663 Ok(Ok(Some(os
))) => ProcessResult
::Changed(mk_pending(os
)),
666 stalled_on
.extend(substs_infer_vars(
668 project_obligation
.predicate
.map_bound(|pred
| pred
.projection_ty
.substs
),
670 ProcessResult
::Unchanged
672 // Let the caller handle the recursion
673 Ok(Err(project
::InProgress
)) => ProcessResult
::Changed(mk_pending(vec
![
674 project_obligation
.with(project_obligation
.predicate
.to_predicate(tcx
)),
676 Err(e
) => ProcessResult
::Error(CodeProjectionError(e
)),
681 /// Returns the set of inference variables contained in `substs`.
682 fn substs_infer_vars
<'a
, 'tcx
>(
683 selcx
: &mut SelectionContext
<'a
, 'tcx
>,
684 substs
: ty
::Binder
<SubstsRef
<'tcx
>>,
685 ) -> impl Iterator
<Item
= TyOrConstInferVar
<'tcx
>> {
688 .resolve_vars_if_possible(substs
)
689 .skip_binder() // ok because this check doesn't care about regions
691 .filter(|arg
| arg
.has_infer_types_or_consts())
693 let mut walker
= arg
.walk();
694 while let Some(c
) = walker
.next() {
695 if !c
.has_infer_types_or_consts() {
696 walker
.visited
.remove(&c
);
697 walker
.skip_current_subtree();
700 walker
.visited
.into_iter()
702 .filter_map(TyOrConstInferVar
::maybe_from_generic_arg
)
705 fn to_fulfillment_error
<'tcx
>(
706 error
: Error
<PendingPredicateObligation
<'tcx
>, FulfillmentErrorCode
<'tcx
>>,
707 ) -> FulfillmentError
<'tcx
> {
708 let obligation
= error
.backtrace
.into_iter().next().unwrap().obligation
;
709 FulfillmentError
::new(obligation
, error
.error
)