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_macros::extension;
14use rustc_middle::arena::ArenaAllocatable;
15use rustc_middle::traits::query::NoSolution;
16use rustc_middle::ty::error::TypeError;
17use rustc_middle::ty::relate::Relate;
18use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance};
19
20use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine};
21use crate::error_reporting::InferCtxtErrorExt;
22use crate::regions::InferCtxtRegionExt;
23use crate::solve::{FulfillmentCtxt as NextFulfillmentCtxt, NextSolverError};
24use crate::traits::fulfill::OldSolverError;
25use crate::traits::{
26 FulfillmentError, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
27 StructurallyNormalizeExt,
28};
29
30#[extension(pub trait TraitEngineExt<'tcx, E>)]
31impl<'tcx, E> dyn TraitEngine<'tcx, E>
32where
33 E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>,
34{
35 fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> {
36 if infcx.next_trait_solver() {
37 Box::new(NextFulfillmentCtxt::new(infcx))
38 } else {
39 assert!(
40 !infcx.tcx.next_trait_solver_globally(),
41 "using old solver even though new solver is enabled globally"
42 );
43 Box::new(FulfillmentContext::new(infcx))
44 }
45 }
46}
47
48pub struct ObligationCtxt<'a, 'tcx, E = ScrubbedTraitError<'tcx>> {
51 pub infcx: &'a InferCtxt<'tcx>,
52 engine: RefCell<Box<dyn TraitEngine<'tcx, E>>>,
53}
54
55impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>> {
56 pub fn new_with_diagnostics(infcx: &'a InferCtxt<'tcx>) -> Self {
57 Self { infcx, engine: RefCell::new(<dyn TraitEngine<'tcx, _>>::new(infcx)) }
58 }
59}
60
61impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, ScrubbedTraitError<'tcx>> {
62 pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
63 Self { infcx, engine: RefCell::new(<dyn TraitEngine<'tcx, _>>::new(infcx)) }
64 }
65}
66
67impl<'a, 'tcx, E> ObligationCtxt<'a, 'tcx, E>
68where
69 E: 'tcx,
70{
71 pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
72 self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation);
73 }
74
75 pub fn register_obligations(
76 &self,
77 obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
78 ) {
79 for obligation in obligations {
82 self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation)
83 }
84 }
85
86 pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
87 let InferOk { value, obligations } = infer_ok;
88 self.engine.borrow_mut().register_predicate_obligations(self.infcx, obligations);
89 value
90 }
91
92 pub fn register_bound(
96 &self,
97 cause: ObligationCause<'tcx>,
98 param_env: ty::ParamEnv<'tcx>,
99 ty: Ty<'tcx>,
100 def_id: DefId,
101 ) {
102 let tcx = self.infcx.tcx;
103 let trait_ref = ty::TraitRef::new(tcx, def_id, [ty]);
104 self.register_obligation(Obligation {
105 cause,
106 recursion_depth: 0,
107 param_env,
108 predicate: trait_ref.upcast(tcx),
109 });
110 }
111
112 pub fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
113 &self,
114 cause: &ObligationCause<'tcx>,
115 param_env: ty::ParamEnv<'tcx>,
116 value: T,
117 ) -> T {
118 let infer_ok = self.infcx.at(cause, param_env).normalize(value);
119 self.register_infer_ok_obligations(infer_ok)
120 }
121
122 pub fn eq<T: ToTrace<'tcx>>(
123 &self,
124 cause: &ObligationCause<'tcx>,
125 param_env: ty::ParamEnv<'tcx>,
126 expected: T,
127 actual: T,
128 ) -> Result<(), TypeError<'tcx>> {
129 self.infcx
130 .at(cause, param_env)
131 .eq(DefineOpaqueTypes::Yes, expected, actual)
132 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
133 }
134
135 pub fn eq_trace<T: Relate<TyCtxt<'tcx>>>(
136 &self,
137 cause: &ObligationCause<'tcx>,
138 param_env: ty::ParamEnv<'tcx>,
139 trace: TypeTrace<'tcx>,
140 expected: T,
141 actual: T,
142 ) -> Result<(), TypeError<'tcx>> {
143 self.infcx
144 .at(cause, param_env)
145 .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual)
146 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
147 }
148
149 pub fn sub<T: ToTrace<'tcx>>(
151 &self,
152 cause: &ObligationCause<'tcx>,
153 param_env: ty::ParamEnv<'tcx>,
154 expected: T,
155 actual: T,
156 ) -> Result<(), TypeError<'tcx>> {
157 self.infcx
158 .at(cause, param_env)
159 .sub(DefineOpaqueTypes::Yes, expected, actual)
160 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
161 }
162
163 pub fn relate<T: ToTrace<'tcx>>(
164 &self,
165 cause: &ObligationCause<'tcx>,
166 param_env: ty::ParamEnv<'tcx>,
167 variance: Variance,
168 expected: T,
169 actual: T,
170 ) -> Result<(), TypeError<'tcx>> {
171 self.infcx
172 .at(cause, param_env)
173 .relate(DefineOpaqueTypes::Yes, expected, variance, actual)
174 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
175 }
176
177 pub fn sup<T: ToTrace<'tcx>>(
179 &self,
180 cause: &ObligationCause<'tcx>,
181 param_env: ty::ParamEnv<'tcx>,
182 expected: T,
183 actual: T,
184 ) -> Result<(), TypeError<'tcx>> {
185 self.infcx
186 .at(cause, param_env)
187 .sup(DefineOpaqueTypes::Yes, expected, actual)
188 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
189 }
190
191 pub fn lub<T: ToTrace<'tcx>>(
193 &self,
194 cause: &ObligationCause<'tcx>,
195 param_env: ty::ParamEnv<'tcx>,
196 expected: T,
197 actual: T,
198 ) -> Result<T, TypeError<'tcx>> {
199 self.infcx
200 .at(cause, param_env)
201 .lub(expected, actual)
202 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
203 }
204
205 #[must_use]
214 pub fn try_evaluate_obligations(&self) -> Vec<E> {
215 self.engine.borrow_mut().try_evaluate_obligations(self.infcx)
216 }
217
218 #[must_use]
227 pub fn evaluate_obligations_error_on_ambiguity(&self) -> Vec<E> {
228 self.engine.borrow_mut().evaluate_obligations_error_on_ambiguity(self.infcx)
229 }
230
231 #[must_use]
239 pub fn into_pending_obligations(self) -> PredicateObligations<'tcx> {
240 self.engine.borrow().pending_obligations()
241 }
242
243 pub fn resolve_regions_and_report_errors(
248 self,
249 body_id: LocalDefId,
250 param_env: ty::ParamEnv<'tcx>,
251 assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
252 ) -> Result<(), ErrorGuaranteed> {
253 let errors = self.infcx.resolve_regions(body_id, param_env, assumed_wf_tys);
254 if errors.is_empty() {
255 Ok(())
256 } else {
257 Err(self.infcx.err_ctxt().report_region_errors(body_id, &errors))
258 }
259 }
260
261 #[must_use]
266 pub fn resolve_regions(
267 self,
268 body_id: LocalDefId,
269 param_env: ty::ParamEnv<'tcx>,
270 assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
271 ) -> Vec<RegionResolutionError<'tcx>> {
272 self.infcx.resolve_regions(body_id, param_env, assumed_wf_tys)
273 }
274}
275
276impl<'tcx> ObligationCtxt<'_, 'tcx, FulfillmentError<'tcx>> {
277 pub fn assumed_wf_types_and_report_errors(
278 &self,
279 param_env: ty::ParamEnv<'tcx>,
280 def_id: LocalDefId,
281 ) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed> {
282 self.assumed_wf_types(param_env, def_id)
283 .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(errors))
284 }
285}
286
287impl<'tcx> ObligationCtxt<'_, 'tcx, ScrubbedTraitError<'tcx>> {
288 pub fn make_canonicalized_query_response<T>(
289 &self,
290 inference_vars: CanonicalVarValues<'tcx>,
291 answer: T,
292 ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
293 where
294 T: Debug + TypeFoldable<TyCtxt<'tcx>>,
295 Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
296 {
297 self.infcx.make_canonicalized_query_response(
298 inference_vars,
299 answer,
300 &mut **self.engine.borrow_mut(),
301 )
302 }
303}
304
305impl<'tcx, E> ObligationCtxt<'_, 'tcx, E>
306where
307 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
308{
309 pub fn assumed_wf_types(
310 &self,
311 param_env: ty::ParamEnv<'tcx>,
312 def_id: LocalDefId,
313 ) -> Result<FxIndexSet<Ty<'tcx>>, Vec<E>> {
314 let tcx = self.infcx.tcx;
315 let mut implied_bounds = FxIndexSet::default();
316 let mut errors = Vec::new();
317 for &(ty, span) in tcx.assumed_wf_types(def_id) {
318 let cause = ObligationCause::misc(span, def_id);
331 match self
332 .infcx
333 .at(&cause, param_env)
334 .deeply_normalize(ty, &mut **self.engine.borrow_mut())
335 {
336 Ok(normalized) => drop(implied_bounds.insert(normalized)),
338 Err(normalization_errors) => errors.extend(normalization_errors),
339 };
340 }
341
342 if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) }
343 }
344
345 pub fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
346 &self,
347 cause: &ObligationCause<'tcx>,
348 param_env: ty::ParamEnv<'tcx>,
349 value: T,
350 ) -> Result<T, Vec<E>> {
351 self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut())
352 }
353
354 pub fn structurally_normalize_ty(
355 &self,
356 cause: &ObligationCause<'tcx>,
357 param_env: ty::ParamEnv<'tcx>,
358 value: Ty<'tcx>,
359 ) -> Result<Ty<'tcx>, Vec<E>> {
360 self.infcx
361 .at(cause, param_env)
362 .structurally_normalize_ty(value, &mut **self.engine.borrow_mut())
363 }
364
365 pub fn structurally_normalize_const(
366 &self,
367 cause: &ObligationCause<'tcx>,
368 param_env: ty::ParamEnv<'tcx>,
369 value: ty::Const<'tcx>,
370 ) -> Result<ty::Const<'tcx>, Vec<E>> {
371 self.infcx
372 .at(cause, param_env)
373 .structurally_normalize_const(value, &mut **self.engine.borrow_mut())
374 }
375
376 pub fn structurally_normalize_term(
377 &self,
378 cause: &ObligationCause<'tcx>,
379 param_env: ty::ParamEnv<'tcx>,
380 value: ty::Term<'tcx>,
381 ) -> Result<ty::Term<'tcx>, Vec<E>> {
382 self.infcx
383 .at(cause, param_env)
384 .structurally_normalize_term(value, &mut **self.engine.borrow_mut())
385 }
386}