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,
61 // FIXME - does Chalk have a notation of 'root obligation'?
62 // This is just for diagnostics, so it's okay if this is wrong
63 root_obligation
: obligation
.clone(),
70 fn select_where_possible(
72 infcx
: &InferCtxt
<'_
, 'tcx
>,
73 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
74 assert
!(!infcx
.is_in_snapshot());
76 let mut errors
= Vec
::new();
77 let mut next_round
= FxIndexSet
::default();
78 let mut making_progress
;
81 making_progress
= false;
83 // We iterate over all obligations, and record if we are able
84 // to unambiguously prove at least one obligation.
85 for obligation
in self.obligations
.drain(..) {
86 let obligation
= infcx
.resolve_vars_if_possible(obligation
);
87 let environment
= obligation
.param_env
.caller_bounds();
88 let goal
= ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }
;
89 let mut orig_values
= OriginalQueryValues
::default();
90 let canonical_goal
= infcx
.canonicalize_query(goal
, &mut orig_values
);
92 match infcx
.tcx
.evaluate_goal(canonical_goal
) {
94 if response
.is_proven() {
95 making_progress
= true;
97 match infcx
.instantiate_query_response_and_region_obligations(
103 Ok(infer_ok
) => next_round
.extend(
104 infer_ok
.obligations
.into_iter().map(|obligation
| {
105 assert
!(!infcx
.is_in_snapshot());
106 infcx
.resolve_vars_if_possible(obligation
)
110 Err(_err
) => errors
.push(FulfillmentError
{
111 obligation
: obligation
.clone(),
112 code
: FulfillmentErrorCode
::CodeSelectionError(
113 SelectionError
::Unimplemented
,
115 points_at_arg_span
: false,
116 // FIXME - does Chalk have a notation of 'root obligation'?
117 // This is just for diagnostics, so it's okay if this is wrong
118 root_obligation
: obligation
,
122 // Ambiguous: retry at next round.
123 next_round
.insert(obligation
);
127 Err(NoSolution
) => errors
.push(FulfillmentError
{
128 obligation
: obligation
.clone(),
129 code
: FulfillmentErrorCode
::CodeSelectionError(
130 SelectionError
::Unimplemented
,
132 points_at_arg_span
: false,
133 // FIXME - does Chalk have a notation of 'root obligation'?
134 // This is just for diagnostics, so it's okay if this is wrong
135 root_obligation
: obligation
,
139 next_round
= std
::mem
::replace(&mut self.obligations
, next_round
);
141 if !making_progress
{
146 if errors
.is_empty() { Ok(()) }
else { Err(errors) }
149 fn pending_obligations(&self) -> Vec
<PredicateObligation
<'tcx
>> {
150 self.obligations
.iter().cloned().collect()