• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Trait Resolution. See the [rustc-dev-guide] for more information on how this works.
2 //!
3 //! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
4 
5 mod engine;
6 pub mod error_reporting;
7 mod project;
8 mod structural_impls;
9 pub mod util;
10 
11 use std::cmp;
12 
13 use hir::def_id::LocalDefId;
14 use rustc_hir as hir;
15 use rustc_middle::ty::error::{ExpectedFound, TypeError};
16 use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt};
17 use rustc_span::Span;
18 
19 pub use self::FulfillmentErrorCode::*;
20 pub use self::ImplSource::*;
21 pub use self::ObligationCauseCode::*;
22 pub use self::SelectionError::*;
23 
24 pub use self::engine::{TraitEngine, TraitEngineExt};
25 pub use self::project::MismatchedProjectionTypes;
26 pub(crate) use self::project::UndoLog;
27 pub use self::project::{
28     Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
29     ProjectionCacheStorage, Reveal,
30 };
31 pub use rustc_middle::traits::*;
32 
33 /// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for
34 /// which the "impl_source" must be found. The process of finding an "impl_source" is
35 /// called "resolving" the `Obligation`. This process consists of
36 /// either identifying an `impl` (e.g., `impl Eq for i32`) that
37 /// satisfies the obligation, or else finding a bound that is in
38 /// scope. The eventual result is usually a `Selection` (defined below).
39 #[derive(Clone, PartialEq, Eq, Hash)]
40 pub struct Obligation<'tcx, T> {
41     /// The reason we have to prove this thing.
42     pub cause: ObligationCause<'tcx>,
43 
44     /// The environment in which we should prove this thing.
45     pub param_env: ty::ParamEnv<'tcx>,
46 
47     /// The thing we are trying to prove.
48     pub predicate: T,
49 
50     /// If we started proving this as a result of trying to prove
51     /// something else, track the total depth to ensure termination.
52     /// If this goes over a certain threshold, we abort compilation --
53     /// in such cases, we can not say whether or not the predicate
54     /// holds for certain. Stupid halting problem; such a drag.
55     pub recursion_depth: usize,
56 }
57 
58 impl<'tcx, P> From<Obligation<'tcx, P>> for solve::Goal<'tcx, P> {
from(value: Obligation<'tcx, P>) -> Self59     fn from(value: Obligation<'tcx, P>) -> Self {
60         solve::Goal { param_env: value.param_env, predicate: value.predicate }
61     }
62 }
63 
64 pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
65 pub type TraitObligation<'tcx> = Obligation<'tcx, ty::TraitPredicate<'tcx>>;
66 pub type PolyTraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
67 
68 impl<'tcx> PredicateObligation<'tcx> {
69     /// Flips the polarity of the inner predicate.
70     ///
71     /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>>72     pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>> {
73         Some(PredicateObligation {
74             cause: self.cause.clone(),
75             param_env: self.param_env,
76             predicate: self.predicate.flip_polarity(tcx)?,
77             recursion_depth: self.recursion_depth,
78         })
79     }
80 
without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx>81     pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx> {
82         self.param_env = self.param_env.without_const();
83         if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() {
84             self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred.without_const()))));
85         }
86         self
87     }
88 }
89 
90 impl<'tcx> PolyTraitObligation<'tcx> {
91     /// Returns `true` if the trait predicate is considered `const` in its ParamEnv.
is_const(&self) -> bool92     pub fn is_const(&self) -> bool {
93         matches!(
94             (self.predicate.skip_binder().constness, self.param_env.constness()),
95             (ty::BoundConstness::ConstIfConst, hir::Constness::Const)
96         )
97     }
98 
derived_cause( &self, variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx>99     pub fn derived_cause(
100         &self,
101         variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
102     ) -> ObligationCause<'tcx> {
103         self.cause.clone().derived_cause(self.predicate, variant)
104     }
105 }
106 
107 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
108 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
109 static_assert_size!(PredicateObligation<'_>, 48);
110 
111 pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
112 
113 pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>;
114 
115 pub struct FulfillmentError<'tcx> {
116     pub obligation: PredicateObligation<'tcx>,
117     pub code: FulfillmentErrorCode<'tcx>,
118     /// Diagnostics only: the 'root' obligation which resulted in
119     /// the failure to process `obligation`. This is the obligation
120     /// that was initially passed to `register_predicate_obligation`
121     pub root_obligation: PredicateObligation<'tcx>,
122 }
123 
124 #[derive(Clone)]
125 pub enum FulfillmentErrorCode<'tcx> {
126     /// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented.
127     CodeCycle(Vec<PredicateObligation<'tcx>>),
128     CodeSelectionError(SelectionError<'tcx>),
129     CodeProjectionError(MismatchedProjectionTypes<'tcx>),
130     CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
131     CodeConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
132     CodeAmbiguity {
133         /// Overflow reported from the new solver `-Ztrait-solver=next`, which will
134         /// be reported as an regular error as opposed to a fatal error.
135         overflow: bool,
136     },
137 }
138 
139 impl<'tcx, O> Obligation<'tcx, O> {
new( tcx: TyCtxt<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, predicate: impl ToPredicate<'tcx, O>, ) -> Obligation<'tcx, O>140     pub fn new(
141         tcx: TyCtxt<'tcx>,
142         cause: ObligationCause<'tcx>,
143         param_env: ty::ParamEnv<'tcx>,
144         predicate: impl ToPredicate<'tcx, O>,
145     ) -> Obligation<'tcx, O> {
146         Self::with_depth(tcx, cause, 0, param_env, predicate)
147     }
148 
149     /// We often create nested obligations without setting the correct depth.
150     ///
151     /// To deal with this evaluate and fulfill explicitly update the depth
152     /// of nested obligations using this function.
set_depth_from_parent(&mut self, parent_depth: usize)153     pub fn set_depth_from_parent(&mut self, parent_depth: usize) {
154         self.recursion_depth = cmp::max(parent_depth + 1, self.recursion_depth);
155     }
156 
with_depth( tcx: TyCtxt<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, predicate: impl ToPredicate<'tcx, O>, ) -> Obligation<'tcx, O>157     pub fn with_depth(
158         tcx: TyCtxt<'tcx>,
159         cause: ObligationCause<'tcx>,
160         recursion_depth: usize,
161         param_env: ty::ParamEnv<'tcx>,
162         predicate: impl ToPredicate<'tcx, O>,
163     ) -> Obligation<'tcx, O> {
164         let predicate = predicate.to_predicate(tcx);
165         Obligation { cause, param_env, recursion_depth, predicate }
166     }
167 
misc( tcx: TyCtxt<'tcx>, span: Span, body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, trait_ref: impl ToPredicate<'tcx, O>, ) -> Obligation<'tcx, O>168     pub fn misc(
169         tcx: TyCtxt<'tcx>,
170         span: Span,
171         body_id: LocalDefId,
172         param_env: ty::ParamEnv<'tcx>,
173         trait_ref: impl ToPredicate<'tcx, O>,
174     ) -> Obligation<'tcx, O> {
175         Obligation::new(tcx, ObligationCause::misc(span, body_id), param_env, trait_ref)
176     }
177 
with<P>( &self, tcx: TyCtxt<'tcx>, value: impl ToPredicate<'tcx, P>, ) -> Obligation<'tcx, P>178     pub fn with<P>(
179         &self,
180         tcx: TyCtxt<'tcx>,
181         value: impl ToPredicate<'tcx, P>,
182     ) -> Obligation<'tcx, P> {
183         Obligation::with_depth(tcx, self.cause.clone(), self.recursion_depth, self.param_env, value)
184     }
185 }
186 
187 impl<'tcx> FulfillmentError<'tcx> {
new( obligation: PredicateObligation<'tcx>, code: FulfillmentErrorCode<'tcx>, root_obligation: PredicateObligation<'tcx>, ) -> FulfillmentError<'tcx>188     pub fn new(
189         obligation: PredicateObligation<'tcx>,
190         code: FulfillmentErrorCode<'tcx>,
191         root_obligation: PredicateObligation<'tcx>,
192     ) -> FulfillmentError<'tcx> {
193         FulfillmentError { obligation, code, root_obligation }
194     }
195 }
196 
197 impl<'tcx> PolyTraitObligation<'tcx> {
polarity(&self) -> ty::ImplPolarity198     pub fn polarity(&self) -> ty::ImplPolarity {
199         self.predicate.skip_binder().polarity
200     }
201 
self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>>202     pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
203         self.predicate.map_bound(|p| p.self_ty())
204     }
205 }
206