1 //! Defines a Chalk-based `TraitEngine`
3 use crate::infer
::canonical
::OriginalQueryValues
;
4 use crate::infer
::InferCtxt
;
5 use crate::traits
::query
::NoSolution
;
7 ChalkEnvironmentAndGoal
, FulfillmentError
, FulfillmentErrorCode
, ObligationCause
,
8 PredicateObligation
, SelectionError
, TraitEngine
,
10 use rustc_data_structures
::fx
::FxIndexSet
;
11 use rustc_middle
::ty
::{self, Ty}
;
13 pub struct FulfillmentContext
<'tcx
> {
14 obligations
: FxIndexSet
<PredicateObligation
<'tcx
>>,
17 impl FulfillmentContext
<'tcx
> {
18 crate fn new() -> Self {
19 FulfillmentContext { obligations: FxIndexSet::default() }
23 impl TraitEngine
<'tcx
> for FulfillmentContext
<'tcx
> {
24 fn normalize_projection_type(
26 infcx
: &InferCtxt
<'_
, 'tcx
>,
27 _param_env
: ty
::ParamEnv
<'tcx
>,
28 projection_ty
: ty
::ProjectionTy
<'tcx
>,
29 _cause
: ObligationCause
<'tcx
>,
31 infcx
.tcx
.mk_ty(ty
::Projection(projection_ty
))
34 fn register_predicate_obligation(
36 infcx
: &InferCtxt
<'_
, 'tcx
>,
37 obligation
: PredicateObligation
<'tcx
>,
39 assert
!(!infcx
.is_in_snapshot());
40 let obligation
= infcx
.resolve_vars_if_possible(&obligation
);
42 self.obligations
.insert(obligation
);
45 fn select_all_or_error(
47 infcx
: &InferCtxt
<'_
, 'tcx
>,
48 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
49 self.select_where_possible(infcx
)?
;
51 if self.obligations
.is_empty() {
57 .map(|obligation
| FulfillmentError
{
58 obligation
: obligation
.clone(),
59 code
: FulfillmentErrorCode
::CodeAmbiguity
,
60 points_at_arg_span
: false,
67 fn select_where_possible(
69 infcx
: &InferCtxt
<'_
, 'tcx
>,
70 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
71 assert
!(!infcx
.is_in_snapshot());
73 let mut errors
= Vec
::new();
74 let mut next_round
= FxIndexSet
::default();
75 let mut making_progress
;
78 making_progress
= false;
80 // We iterate over all obligations, and record if we are able
81 // to unambiguously prove at least one obligation.
82 for obligation
in self.obligations
.drain(..) {
83 let obligation
= infcx
.resolve_vars_if_possible(&obligation
);
84 let environment
= obligation
.param_env
.caller_bounds();
85 let goal
= ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }
;
86 let mut orig_values
= OriginalQueryValues
::default();
87 let canonical_goal
= infcx
.canonicalize_query(&goal
, &mut orig_values
);
89 match infcx
.tcx
.evaluate_goal(canonical_goal
) {
91 if response
.is_proven() {
92 making_progress
= true;
94 match infcx
.instantiate_query_response_and_region_obligations(
100 Ok(infer_ok
) => next_round
.extend(
101 infer_ok
.obligations
.into_iter().map(|obligation
| {
102 assert
!(!infcx
.is_in_snapshot());
103 infcx
.resolve_vars_if_possible(&obligation
)
107 Err(_err
) => errors
.push(FulfillmentError
{
109 code
: FulfillmentErrorCode
::CodeSelectionError(
110 SelectionError
::Unimplemented
,
112 points_at_arg_span
: false,
116 // Ambiguous: retry at next round.
117 next_round
.insert(obligation
);
121 Err(NoSolution
) => errors
.push(FulfillmentError
{
123 code
: FulfillmentErrorCode
::CodeSelectionError(
124 SelectionError
::Unimplemented
,
126 points_at_arg_span
: false,
130 next_round
= std
::mem
::replace(&mut self.obligations
, next_round
);
132 if !making_progress
{
137 if errors
.is_empty() { Ok(()) }
else { Err(errors) }
140 fn pending_obligations(&self) -> Vec
<PredicateObligation
<'tcx
>> {
141 self.obligations
.iter().cloned().collect()