]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / chalk_fulfill.rs
1 //! Defines a Chalk-based `TraitEngine`
2
3 use crate::infer::canonical::OriginalQueryValues;
4 use crate::infer::InferCtxt;
5 use crate::traits::query::NoSolution;
6 use crate::traits::{
7 ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause,
8 PredicateObligation, SelectionError, TraitEngine,
9 };
10 use rustc_data_structures::fx::FxIndexSet;
11 use rustc_middle::ty::{self, Ty};
12
13 pub struct FulfillmentContext<'tcx> {
14 obligations: FxIndexSet<PredicateObligation<'tcx>>,
15 }
16
17 impl FulfillmentContext<'tcx> {
18 crate fn new() -> Self {
19 FulfillmentContext { obligations: FxIndexSet::default() }
20 }
21 }
22
23 impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
24 fn normalize_projection_type(
25 &mut self,
26 infcx: &InferCtxt<'_, 'tcx>,
27 _param_env: ty::ParamEnv<'tcx>,
28 projection_ty: ty::ProjectionTy<'tcx>,
29 _cause: ObligationCause<'tcx>,
30 ) -> Ty<'tcx> {
31 infcx.tcx.mk_ty(ty::Projection(projection_ty))
32 }
33
34 fn register_predicate_obligation(
35 &mut self,
36 infcx: &InferCtxt<'_, 'tcx>,
37 obligation: PredicateObligation<'tcx>,
38 ) {
39 assert!(!infcx.is_in_snapshot());
40 let obligation = infcx.resolve_vars_if_possible(&obligation);
41
42 self.obligations.insert(obligation);
43 }
44
45 fn select_all_or_error(
46 &mut self,
47 infcx: &InferCtxt<'_, 'tcx>,
48 ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
49 self.select_where_possible(infcx)?;
50
51 if self.obligations.is_empty() {
52 Ok(())
53 } else {
54 let errors = self
55 .obligations
56 .iter()
57 .map(|obligation| FulfillmentError {
58 obligation: obligation.clone(),
59 code: FulfillmentErrorCode::CodeAmbiguity,
60 points_at_arg_span: false,
61 })
62 .collect();
63 Err(errors)
64 }
65 }
66
67 fn select_where_possible(
68 &mut self,
69 infcx: &InferCtxt<'_, 'tcx>,
70 ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
71 assert!(!infcx.is_in_snapshot());
72
73 let mut errors = Vec::new();
74 let mut next_round = FxIndexSet::default();
75 let mut making_progress;
76
77 loop {
78 making_progress = false;
79
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);
88
89 match infcx.tcx.evaluate_goal(canonical_goal) {
90 Ok(response) => {
91 if response.is_proven() {
92 making_progress = true;
93
94 match infcx.instantiate_query_response_and_region_obligations(
95 &obligation.cause,
96 obligation.param_env,
97 &orig_values,
98 &response,
99 ) {
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)
104 }),
105 ),
106
107 Err(_err) => errors.push(FulfillmentError {
108 obligation,
109 code: FulfillmentErrorCode::CodeSelectionError(
110 SelectionError::Unimplemented,
111 ),
112 points_at_arg_span: false,
113 }),
114 }
115 } else {
116 // Ambiguous: retry at next round.
117 next_round.insert(obligation);
118 }
119 }
120
121 Err(NoSolution) => errors.push(FulfillmentError {
122 obligation,
123 code: FulfillmentErrorCode::CodeSelectionError(
124 SelectionError::Unimplemented,
125 ),
126 points_at_arg_span: false,
127 }),
128 }
129 }
130 next_round = std::mem::replace(&mut self.obligations, next_round);
131
132 if !making_progress {
133 break;
134 }
135 }
136
137 if errors.is_empty() { Ok(()) } else { Err(errors) }
138 }
139
140 fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
141 self.obligations.iter().cloned().collect()
142 }
143 }