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
, PredicateObligation
,
8 SelectionError
, TraitEngine
,
10 use rustc_data_structures
::fx
::{FxHashMap, FxIndexSet}
;
11 use rustc_middle
::ty
::{self, TypeVisitable}
;
13 pub struct FulfillmentContext
<'tcx
> {
14 obligations
: FxIndexSet
<PredicateObligation
<'tcx
>>,
16 relationships
: FxHashMap
<ty
::TyVid
, ty
::FoundRelationships
>,
18 usable_in_snapshot
: bool
,
21 impl FulfillmentContext
<'_
> {
22 pub(super) fn new() -> Self {
24 obligations
: FxIndexSet
::default(),
25 relationships
: FxHashMap
::default(),
26 usable_in_snapshot
: false,
30 pub(crate) fn new_in_snapshot() -> Self {
31 FulfillmentContext { usable_in_snapshot: true, ..Self::new() }
35 impl<'tcx
> TraitEngine
<'tcx
> for FulfillmentContext
<'tcx
> {
36 fn register_predicate_obligation(
38 infcx
: &InferCtxt
<'tcx
>,
39 obligation
: PredicateObligation
<'tcx
>,
41 if !self.usable_in_snapshot
{
42 assert
!(!infcx
.is_in_snapshot());
44 let obligation
= infcx
.resolve_vars_if_possible(obligation
);
46 super::relationships
::update(self, infcx
, &obligation
);
48 self.obligations
.insert(obligation
);
51 fn select_all_or_error(&mut self, infcx
: &InferCtxt
<'tcx
>) -> Vec
<FulfillmentError
<'tcx
>> {
53 let errors
= self.select_where_possible(infcx
);
55 if !errors
.is_empty() {
60 // any remaining obligations are errors
63 .map(|obligation
| FulfillmentError
{
64 obligation
: obligation
.clone(),
65 code
: FulfillmentErrorCode
::CodeAmbiguity
,
66 // FIXME - does Chalk have a notation of 'root obligation'?
67 // This is just for diagnostics, so it's okay if this is wrong
68 root_obligation
: obligation
.clone(),
73 fn select_where_possible(&mut self, infcx
: &InferCtxt
<'tcx
>) -> Vec
<FulfillmentError
<'tcx
>> {
74 if !self.usable_in_snapshot
{
75 assert
!(!infcx
.is_in_snapshot());
78 let mut errors
= Vec
::new();
79 let mut next_round
= FxIndexSet
::default();
80 let mut making_progress
;
83 making_progress
= false;
85 // We iterate over all obligations, and record if we are able
86 // to unambiguously prove at least one obligation.
87 for obligation
in self.obligations
.drain(..) {
88 let obligation
= infcx
.resolve_vars_if_possible(obligation
);
89 let environment
= obligation
.param_env
.caller_bounds();
90 let goal
= ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }
;
91 let mut orig_values
= OriginalQueryValues
::default();
92 if goal
.references_error() {
97 infcx
.canonicalize_query_preserving_universes(goal
, &mut orig_values
);
99 match infcx
.tcx
.evaluate_goal(canonical_goal
) {
101 if response
.is_proven() {
102 making_progress
= true;
104 match infcx
.instantiate_query_response_and_region_obligations(
106 obligation
.param_env
,
110 Ok(infer_ok
) => next_round
.extend(
111 infer_ok
.obligations
.into_iter().map(|obligation
| {
112 assert
!(!infcx
.is_in_snapshot());
113 infcx
.resolve_vars_if_possible(obligation
)
117 Err(_err
) => errors
.push(FulfillmentError
{
118 obligation
: obligation
.clone(),
119 code
: FulfillmentErrorCode
::CodeSelectionError(
120 SelectionError
::Unimplemented
,
122 // FIXME - does Chalk have a notation of 'root obligation'?
123 // This is just for diagnostics, so it's okay if this is wrong
124 root_obligation
: obligation
,
128 // Ambiguous: retry at next round.
129 next_round
.insert(obligation
);
133 Err(NoSolution
) => errors
.push(FulfillmentError
{
134 obligation
: obligation
.clone(),
135 code
: FulfillmentErrorCode
::CodeSelectionError(
136 SelectionError
::Unimplemented
,
138 // FIXME - does Chalk have a notation of 'root obligation'?
139 // This is just for diagnostics, so it's okay if this is wrong
140 root_obligation
: obligation
,
144 next_round
= std
::mem
::replace(&mut self.obligations
, next_round
);
146 if !making_progress
{
154 fn pending_obligations(&self) -> Vec
<PredicateObligation
<'tcx
>> {
155 self.obligations
.iter().cloned().collect()
158 fn relationships(&mut self) -> &mut FxHashMap
<ty
::TyVid
, ty
::FoundRelationships
> {
159 &mut self.relationships