rustc_trait_selection/traits/
engine.rs1use std::cell::RefCell;
2use std::fmt::Debug;
3
4use rustc_data_structures::fx::FxIndexSet;
5use rustc_errors::ErrorGuaranteed;
6use rustc_hir::def_id::{DefId, LocalDefId};
7use rustc_infer::infer::at::ToTrace;
8use rustc_infer::infer::canonical::{
9 Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
10};
11use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace};
12use rustc_infer::traits::PredicateObligations;
13use rustc_middle::arena::ArenaAllocatable;
14use rustc_middle::traits::query::NoSolution;
15use rustc_middle::ty::error::TypeError;
16use rustc_middle::ty::relate::Relate;
17use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Unnormalized, Upcast, Variance};
18
19use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine};
20use crate::error_reporting::InferCtxtErrorExt;
21use crate::regions::InferCtxtRegionExt;
22use crate::solve::{FulfillmentCtxt as NextFulfillmentCtxt, NextSolverError};
23use crate::traits::fulfill::OldSolverError;
24use crate::traits::{
25 FulfillmentError, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
26 StructurallyNormalizeExt,
27};
28
29pub enum FulfillmentEngine<'tcx, E> {
34 Old(FulfillmentContext<'tcx, E>),
35 Next(NextFulfillmentCtxt<'tcx, E>),
36}
37
38impl<'tcx, E> FulfillmentEngine<'tcx, E>
39where
40 E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>,
41{
42 pub fn new(infcx: &InferCtxt<'tcx>) -> Self {
43 if infcx.next_trait_solver() {
44 FulfillmentEngine::Next(NextFulfillmentCtxt::new(infcx))
45 } else {
46 if !!infcx.tcx.next_trait_solver_globally() {
{
::core::panicking::panic_fmt(format_args!("using old solver even though new solver is enabled globally"));
}
};assert!(
47 !infcx.tcx.next_trait_solver_globally(),
48 "using old solver even though new solver is enabled globally"
49 );
50 FulfillmentEngine::Old(FulfillmentContext::new(infcx))
51 }
52 }
53}
54
55impl<'tcx, E> TraitEngine<'tcx, E> for FulfillmentEngine<'tcx, E>
56where
57 E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>,
58{
59 fn register_predicate_obligation(
60 &mut self,
61 infcx: &InferCtxt<'tcx>,
62 obligation: PredicateObligation<'tcx>,
63 ) {
64 match self {
65 FulfillmentEngine::Old(engine) => {
66 engine.register_predicate_obligation(infcx, obligation)
67 }
68 FulfillmentEngine::Next(engine) => {
69 engine.register_predicate_obligation(infcx, obligation)
70 }
71 }
72 }
73
74 fn register_predicate_obligations(
75 &mut self,
76 infcx: &InferCtxt<'tcx>,
77 obligations: PredicateObligations<'tcx>,
78 ) {
79 match self {
80 FulfillmentEngine::Old(engine) => {
81 engine.register_predicate_obligations(infcx, obligations)
82 }
83 FulfillmentEngine::Next(engine) => {
84 engine.register_predicate_obligations(infcx, obligations)
85 }
86 }
87 }
88
89 fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
90 match self {
91 FulfillmentEngine::Old(engine) => engine.try_evaluate_obligations(infcx),
92 FulfillmentEngine::Next(engine) => engine.try_evaluate_obligations(infcx),
93 }
94 }
95
96 fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
97 match self {
98 FulfillmentEngine::Old(engine) => engine.collect_remaining_errors(infcx),
99 FulfillmentEngine::Next(engine) => engine.collect_remaining_errors(infcx),
100 }
101 }
102
103 fn has_pending_obligations(&self) -> bool {
104 match self {
105 FulfillmentEngine::Old(engine) => engine.has_pending_obligations(),
106 FulfillmentEngine::Next(engine) => engine.has_pending_obligations(),
107 }
108 }
109
110 fn pending_obligations(&self) -> PredicateObligations<'tcx> {
111 match self {
112 FulfillmentEngine::Old(engine) => engine.pending_obligations(),
113 FulfillmentEngine::Next(engine) => engine.pending_obligations(),
114 }
115 }
116
117 fn pending_obligations_potentially_referencing_sub_root(
118 &self,
119 infcx: &InferCtxt<'tcx>,
120 sub_root: ty::TyVid,
121 ) -> PredicateObligations<'tcx> {
122 match self {
123 FulfillmentEngine::Old(engine) => {
124 engine.pending_obligations_potentially_referencing_sub_root(infcx, sub_root)
125 }
126 FulfillmentEngine::Next(engine) => {
127 engine.pending_obligations_potentially_referencing_sub_root(infcx, sub_root)
128 }
129 }
130 }
131
132 fn drain_stalled_obligations_for_coroutines(
133 &mut self,
134 infcx: &InferCtxt<'tcx>,
135 ) -> PredicateObligations<'tcx> {
136 match self {
137 FulfillmentEngine::Old(engine) => {
138 engine.drain_stalled_obligations_for_coroutines(infcx)
139 }
140 FulfillmentEngine::Next(engine) => {
141 engine.drain_stalled_obligations_for_coroutines(infcx)
142 }
143 }
144 }
145}
146
147pub struct ObligationCtxt<'a, 'tcx, E = ScrubbedTraitError<'tcx>> {
150 pub infcx: &'a InferCtxt<'tcx>,
151 engine: RefCell<FulfillmentEngine<'tcx, E>>,
152}
153
154impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>> {
155 pub fn new_with_diagnostics(infcx: &'a InferCtxt<'tcx>) -> Self {
156 Self { infcx, engine: RefCell::new(FulfillmentEngine::new(infcx)) }
157 }
158}
159
160impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, ScrubbedTraitError<'tcx>> {
161 pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
162 Self { infcx, engine: RefCell::new(FulfillmentEngine::new(infcx)) }
163 }
164}
165
166impl<'a, 'tcx, E> ObligationCtxt<'a, 'tcx, E>
167where
168 E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>,
169{
170 pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
171 self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation);
172 }
173
174 pub fn register_obligations(
175 &self,
176 obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
177 ) {
178 for obligation in obligations {
181 self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation)
182 }
183 }
184
185 pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
186 let InferOk { value, obligations } = infer_ok;
187 self.engine.borrow_mut().register_predicate_obligations(self.infcx, obligations);
188 value
189 }
190
191 pub fn register_bound(
195 &self,
196 cause: ObligationCause<'tcx>,
197 param_env: ty::ParamEnv<'tcx>,
198 ty: Ty<'tcx>,
199 def_id: DefId,
200 ) {
201 let tcx = self.infcx.tcx;
202 let trait_ref = ty::TraitRef::new(tcx, def_id, [ty]);
203 self.register_obligation(Obligation {
204 cause,
205 recursion_depth: 0,
206 param_env,
207 predicate: trait_ref.upcast(tcx),
208 });
209 }
210
211 pub fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
212 &self,
213 cause: &ObligationCause<'tcx>,
214 param_env: ty::ParamEnv<'tcx>,
215 value: Unnormalized<'tcx, T>,
216 ) -> T {
217 let infer_ok = self.infcx.at(cause, param_env).normalize(value);
218 self.register_infer_ok_obligations(infer_ok)
219 }
220
221 pub fn eq<T: ToTrace<'tcx>>(
222 &self,
223 cause: &ObligationCause<'tcx>,
224 param_env: ty::ParamEnv<'tcx>,
225 expected: T,
226 actual: T,
227 ) -> Result<(), TypeError<'tcx>> {
228 self.infcx
229 .at(cause, param_env)
230 .eq(DefineOpaqueTypes::Yes, expected, actual)
231 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
232 }
233
234 pub fn eq_trace<T: Relate<TyCtxt<'tcx>>>(
235 &self,
236 cause: &ObligationCause<'tcx>,
237 param_env: ty::ParamEnv<'tcx>,
238 trace: TypeTrace<'tcx>,
239 expected: T,
240 actual: T,
241 ) -> Result<(), TypeError<'tcx>> {
242 self.infcx
243 .at(cause, param_env)
244 .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual)
245 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
246 }
247
248 pub fn sub<T: ToTrace<'tcx>>(
250 &self,
251 cause: &ObligationCause<'tcx>,
252 param_env: ty::ParamEnv<'tcx>,
253 expected: T,
254 actual: T,
255 ) -> Result<(), TypeError<'tcx>> {
256 self.infcx
257 .at(cause, param_env)
258 .sub(DefineOpaqueTypes::Yes, expected, actual)
259 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
260 }
261
262 pub fn relate<T: ToTrace<'tcx>>(
263 &self,
264 cause: &ObligationCause<'tcx>,
265 param_env: ty::ParamEnv<'tcx>,
266 variance: Variance,
267 expected: T,
268 actual: T,
269 ) -> Result<(), TypeError<'tcx>> {
270 self.infcx
271 .at(cause, param_env)
272 .relate(DefineOpaqueTypes::Yes, expected, variance, actual)
273 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
274 }
275
276 pub fn sup<T: ToTrace<'tcx>>(
278 &self,
279 cause: &ObligationCause<'tcx>,
280 param_env: ty::ParamEnv<'tcx>,
281 expected: T,
282 actual: T,
283 ) -> Result<(), TypeError<'tcx>> {
284 self.infcx
285 .at(cause, param_env)
286 .sup(DefineOpaqueTypes::Yes, expected, actual)
287 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
288 }
289
290 pub fn lub<T: ToTrace<'tcx>>(
292 &self,
293 cause: &ObligationCause<'tcx>,
294 param_env: ty::ParamEnv<'tcx>,
295 expected: T,
296 actual: T,
297 ) -> Result<T, TypeError<'tcx>> {
298 self.infcx
299 .at(cause, param_env)
300 .lub(expected, actual)
301 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
302 }
303
304 #[must_use]
313 pub fn try_evaluate_obligations(&self) -> Vec<E> {
314 self.engine.borrow_mut().try_evaluate_obligations(self.infcx)
315 }
316
317 #[must_use]
326 pub fn evaluate_obligations_error_on_ambiguity(&self) -> Vec<E> {
327 self.engine.borrow_mut().evaluate_obligations_error_on_ambiguity(self.infcx)
328 }
329
330 #[must_use]
338 pub fn into_pending_obligations(self) -> PredicateObligations<'tcx> {
339 self.engine.borrow().pending_obligations()
340 }
341
342 pub fn resolve_regions_and_report_errors(
347 self,
348 body_def_id: LocalDefId,
349 param_env: ty::ParamEnv<'tcx>,
350 assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
351 ) -> Result<(), ErrorGuaranteed> {
352 let errors = self.infcx.resolve_regions(body_def_id, param_env, assumed_wf_tys);
353 if errors.is_empty() {
354 Ok(())
355 } else {
356 Err(self.infcx.err_ctxt().report_region_errors(body_def_id, &errors))
357 }
358 }
359
360 #[must_use]
365 pub fn resolve_regions(
366 self,
367 body_def_id: LocalDefId,
368 param_env: ty::ParamEnv<'tcx>,
369 assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
370 ) -> Vec<RegionResolutionError<'tcx>> {
371 self.infcx.resolve_regions(body_def_id, param_env, assumed_wf_tys)
372 }
373}
374
375impl<'tcx> ObligationCtxt<'_, 'tcx, FulfillmentError<'tcx>> {
376 pub fn assumed_wf_types_and_report_errors(
377 &self,
378 param_env: ty::ParamEnv<'tcx>,
379 def_id: LocalDefId,
380 ) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed> {
381 self.assumed_wf_types(param_env, def_id)
382 .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(errors))
383 }
384}
385
386impl<'tcx> ObligationCtxt<'_, 'tcx, ScrubbedTraitError<'tcx>> {
387 pub fn make_canonicalized_query_response<T>(
388 &self,
389 inference_vars: CanonicalVarValues<'tcx>,
390 answer: T,
391 ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
392 where
393 T: Debug + TypeFoldable<TyCtxt<'tcx>>,
394 Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
395 {
396 self.infcx.make_canonicalized_query_response(
397 inference_vars,
398 answer,
399 &mut *self.engine.borrow_mut(),
400 )
401 }
402}
403
404impl<'tcx, E> ObligationCtxt<'_, 'tcx, E>
405where
406 E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>,
407{
408 pub fn assumed_wf_types(
409 &self,
410 param_env: ty::ParamEnv<'tcx>,
411 def_id: LocalDefId,
412 ) -> Result<FxIndexSet<Ty<'tcx>>, Vec<E>> {
413 let tcx = self.infcx.tcx;
414 let mut implied_bounds = FxIndexSet::default();
415 let mut errors = Vec::new();
416 for &(ty, span) in tcx.assumed_wf_types(def_id) {
417 let cause = ObligationCause::misc(span, def_id);
430 match self
431 .infcx
432 .at(&cause, param_env)
433 .deeply_normalize(Unnormalized::new_wip(ty), &mut *self.engine.borrow_mut())
434 {
435 Ok(normalized) => drop(implied_bounds.insert(normalized)),
437 Err(normalization_errors) => errors.extend(normalization_errors),
438 };
439 }
440
441 if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) }
442 }
443
444 pub fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
445 &self,
446 cause: &ObligationCause<'tcx>,
447 param_env: ty::ParamEnv<'tcx>,
448 value: Unnormalized<'tcx, T>,
449 ) -> Result<T, Vec<E>> {
450 self.infcx.at(cause, param_env).deeply_normalize(value, &mut *self.engine.borrow_mut())
451 }
452
453 pub fn structurally_normalize_ty(
454 &self,
455 cause: &ObligationCause<'tcx>,
456 param_env: ty::ParamEnv<'tcx>,
457 value: Unnormalized<'tcx, Ty<'tcx>>,
458 ) -> Result<Ty<'tcx>, Vec<E>> {
459 self.infcx
460 .at(cause, param_env)
461 .structurally_normalize_ty(value, &mut *self.engine.borrow_mut())
462 }
463
464 pub fn structurally_normalize_const(
465 &self,
466 cause: &ObligationCause<'tcx>,
467 param_env: ty::ParamEnv<'tcx>,
468 value: Unnormalized<'tcx, ty::Const<'tcx>>,
469 ) -> Result<ty::Const<'tcx>, Vec<E>> {
470 self.infcx
471 .at(cause, param_env)
472 .structurally_normalize_const(value, &mut *self.engine.borrow_mut())
473 }
474
475 pub fn structurally_normalize_term(
476 &self,
477 cause: &ObligationCause<'tcx>,
478 param_env: ty::ParamEnv<'tcx>,
479 value: Unnormalized<'tcx, ty::Term<'tcx>>,
480 ) -> Result<ty::Term<'tcx>, Vec<E>> {
481 self.infcx
482 .at(cause, param_env)
483 .structurally_normalize_term(value, &mut *self.engine.borrow_mut())
484 }
485}