]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_trait_selection/src/solve/fulfill.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / solve / fulfill.rs
1 use std::mem;
2
3 use rustc_infer::infer::InferCtxt;
4 use rustc_infer::traits::{
5 query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
6 PredicateObligation, SelectionError, TraitEngine,
7 };
8 use rustc_middle::ty;
9 use rustc_middle::ty::error::{ExpectedFound, TypeError};
10
11 use super::{Certainty, InferCtxtEvalExt};
12
13 /// A trait engine using the new trait solver.
14 ///
15 /// This is mostly identical to how `evaluate_all` works inside of the
16 /// solver, except that the requirements are slightly different.
17 ///
18 /// Unlike `evaluate_all` it is possible to add new obligations later on
19 /// and we also have to track diagnostics information by using `Obligation`
20 /// instead of `Goal`.
21 ///
22 /// It is also likely that we want to use slightly different datastructures
23 /// here as this will have to deal with far more root goals than `evaluate_all`.
24 pub struct FulfillmentCtxt<'tcx> {
25 obligations: Vec<PredicateObligation<'tcx>>,
26 }
27
28 impl<'tcx> FulfillmentCtxt<'tcx> {
29 pub fn new() -> FulfillmentCtxt<'tcx> {
30 FulfillmentCtxt { obligations: Vec::new() }
31 }
32 }
33
34 impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
35 fn register_predicate_obligation(
36 &mut self,
37 _infcx: &InferCtxt<'tcx>,
38 obligation: PredicateObligation<'tcx>,
39 ) {
40 self.obligations.push(obligation);
41 }
42
43 fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
44 self.obligations
45 .drain(..)
46 .map(|obligation| FulfillmentError {
47 obligation: obligation.clone(),
48 code: FulfillmentErrorCode::CodeAmbiguity,
49 root_obligation: obligation,
50 })
51 .collect()
52 }
53
54 fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
55 let mut errors = Vec::new();
56 for i in 0.. {
57 if !infcx.tcx.recursion_limit().value_within_limit(i) {
58 unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
59 }
60
61 let mut has_changed = false;
62 for obligation in mem::take(&mut self.obligations) {
63 let goal = obligation.clone().into();
64 let (changed, certainty) = match infcx.evaluate_root_goal(goal) {
65 Ok(result) => result,
66 Err(NoSolution) => {
67 errors.push(FulfillmentError {
68 obligation: obligation.clone(),
69 code: match goal.predicate.kind().skip_binder() {
70 ty::PredicateKind::Clause(ty::Clause::Projection(_)) => {
71 FulfillmentErrorCode::CodeProjectionError(
72 // FIXME: This could be a `Sorts` if the term is a type
73 MismatchedProjectionTypes { err: TypeError::Mismatch },
74 )
75 }
76 ty::PredicateKind::AliasEq(_, _) => {
77 FulfillmentErrorCode::CodeProjectionError(
78 MismatchedProjectionTypes { err: TypeError::Mismatch },
79 )
80 }
81 ty::PredicateKind::Subtype(pred) => {
82 let (a, b) = infcx.instantiate_binder_with_placeholders(
83 goal.predicate.kind().rebind((pred.a, pred.b)),
84 );
85 let expected_found = ExpectedFound::new(true, a, b);
86 FulfillmentErrorCode::CodeSubtypeError(
87 expected_found,
88 TypeError::Sorts(expected_found),
89 )
90 }
91 ty::PredicateKind::Coerce(pred) => {
92 let (a, b) = infcx.instantiate_binder_with_placeholders(
93 goal.predicate.kind().rebind((pred.a, pred.b)),
94 );
95 let expected_found = ExpectedFound::new(false, a, b);
96 FulfillmentErrorCode::CodeSubtypeError(
97 expected_found,
98 TypeError::Sorts(expected_found),
99 )
100 }
101 ty::PredicateKind::ConstEquate(a, b) => {
102 let (a, b) = infcx.instantiate_binder_with_placeholders(
103 goal.predicate.kind().rebind((a, b)),
104 );
105 let expected_found = ExpectedFound::new(true, a, b);
106 FulfillmentErrorCode::CodeConstEquateError(
107 expected_found,
108 TypeError::ConstMismatch(expected_found),
109 )
110 }
111 ty::PredicateKind::Clause(_)
112 | ty::PredicateKind::WellFormed(_)
113 | ty::PredicateKind::ObjectSafe(_)
114 | ty::PredicateKind::ClosureKind(_, _, _)
115 | ty::PredicateKind::ConstEvaluatable(_)
116 | ty::PredicateKind::TypeWellFormedFromEnv(_)
117 | ty::PredicateKind::Ambiguous => {
118 FulfillmentErrorCode::CodeSelectionError(
119 SelectionError::Unimplemented,
120 )
121 }
122 },
123 root_obligation: obligation,
124 });
125 continue;
126 }
127 };
128
129 has_changed |= changed;
130 match certainty {
131 Certainty::Yes => {}
132 Certainty::Maybe(_) => self.obligations.push(obligation),
133 }
134 }
135
136 if !has_changed {
137 break;
138 }
139 }
140
141 errors
142 }
143
144 fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
145 self.obligations.clone()
146 }
147
148 fn drain_unstalled_obligations(
149 &mut self,
150 _: &InferCtxt<'tcx>,
151 ) -> Vec<PredicateObligation<'tcx>> {
152 unimplemented!()
153 }
154 }