pub(crate) struct AutoTraitFinder<'a, 'tcx> {
    pub(crate) cx: &'a mut DocContext<'tcx>,
}

Fields§

§cx: &'a mut DocContext<'tcx>

Implementations§

source§

impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx>where 'tcx: 'a,

source

pub(crate) fn new(cx: &'a mut DocContext<'tcx>) -> Self

source

fn generate_for_trait( &mut self, ty: Ty<'tcx>, trait_def_id: DefId, param_env: ParamEnv<'tcx>, item_def_id: DefId, f: &AutoTraitFinder<'tcx>, discard_positive_impl: bool ) -> Option<Item>

source

pub(crate) fn get_auto_trait_impls(&mut self, item_def_id: DefId) -> Vec<Item>

source

fn get_lifetime( region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime> ) -> Lifetime

source

fn handle_lifetimes<'cx>( regions: &RegionConstraintData<'cx>, names_map: &FxHashMap<Symbol, Lifetime> ) -> ThinVec<WherePredicate>

This method calculates two things: Lifetime constraints of the form 'a: 'b, and region constraints of the form RegionVid: 'a

This is essentially a simplified version of lexical_region_resolve. However, handle_lifetimes determines what needs be true in order for an impl to hold. lexical_region_resolve, along with much of the rest of the compiler, is concerned with determining if a given set up constraints/predicates are met, given some starting conditions (e.g., user-provided code). For this reason, it’s easier to perform the calculations we need on our own, rather than trying to make existing inference/solver code do what we want.

source

fn extract_for_generics(&self, pred: Clause<'tcx>) -> FxHashSet<GenericParamDef>

source

fn make_final_bounds( &self, ty_to_bounds: FxHashMap<Type, FxHashSet<GenericBound>>, ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)>, lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<GenericBound>> ) -> Vec<WherePredicate>

source

fn param_env_to_generics( &mut self, item_def_id: DefId, param_env: ParamEnv<'tcx>, existing_predicates: ThinVec<WherePredicate>, vid_to_region: FxHashMap<RegionVid, Region<'tcx>> ) -> Generics

Converts the calculated ParamEnv and lifetime information to a clean::Generics, suitable for display on the docs page. Cleaning the Predicates produces sub-optimal WherePredicates, so we fix them up:

  • Multiple bounds for the same type are coalesced into one: e.g., T: Copy, T: Debug becomes T: Copy + Debug
  • Fn bounds are handled specially - instead of leaving it as T: Fn(), <T as Fn::Output> = K, we use the dedicated syntax T: Fn() -> K
  • We explicitly add a ?Sized bound if we didn’t find any Sized predicates for a type
source

fn sort_where_predicates(&self, predicates: &mut [WherePredicate])

Ensure that the predicates are in a consistent order. The precise ordering doesn’t actually matter, but it’s important that a given set of predicates always appears in the same order - both for visual consistency between ‘rustdoc’ runs, and to make writing tests much easier

source

fn sort_where_bounds(&self, bounds: &mut Vec<GenericBound>)

Ensure that the bounds are in a consistent order. The precise ordering doesn’t actually matter, but it’s important that a given set of bounds always appears in the same order - both for visual consistency between ‘rustdoc’ runs, and to make writing tests much easier

source

fn unstable_debug_sort<T: Debug>(&self, vec: &mut [T])

This might look horrendously hacky, but it’s actually not that bad.

For performance reasons, we use several different FxHashMaps in the process of computing the final set of where predicates. However, the iteration order of a HashMap is completely unspecified. In fact, the iteration of an FxHashMap can even vary between platforms, since FxHasher has different behavior for 32-bit and 64-bit platforms.

Obviously, it’s extremely undesirable for documentation rendering to be dependent on the platform it’s run on. Apart from being confusing to end users, it makes writing tests much more difficult, as predicates can appear in any order in the final result.

To solve this problem, we sort WherePredicates and GenericBounds by their Debug string. The thing to keep in mind is that we don’t really care what the final order is - we’re synthesizing an impl or bound ourselves, so any order can be considered equally valid. By sorting the predicates and bounds, however, we ensure that for a given codebase, all auto-trait impls always render in exactly the same way.

Using the Debug implementation for sorting prevents us from needing to write quite a bit of almost entirely useless code (e.g., how should two Types be sorted relative to each other). It also allows us to solve the problem for both WherePredicates and GenericBounds at the same time. This approach is probably somewhat slower, but the small number of items involved (impls rarely have more than a few bounds) means that it shouldn’t matter in practice.

source

fn is_fn_trait(&self, path: &Path) -> bool

Auto Trait Implementations§

§

impl<'a, 'tcx> !RefUnwindSafe for AutoTraitFinder<'a, 'tcx>

§

impl<'a, 'tcx> !Send for AutoTraitFinder<'a, 'tcx>

§

impl<'a, 'tcx> !Sync for AutoTraitFinder<'a, 'tcx>

§

impl<'a, 'tcx> Unpin for AutoTraitFinder<'a, 'tcx>

§

impl<'a, 'tcx> !UnwindSafe for AutoTraitFinder<'a, 'tcx>

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more

Layout§

Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...) attributes. Please see the Rust Reference's “Type Layout” chapter for details on type layout guarantees.

Size: 8 bytes