pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
    cx: Cx,
    delegate: RefCell<D>,
    upvars: Option<&'tcx FxIndexMap<HirId, Upvar>>,
}
Expand description

The ExprUseVisitor type

This is the code that actually walks the tree.

Fields§

§cx: Cx§delegate: RefCell<D>

We use a RefCell here so that delegates can mutate themselves, but we can still have calls to our own helper functions.

§upvars: Option<&'tcx FxIndexMap<HirId, Upvar>>

Implementations§

source§

impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'tcx, (&'a LateContext<'tcx>, LocalDefId), D>

source

pub fn for_clippy( cx: &'a LateContext<'tcx>, body_def_id: LocalDefId, delegate: D, ) -> Self

source§

impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D>

source

pub(crate) fn new(cx: Cx, delegate: D) -> Self

Creates the ExprUseVisitor, configuring it with the various options provided:

  • delegate – who receives the callbacks
  • param_env — parameter environment for trait lookups (esp. pertaining to Copy)
  • typeck_results — typeck results for the code being analyzed
source

pub fn consume_body(&self, body: &Body<'_>) -> Result<(), Cx::Error>

source

fn consume_or_copy( &self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, )

source

fn consume_exprs(&self, exprs: &[Expr<'_>]) -> Result<(), Cx::Error>

source

pub fn consume_expr(&self, expr: &Expr<'_>) -> Result<(), Cx::Error>

source

fn mutate_expr(&self, expr: &Expr<'_>) -> Result<(), Cx::Error>

source

fn borrow_expr(&self, expr: &Expr<'_>, bk: BorrowKind) -> Result<(), Cx::Error>

source

pub fn walk_expr(&self, expr: &Expr<'_>) -> Result<(), Cx::Error>

source

fn walk_stmt(&self, stmt: &Stmt<'_>) -> Result<(), Cx::Error>

source

fn maybe_read_scrutinee<'t>( &self, discr: &Expr<'_>, discr_place: PlaceWithHirId<'tcx>, pats: impl Iterator<Item = &'t Pat<'t>>, ) -> Result<(), Cx::Error>

source

fn walk_local<F>( &self, expr: &Expr<'_>, pat: &Pat<'_>, els: Option<&Block<'_>>, f: F, ) -> Result<(), Cx::Error>
where F: FnMut() -> Result<(), Cx::Error>,

source

fn walk_block(&self, blk: &Block<'_>) -> Result<(), Cx::Error>

Indicates that the value of blk will be consumed, meaning either copied or moved depending on its type.

source

fn walk_struct_expr<'hir>( &self, fields: &[ExprField<'_>], opt_with: &Option<&'hir Expr<'_>>, ) -> Result<(), Cx::Error>

source

fn walk_adjustment(&self, expr: &Expr<'_>) -> Result<(), Cx::Error>

Invoke the appropriate delegate calls for anything that gets consumed or borrowed as part of the automatic adjustment process.

source

fn walk_autoref( &self, expr: &Expr<'_>, base_place: &PlaceWithHirId<'tcx>, autoref: &AutoBorrow<'tcx>, )

Walks the autoref autoref applied to the autoderef’d expr. base_place is the mem-categorized form of expr after all relevant autoderefs have occurred.

source

fn walk_arm( &self, discr_place: &PlaceWithHirId<'tcx>, arm: &Arm<'_>, ) -> Result<(), Cx::Error>

source

fn walk_irrefutable_pat( &self, discr_place: &PlaceWithHirId<'tcx>, pat: &Pat<'_>, ) -> Result<(), Cx::Error>

Walks a pat that occurs in isolation (i.e., top-level of fn argument or let binding, and not a match arm or nested pat.)

source

fn walk_pat( &self, discr_place: &PlaceWithHirId<'tcx>, pat: &Pat<'_>, has_guard: bool, ) -> Result<(), Cx::Error>

The core driver for walking a pattern

source

fn walk_captures(&self, closure_expr: &Closure<'_>) -> Result<(), Cx::Error>

Handle the case where the current body contains a closure.

When the current body being handled is a closure, then we must make sure that

  • The parent closure only captures Places from the nested closure that are not local to it.

In the following example the closures c only captures p.x even though incr is a capture of the nested closure

struct P { x: i32 }
let mut p = P { x: 4 };
let c = || {
   let incr = 10;
   let nested = || p.x += incr;
};
  • When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing closure as the DefId.
source§

impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D>

The job of the categorization methods is to analyze an expression to determine what kind of memory is used in evaluating it (for example, where dereferences occur and what kind of pointer is dereferenced; whether the memory is mutable, etc.).

Categorization effectively transforms all of our expressions into expressions of the following forms (the actual enum has many more possibilities, naturally, but they are all variants of these base forms):

E = rvalue    // some computed rvalue
  | x         // address of a local variable or argument
  | *E        // deref of a ptr
  | E.comp    // access to an interior component

Imagine a routine ToAddr(Expr) that evaluates an expression and returns an address where the result is to be found. If Expr is a place, then this is the address of the place. If Expr is an rvalue, this is the address of some temporary spot in memory where the result is stored.

Now, cat_expr() classifies the expression Expr and the address A = ToAddr(Expr) as follows:

  • cat: what kind of expression was this? This is a subset of the full expression forms which only includes those that we care about for the purpose of the analysis.
  • mutbl: mutability of the address A.
  • ty: the type of data found at the address A.

The resulting categorization tree differs somewhat from the expressions themselves. For example, auto-derefs are explicit. Also, an index a[b] is decomposed into two operations: a dereference to reach the array data and then an index to jump forward to the relevant item.

§By-reference upvars

One part of the codegen which may be non-obvious is that we translate closure upvars into the dereference of a borrowed pointer; this more closely resembles the runtime codegen. So, for example, if we had:

let mut x = 3;
let y = 5;
let inc = || x += y;

Then when we categorize x (within the closure) we would yield a result of *x', effectively, where x' is a Categorization::Upvar reference tied to x. The type of x' will be a borrowed pointer.

source

fn resolve_type_vars_or_error( &self, id: HirId, ty: Option<Ty<'tcx>>, ) -> Result<Ty<'tcx>, Cx::Error>

source

fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, Cx::Error>

source

fn expr_ty(&self, expr: &Expr<'_>) -> Result<Ty<'tcx>, Cx::Error>

source

fn expr_ty_adjusted(&self, expr: &Expr<'_>) -> Result<Ty<'tcx>, Cx::Error>

source

fn pat_ty_adjusted(&self, pat: &Pat<'_>) -> Result<Ty<'tcx>, Cx::Error>

Returns the type of value that this pattern matches against. Some non-obvious cases:

  • a ref x binding matches against a value of type T and gives x the type &T; we return T.
  • a pattern with implicit derefs (thanks to default binding modes #42640) may look like Some(x) but in fact have implicit deref patterns attached (e.g., it is really &Some(x)). In that case, we return the “outermost” type (e.g., &Option<T>).
source

fn pat_ty_unadjusted(&self, pat: &Pat<'_>) -> Result<Ty<'tcx>, Cx::Error>

Like TypeckResults::pat_ty, but ignores implicit & patterns.

source

fn cat_expr(&self, expr: &Expr<'_>) -> Result<PlaceWithHirId<'tcx>, Cx::Error>

source

fn cat_expr_( &self, expr: &Expr<'_>, adjustments: &[Adjustment<'tcx>], ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>

This recursion helper avoids going through too many adjustments, since only non-overloaded deref recurses.

source

fn cat_expr_adjusted( &self, expr: &Expr<'_>, previous: PlaceWithHirId<'tcx>, adjustment: &Adjustment<'tcx>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>

source

fn cat_expr_adjusted_with<F>( &self, expr: &Expr<'_>, previous: F, adjustment: &Adjustment<'tcx>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
where F: FnOnce() -> Result<PlaceWithHirId<'tcx>, Cx::Error>,

source

fn cat_expr_unadjusted( &self, expr: &Expr<'_>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>

source

fn cat_res( &self, hir_id: HirId, span: Span, expr_ty: Ty<'tcx>, res: Res, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>

source

fn cat_upvar( &self, hir_id: HirId, var_id: HirId, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>

Categorize an upvar.

Note: the actual upvar access contains invisible derefs of closure environment and upvar reference as appropriate. Only regionck cares about these dereferences, so we let it compute them as needed.

source

fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx>

source

fn cat_projection( &self, node: HirId, base_place: PlaceWithHirId<'tcx>, ty: Ty<'tcx>, kind: ProjectionKind, ) -> PlaceWithHirId<'tcx>

source

fn cat_overloaded_place( &self, expr: &Expr<'_>, base: &Expr<'_>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>

source

fn cat_deref( &self, node: HirId, base_place: PlaceWithHirId<'tcx>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>

source

fn variant_index_for_adt( &self, qpath: &QPath<'_>, pat_hir_id: HirId, span: Span, ) -> Result<VariantIdx, Cx::Error>

Returns the variant index for an ADT used within a Struct or TupleStruct pattern Here pat_hir_id is the HirId of the pattern itself.

source

fn total_fields_in_adt_variant( &self, pat_hir_id: HirId, variant_index: VariantIdx, span: Span, ) -> Result<usize, Cx::Error>

Returns the total number of fields in an ADT variant used within a pattern. Here pat_hir_id is the HirId of the pattern itself.

source

fn total_fields_in_tuple( &self, pat_hir_id: HirId, span: Span, ) -> Result<usize, Cx::Error>

Returns the total number of fields in a tuple used within a Tuple pattern. Here pat_hir_id is the HirId of the pattern itself.

source

fn cat_pattern<F>( &self, place_with_id: PlaceWithHirId<'tcx>, pat: &Pat<'_>, op: &mut F, ) -> Result<(), Cx::Error>
where F: FnMut(&PlaceWithHirId<'tcx>, &Pat<'_>) -> Result<(), Cx::Error>,

Here, place is the PlaceWithHirId being matched and pat is the pattern it is being matched against.

In general, the way that this works is that we walk down the pattern, constructing a PlaceWithHirId that represents the path that will be taken to reach the value being matched.

source

fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool

Auto Trait Implementations§

§

impl<'tcx, Cx, D> DynSend for ExprUseVisitor<'tcx, Cx, D>
where Cx: DynSend, D: DynSend,

§

impl<'tcx, Cx, D> !DynSync for ExprUseVisitor<'tcx, Cx, D>

§

impl<'tcx, Cx, D> !Freeze for ExprUseVisitor<'tcx, Cx, D>

§

impl<'tcx, Cx, D> !RefUnwindSafe for ExprUseVisitor<'tcx, Cx, D>

§

impl<'tcx, Cx, D> Send for ExprUseVisitor<'tcx, Cx, D>
where Cx: Send, D: Send,

§

impl<'tcx, Cx, D> !Sync for ExprUseVisitor<'tcx, Cx, D>

§

impl<'tcx, Cx, D> Unpin for ExprUseVisitor<'tcx, Cx, D>
where Cx: Unpin, D: Unpin,

§

impl<'tcx, Cx, D> UnwindSafe for ExprUseVisitor<'tcx, Cx, D>
where Cx: UnwindSafe, D: UnwindSafe,

Blanket Implementations§

source§

impl<T> Aligned for T

source§

const ALIGN: Alignment = _

Alignment of Self.
source§

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

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

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

source§

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

Mutably borrows from an owned value. Read more
source§

impl<T, R> CollectAndApply<T, R> for T

source§

fn collect_and_apply<I, F>(iter: I, f: F) -> R
where I: Iterator<Item = T>, F: FnOnce(&[T]) -> R,

Equivalent to f(&iter.collect::<Vec<_>>()).

§

type Output = R

source§

impl<T> Filterable for T

source§

fn filterable( self, filter_name: &'static str, ) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>

Creates a filterable data provider with the given name for debugging. 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 T
where 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> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

impl<P> IntoQueryParam<P> for P

source§

impl<T> MaybeResult<T> for T

§

type Error = !

source§

fn from(_: Result<T, <T as MaybeResult<T>>::Error>) -> T

source§

fn to_result(self) -> Result<T, <T as MaybeResult<T>>::Error>

source§

impl<T> Pointable for T

source§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for T
where 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 T
where 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<I, T, U> Upcast<I, U> for T
where U: UpcastFrom<I, T>,

source§

fn upcast(self, interner: I) -> U

source§

impl<I, T> UpcastFrom<I, T> for T

source§

fn upcast_from(from: T, _tcx: I) -> T

source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V

source§

impl<Tcx, T> Value<Tcx> for T
where Tcx: DepContext,

source§

default fn from_cycle_error( tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed, ) -> T

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
source§

impl<'a, T> Captures<'a> for T
where T: ?Sized,

source§

impl<T> ErasedDestructor for T
where T: 'static,

Layout§

Note: Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.