diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_infer/src/traits/mod.rs | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs new file mode 100644 index 000000000..4df4de21a --- /dev/null +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -0,0 +1,170 @@ +//! Trait Resolution. See the [rustc-dev-guide] for more information on how this works. +//! +//! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html + +mod engine; +pub mod error_reporting; +mod project; +mod structural_impls; +pub mod util; + +use rustc_hir as hir; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_span::Span; + +pub use self::FulfillmentErrorCode::*; +pub use self::ImplSource::*; +pub use self::ObligationCauseCode::*; +pub use self::SelectionError::*; + +pub use self::engine::{TraitEngine, TraitEngineExt}; +pub use self::project::MismatchedProjectionTypes; +pub(crate) use self::project::UndoLog; +pub use self::project::{ + Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, + ProjectionCacheStorage, Reveal, +}; +pub use rustc_middle::traits::*; + +/// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for +/// which the "impl_source" must be found. The process of finding an "impl_source" is +/// called "resolving" the `Obligation`. This process consists of +/// either identifying an `impl` (e.g., `impl Eq for i32`) that +/// satisfies the obligation, or else finding a bound that is in +/// scope. The eventual result is usually a `Selection` (defined below). +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Obligation<'tcx, T> { + /// The reason we have to prove this thing. + pub cause: ObligationCause<'tcx>, + + /// The environment in which we should prove this thing. + pub param_env: ty::ParamEnv<'tcx>, + + /// The thing we are trying to prove. + pub predicate: T, + + /// If we started proving this as a result of trying to prove + /// something else, track the total depth to ensure termination. + /// If this goes over a certain threshold, we abort compilation -- + /// in such cases, we can not say whether or not the predicate + /// holds for certain. Stupid halting problem; such a drag. + pub recursion_depth: usize, +} + +pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; +pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; + +impl<'tcx> PredicateObligation<'tcx> { + /// Flips the polarity of the inner predicate. + /// + /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`. + pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>> { + Some(PredicateObligation { + cause: self.cause.clone(), + param_env: self.param_env, + predicate: self.predicate.flip_polarity(tcx)?, + recursion_depth: self.recursion_depth, + }) + } +} + +impl<'tcx> TraitObligation<'tcx> { + /// Returns `true` if the trait predicate is considered `const` in its ParamEnv. + pub fn is_const(&self) -> bool { + match (self.predicate.skip_binder().constness, self.param_env.constness()) { + (ty::BoundConstness::ConstIfConst, hir::Constness::Const) => true, + _ => false, + } + } + + pub fn derived_cause( + &self, + variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx> { + self.cause.clone().derived_cause(self.predicate, variant) + } +} + +// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(PredicateObligation<'_>, 48); + +pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; + +pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; + +pub struct FulfillmentError<'tcx> { + pub obligation: PredicateObligation<'tcx>, + pub code: FulfillmentErrorCode<'tcx>, + /// Diagnostics only: the 'root' obligation which resulted in + /// the failure to process `obligation`. This is the obligation + /// that was initially passed to `register_predicate_obligation` + pub root_obligation: PredicateObligation<'tcx>, +} + +#[derive(Clone)] +pub enum FulfillmentErrorCode<'tcx> { + CodeSelectionError(SelectionError<'tcx>), + CodeProjectionError(MismatchedProjectionTypes<'tcx>), + CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate + CodeConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>), + CodeAmbiguity, +} + +impl<'tcx, O> Obligation<'tcx, O> { + pub fn new( + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: O, + ) -> Obligation<'tcx, O> { + Obligation { cause, param_env, recursion_depth: 0, predicate } + } + + pub fn with_depth( + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + predicate: O, + ) -> Obligation<'tcx, O> { + Obligation { cause, param_env, recursion_depth, predicate } + } + + pub fn misc( + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + trait_ref: O, + ) -> Obligation<'tcx, O> { + Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref) + } + + pub fn with<P>(&self, value: P) -> Obligation<'tcx, P> { + Obligation { + cause: self.cause.clone(), + param_env: self.param_env, + recursion_depth: self.recursion_depth, + predicate: value, + } + } +} + +impl<'tcx> FulfillmentError<'tcx> { + pub fn new( + obligation: PredicateObligation<'tcx>, + code: FulfillmentErrorCode<'tcx>, + root_obligation: PredicateObligation<'tcx>, + ) -> FulfillmentError<'tcx> { + FulfillmentError { obligation, code, root_obligation } + } +} + +impl<'tcx> TraitObligation<'tcx> { + pub fn polarity(&self) -> ty::ImplPolarity { + self.predicate.skip_binder().polarity + } + + pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> { + self.predicate.map_bound(|p| p.self_ty()) + } +} |