11 use crate::traits
::query
::NoSolution
;
12 use crate::infer
::InferCtxt
;
13 use crate::infer
::canonical
::{Canonical, OriginalQueryValues}
;
14 use crate::ty
::{self, Ty}
;
15 use rustc_data_structures
::fx
::FxHashSet
;
17 pub type CanonicalGoal
<'tcx
> = Canonical
<'tcx
, InEnvironment
<'tcx
, ty
::Predicate
<'tcx
>>>;
19 pub struct FulfillmentContext
<'tcx
> {
20 obligations
: FxHashSet
<InEnvironment
<'tcx
, PredicateObligation
<'tcx
>>>,
23 impl FulfillmentContext
<'tcx
> {
24 crate fn new() -> Self {
26 obligations
: FxHashSet
::default(),
32 infcx
: &InferCtxt
<'_
, 'gcx
, 'tcx
>,
33 obligation
: PredicateObligation
<'tcx
>
34 ) -> InEnvironment
<'tcx
, PredicateObligation
<'tcx
>> {
35 assert
!(!infcx
.is_in_snapshot());
36 let obligation
= infcx
.resolve_type_vars_if_possible(&obligation
);
38 let environment
= match obligation
.param_env
.def_id
{
39 Some(def_id
) => infcx
.tcx
.environment(def_id
),
40 None
if obligation
.param_env
.caller_bounds
.is_empty() => Environment
{
41 clauses
: ty
::List
::empty(),
43 _
=> bug
!("non-empty `ParamEnv` with no def-id"),
52 impl TraitEngine
<'tcx
> for FulfillmentContext
<'tcx
> {
53 fn normalize_projection_type(
55 infcx
: &InferCtxt
<'_
, 'gcx
, 'tcx
>,
56 _param_env
: ty
::ParamEnv
<'tcx
>,
57 projection_ty
: ty
::ProjectionTy
<'tcx
>,
58 _cause
: ObligationCause
<'tcx
>,
60 infcx
.tcx
.mk_ty(ty
::Projection(projection_ty
))
63 fn register_predicate_obligation(
65 infcx
: &InferCtxt
<'_
, 'gcx
, 'tcx
>,
66 obligation
: PredicateObligation
<'tcx
>,
68 self.obligations
.insert(in_environment(infcx
, obligation
));
71 fn select_all_or_error(
73 infcx
: &InferCtxt
<'_
, 'gcx
, 'tcx
>,
74 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
75 self.select_where_possible(infcx
)?
;
77 if self.obligations
.is_empty() {
80 let errors
= self.obligations
.iter()
81 .map(|obligation
| FulfillmentError
{
82 obligation
: obligation
.goal
.clone(),
83 code
: FulfillmentErrorCode
::CodeAmbiguity
,
90 fn select_where_possible(
92 infcx
: &InferCtxt
<'_
, 'gcx
, 'tcx
>,
93 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
94 let mut errors
= Vec
::new();
95 let mut next_round
= FxHashSet
::default();
96 let mut making_progress
;
99 making_progress
= false;
101 // We iterate over all obligations, and record if we are able
102 // to unambiguously prove at least one obligation.
103 for obligation
in self.obligations
.drain() {
104 let mut orig_values
= OriginalQueryValues
::default();
105 let canonical_goal
= infcx
.canonicalize_query(&InEnvironment
{
106 environment
: obligation
.environment
,
107 goal
: obligation
.goal
.predicate
,
108 }, &mut orig_values
);
110 match infcx
.tcx
.global_tcx().evaluate_goal(canonical_goal
) {
112 if response
.is_proven() {
113 making_progress
= true;
115 match infcx
.instantiate_query_response_and_region_obligations(
116 &obligation
.goal
.cause
,
117 obligation
.goal
.param_env
,
121 Ok(infer_ok
) => next_round
.extend(
124 .map(|obligation
| in_environment(infcx
, obligation
))
127 Err(_err
) => errors
.push(FulfillmentError
{
128 obligation
: obligation
.goal
,
129 code
: FulfillmentErrorCode
::CodeSelectionError(
130 SelectionError
::Unimplemented
135 // Ambiguous: retry at next round.
136 next_round
.insert(obligation
);
140 Err(NoSolution
) => errors
.push(FulfillmentError
{
141 obligation
: obligation
.goal
,
142 code
: FulfillmentErrorCode
::CodeSelectionError(
143 SelectionError
::Unimplemented
148 next_round
= std
::mem
::replace(&mut self.obligations
, next_round
);
150 if !making_progress
{
155 if errors
.is_empty() {
162 fn pending_obligations(&self) -> Vec
<PredicateObligation
<'tcx
>> {
163 self.obligations
.iter().map(|obligation
| obligation
.goal
.clone()).collect()