rustc_trait_selection/traits/
engine.rs

1use 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
48/// Used if you want to have pleasant experience when dealing
49/// with obligations outside of hir or mir typeck.
50pub 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        // Can't use `register_predicate_obligations` because the iterator
80        // may also use this `ObligationCtxt`.
81        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    /// Requires that `ty` must implement the trait with `def_id` in
93    /// the given environment. This trait must not have any type
94    /// parameters (except for `Self`).
95    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    /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`.
150    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    /// Checks whether `expected` is a supertype of `actual`: `expected :> actual`.
178    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    /// Computes the least-upper-bound, or mutual supertype, of two values.
192    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    /// Go over the list of pending obligations and try to evaluate them.
206    ///
207    /// For each result:
208    /// Ok: remove the obligation from the list
209    /// Ambiguous: leave the obligation in the list to be evaluated later
210    /// Err: remove the obligation from the list and return an error
211    ///
212    /// Returns a list of errors from obligations that evaluated to Err.
213    #[must_use]
214    pub fn try_evaluate_obligations(&self) -> Vec<E> {
215        self.engine.borrow_mut().try_evaluate_obligations(self.infcx)
216    }
217
218    /// Evaluate all pending obligations, return error if they can't be evaluated.
219    ///
220    /// For each result:
221    /// Ok: remove the obligation from the list
222    /// Ambiguous: remove the obligation from the list and return an error
223    /// Err: remove the obligation from the list and return an error
224    ///
225    /// Returns a list of errors from obligations that evaluated to Ambiguous or Err.
226    #[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    /// Returns the not-yet-processed and stalled obligations from the
232    /// `ObligationCtxt`.
233    ///
234    /// Takes ownership of the context as doing operations such as
235    /// [`ObligationCtxt::eq`] afterwards will result in other obligations
236    /// getting ignored. You can make a new `ObligationCtxt` if this
237    /// needs to be done in a loop, for example.
238    #[must_use]
239    pub fn into_pending_obligations(self) -> PredicateObligations<'tcx> {
240        self.engine.borrow().pending_obligations()
241    }
242
243    /// Resolves regions and reports errors.
244    ///
245    /// Takes ownership of the context as doing trait solving afterwards
246    /// will result in region constraints getting ignored.
247    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    /// Resolves regions and reports errors.
262    ///
263    /// Takes ownership of the context as doing trait solving afterwards
264    /// will result in region constraints getting ignored.
265    #[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            // FIXME(@lcnr): rustc currently does not check wf for types
319            // pre-normalization, meaning that implied bounds are sometimes
320            // incorrect. See #100910 for more details.
321            //
322            // Not adding the unnormalized types here mostly fixes that, except
323            // that there are projections which are still ambiguous in the item definition
324            // but do normalize successfully when using the item, see #98543.
325            //
326            // Anyways, I will hopefully soon change implied bounds to make all of this
327            // sound and then uncomment this line again.
328
329            // implied_bounds.insert(ty);
330            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                // Insert well-formed types, ignoring duplicates.
337                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}