Skip to main content

rustc_infer/traits/
engine.rs

1use std::fmt::Debug;
2
3use rustc_hir::def_id::DefId;
4use rustc_middle::ty::{self, Ty, TyVid, Upcast};
5use thin_vec::{ThinVec, thin_vec};
6
7use super::{ObligationCause, PredicateObligation, PredicateObligations};
8use crate::infer::InferCtxt;
9use crate::traits::Obligation;
10
11/// A trait error with most of its information removed. This is the error
12/// returned by an `ObligationCtxt` by default, and suitable if you just
13/// want to see if a predicate holds, and don't particularly care about the
14/// error itself (except for if it's an ambiguity or true error).
15///
16/// use `ObligationCtxt::new_with_diagnostics` to get a `FulfillmentError`.
17#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for ScrubbedTraitError<'tcx> {
    #[inline]
    fn clone(&self) -> ScrubbedTraitError<'tcx> {
        match self {
            ScrubbedTraitError::TrueError => ScrubbedTraitError::TrueError,
            ScrubbedTraitError::Ambiguity => ScrubbedTraitError::Ambiguity,
            ScrubbedTraitError::Cycle(__self_0) =>
                ScrubbedTraitError::Cycle(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for ScrubbedTraitError<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ScrubbedTraitError::TrueError =>
                ::core::fmt::Formatter::write_str(f, "TrueError"),
            ScrubbedTraitError::Ambiguity =>
                ::core::fmt::Formatter::write_str(f, "Ambiguity"),
            ScrubbedTraitError::Cycle(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Cycle",
                    &__self_0),
        }
    }
}Debug)]
18pub enum ScrubbedTraitError<'tcx> {
19    /// A real error. This goal definitely does not hold.
20    TrueError,
21    /// An ambiguity. This goal may hold if further inference is done.
22    Ambiguity,
23    /// An old-solver-style cycle error, which will fatal. This is not
24    /// returned by the new solver.
25    Cycle(PredicateObligations<'tcx>),
26}
27
28impl<'tcx> ScrubbedTraitError<'tcx> {
29    pub fn is_true_error(&self) -> bool {
30        match self {
31            ScrubbedTraitError::TrueError => true,
32            ScrubbedTraitError::Ambiguity | ScrubbedTraitError::Cycle(_) => false,
33        }
34    }
35}
36
37#[derive(#[automatically_derived]
impl<E: ::core::fmt::Debug> ::core::fmt::Debug for TraitErrors<E> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            TraitErrors::HasErrors(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "HasErrors", &__self_0),
            TraitErrors::NoErrors =>
                ::core::fmt::Formatter::write_str(f, "NoErrors"),
        }
    }
}Debug, #[automatically_derived]
impl<E: ::core::clone::Clone> ::core::clone::Clone for TraitErrors<E> {
    #[inline]
    fn clone(&self) -> TraitErrors<E> {
        match self {
            TraitErrors::HasErrors(__self_0) =>
                TraitErrors::HasErrors(::core::clone::Clone::clone(__self_0)),
            TraitErrors::NoErrors => TraitErrors::NoErrors,
        }
    }
}Clone)]
38#[must_use]
39pub enum TraitErrors<E> {
40    HasErrors(ThinVec<E>),
41    NoErrors,
42}
43
44impl<E> TraitErrors<E> {
45    #[inline]
46    pub fn from_iter(iter: impl ExactSizeIterator<Item = E>) -> TraitErrors<E> {
47        if iter.len() == 0 { TraitErrors::NoErrors } else { TraitErrors::HasErrors(iter.collect()) }
48    }
49
50    #[inline]
51    pub fn has_errors(&self) -> bool {
52        #[allow(non_exhaustive_omitted_patterns)] match self {
    TraitErrors::HasErrors(_) => true,
    _ => false,
}matches!(self, TraitErrors::HasErrors(_))
53    }
54
55    #[inline]
56    pub fn no_errors(&self) -> bool {
57        #[allow(non_exhaustive_omitted_patterns)] match self {
    TraitErrors::NoErrors => true,
    _ => false,
}matches!(self, TraitErrors::NoErrors)
58    }
59
60    #[inline]
61    pub fn as_slice(&self) -> &[E] {
62        match self {
63            TraitErrors::HasErrors(errors) => errors.as_slice(),
64            TraitErrors::NoErrors => &[],
65        }
66    }
67
68    #[inline]
69    pub fn as_mut_slice(&mut self) -> &mut [E] {
70        match self {
71            TraitErrors::HasErrors(errors) => errors.as_mut_slice(),
72            TraitErrors::NoErrors => &mut [],
73        }
74    }
75
76    #[inline]
77    pub fn into_thin_vec(self) -> ThinVec<E> {
78        match self {
79            TraitErrors::HasErrors(errors) => errors,
80            TraitErrors::NoErrors => ThinVec::new(),
81        }
82    }
83
84    #[cold]
85    pub fn push(&mut self, err: E) {
86        match self {
87            TraitErrors::HasErrors(errors) => errors.push(err),
88            TraitErrors::NoErrors => *self = TraitErrors::HasErrors({
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(err);
    vec
}thin_vec![err]),
89        }
90    }
91
92    #[inline]
93    pub fn len(&self) -> usize {
94        match self {
95            TraitErrors::HasErrors(errors) => errors.len(),
96            TraitErrors::NoErrors => 0,
97        }
98    }
99}
100
101impl<E> IntoIterator for TraitErrors<E> {
102    type Item = E;
103    type IntoIter = thin_vec::IntoIter<E>;
104
105    #[inline]
106    fn into_iter(self) -> Self::IntoIter {
107        self.into_thin_vec().into_iter()
108    }
109}
110
111impl<'a, E> IntoIterator for &'a TraitErrors<E> {
112    type Item = &'a E;
113    type IntoIter = std::slice::Iter<'a, E>;
114
115    #[inline]
116    fn into_iter(self) -> Self::IntoIter {
117        self.as_slice().iter()
118    }
119}
120
121pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
122    /// Requires that `ty` must implement the trait with `def_id` in
123    /// the given environment. This trait must not have any type
124    /// parameters (except for `Self`).
125    fn register_bound(
126        &mut self,
127        infcx: &InferCtxt<'tcx>,
128        param_env: ty::ParamEnv<'tcx>,
129        ty: Ty<'tcx>,
130        def_id: DefId,
131        cause: ObligationCause<'tcx>,
132    ) {
133        let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]);
134        self.register_predicate_obligation(
135            infcx,
136            Obligation {
137                cause,
138                recursion_depth: 0,
139                param_env,
140                predicate: trait_ref.upcast(infcx.tcx),
141            },
142        );
143    }
144
145    fn register_predicate_obligation(
146        &mut self,
147        infcx: &InferCtxt<'tcx>,
148        obligation: PredicateObligation<'tcx>,
149    );
150
151    fn register_predicate_obligations(
152        &mut self,
153        infcx: &InferCtxt<'tcx>,
154        obligations: PredicateObligations<'tcx>,
155    ) {
156        for obligation in obligations {
157            self.register_predicate_obligation(infcx, obligation);
158        }
159    }
160
161    /// Go over the list of pending obligations and try to evaluate them.
162    ///
163    /// For each result:
164    /// Ok: remove the obligation from the list
165    /// Ambiguous: leave the obligation in the list to be evaluated later
166    /// Err: remove the obligation from the list and return an error
167    ///
168    /// Returns a list of errors from obligations that evaluated to Err.
169    #[must_use]
170    fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> TraitErrors<E>;
171
172    fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> TraitErrors<E>;
173
174    /// Evaluate all pending obligations, return error if they can't be evaluated.
175    ///
176    /// For each result:
177    /// Ok: remove the obligation from the list
178    /// Ambiguous: remove the obligation from the list and return an error
179    /// Err: remove the obligation from the list and return an error
180    ///
181    /// Returns a list of errors from obligations that evaluated to Ambiguous or Err.
182    #[must_use]
183    fn evaluate_obligations_error_on_ambiguity(
184        &mut self,
185        infcx: &InferCtxt<'tcx>,
186    ) -> TraitErrors<E> {
187        let errors = self.try_evaluate_obligations(infcx);
188        if errors.has_errors() {
189            return errors;
190        }
191
192        self.collect_remaining_errors(infcx)
193    }
194
195    fn has_pending_obligations(&self) -> bool;
196
197    fn pending_obligations(&self) -> PredicateObligations<'tcx>;
198
199    /// Pending obligations potentially referencing an inference variable whose
200    /// sub-unification root is `_sub_root`. May be conservative: implementations
201    /// can return obligations that don't actually reference `_sub_root` (the
202    /// default just returns everything).
203    fn pending_obligations_potentially_referencing_sub_root(
204        &self,
205        _infcx: &InferCtxt<'tcx>,
206        _sub_root: TyVid,
207    ) -> PredicateObligations<'tcx> {
208        self.pending_obligations()
209    }
210
211    /// Pending obligations potentially referencing float inference variables.
212    ///
213    /// FIXME: use a generic filter for `pending_obligations_potentially_referencing_sub_root`
214    /// and this after `TraitEngine` doesn't need to be dyn compatible.
215    fn pending_obligations_potentially_referencing_float_infer(
216        &self,
217        _infcx: &InferCtxt<'tcx>,
218    ) -> PredicateObligations<'tcx> {
219        self.pending_obligations()
220    }
221
222    /// Among all pending obligations, collect those are stalled on a inference variable which has
223    /// changed since the last call to `try_evaluate_obligations`. Those obligations are marked as
224    /// successful and returned.
225    fn drain_stalled_obligations_for_coroutines(
226        &mut self,
227        infcx: &InferCtxt<'tcx>,
228    ) -> PredicateObligations<'tcx>;
229}
230
231pub trait FromSolverError<'tcx, E>: Debug + 'tcx {
232    fn from_solver_error(infcx: &InferCtxt<'tcx>, error: E) -> Self;
233}