pub(crate) struct ExprUseVisitor<'a, 'db, D: Delegate<'db>> {
cx: &'a mut InferenceContext<'db>,
delegate: D,
closure_expr: ExprId,
upvars: UpvarsRef<'db>,
}Expand description
A visitor that reports how each expression is being used.
See module-level docs and Delegate for details.
Fields§
§cx: &'a mut InferenceContext<'db>§delegate: D§closure_expr: ExprId§upvars: UpvarsRef<'db>Implementations§
Source§impl<'a, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'db, D>
impl<'a, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'db, D>
Sourcepub(crate) fn new(
cx: &'a mut InferenceContext<'db>,
closure_expr: ExprId,
upvars: UpvarsRef<'db>,
delegate: D,
) -> Self
pub(crate) fn new( cx: &'a mut InferenceContext<'db>, closure_expr: ExprId, upvars: UpvarsRef<'db>, delegate: D, ) -> Self
Creates the ExprUseVisitor, configuring it with the various options provided:
delegate– who receives the callbacksparam_env— parameter environment for trait lookups (esp. pertaining toCopy)typeck_results— typeck results for the code being analyzed
pub(crate) fn consume_closure_body( &mut self, params: &[PatId], body: ExprId, ) -> Result<(), ErrorGuaranteed>
fn consume_or_copy(&mut self, place_with_id: PlaceWithOrigin)
pub(crate) fn consume_clone_or_copy(&mut self, place_with_id: PlaceWithOrigin)
fn consume_exprs(&mut self, exprs: &[ExprId]) -> Result<(), ErrorGuaranteed>
pub(crate) fn consume_expr( &mut self, expr: ExprId, ) -> Result<(), ErrorGuaranteed>
fn mutate_expr(&mut self, expr: ExprId) -> Result<(), ErrorGuaranteed>
fn borrow_expr( &mut self, expr: ExprId, bk: BorrowKind, ) -> Result<(), ErrorGuaranteed>
pub(crate) fn walk_expr(&mut self, expr: ExprId) -> Result<(), ErrorGuaranteed>
fn walk_stmt(&mut self, stmt: &Statement) -> Result<(), ErrorGuaranteed>
fn fake_read_scrutinee(&mut self, discr_place: PlaceWithOrigin, refutable: bool)
fn walk_local<F>( &mut self, expr: ExprId, pat: PatId, els: Option<ExprId>, f: F, ) -> Result<(), ErrorGuaranteed>
fn walk_struct_expr( &mut self, fields: &[RecordLitField], spread: RecordSpread, ) -> Result<(), ErrorGuaranteed>
fn expr_adjustments(&self, expr: ExprId) -> SmallVec<[Adjustment; 5]>
fn pat_adjustments(&self, pat: PatId) -> SmallVec<[PatAdjustment; 5]>
Sourcefn walk_adjustment(&mut self, expr: ExprId) -> Result<(), ErrorGuaranteed>
fn walk_adjustment(&mut self, expr: ExprId) -> Result<(), ErrorGuaranteed>
Invoke the appropriate delegate calls for anything that gets consumed or borrowed as part of the automatic adjustment process.
Sourcefn walk_autoref(
&mut self,
expr: ExprId,
base_place: PlaceWithOrigin,
autoref: &AutoBorrow,
)
fn walk_autoref( &mut self, expr: ExprId, base_place: PlaceWithOrigin, autoref: &AutoBorrow, )
Walks the autoref autoref applied to the autoderef’d
expr. base_place is expr represented as a place,
after all relevant autoderefs have occurred.
fn walk_arm( &mut self, discr_place: PlaceWithOrigin, arm: &MatchArm, ) -> Result<(), ErrorGuaranteed>
Sourcefn walk_pat(
&mut self,
discr_place: PlaceWithOrigin,
pat: PatId,
has_guard: bool,
) -> Result<(), ErrorGuaranteed>
fn walk_pat( &mut self, discr_place: PlaceWithOrigin, pat: PatId, has_guard: bool, ) -> Result<(), ErrorGuaranteed>
The core driver for walking a pattern
This should mirror how pattern-matching gets lowered to MIR, as otherwise lowering will ICE when trying to resolve the upvars.
However, it is okay to approximate it here by doing more accesses than
the actual MIR builder will, which is useful when some checks are too
cumbersome to perform here. For example, if after typeck it becomes
clear that only one variant of an enum is inhabited, and therefore a
read of the discriminant is not necessary, walk_pat will have
over-approximated the necessary upvar capture granularity.
Do note that discrepancies like these do still create obscure corners in the semantics of the language, and should be avoided if possible.
Sourcefn walk_captures(&mut self, closure_expr: ExprId)
fn walk_captures(&mut self, closure_expr: ExprId)
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.
fn error_reported_in_ty(&self, ty: Ty<'db>) -> Result<(), ErrorGuaranteed>
Source§impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, 'db, D>
The job of the methods whose name starts with cat_ is to analyze
expressions and construct the corresponding Places. The cat
stands for “categorize”, this is a leftover from long ago when
places were called “categorizations”.
impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, 'db, D>
The job of the methods whose name starts with cat_ is to analyze
expressions and construct the corresponding Places. The cat
stands for “categorize”, this is a leftover from long ago when
places were called “categorizations”.
Note that a Place differs somewhat from the expression itself. 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.
fn expect_and_resolve_type( &mut self, ty: Option<Ty<'db>>, ) -> Result<Ty<'db>, ErrorGuaranteed>
fn node_ty(&mut self, id: ExprOrPatId) -> Result<Ty<'db>, ErrorGuaranteed>
fn expr_ty(&mut self, expr: ExprId) -> Result<Ty<'db>, ErrorGuaranteed>
fn expr_ty_adjusted(&mut self, expr: ExprId) -> Result<Ty<'db>, ErrorGuaranteed>
Sourcefn pat_ty_adjusted(&mut self, pat: PatId) -> Result<Ty<'db>, ErrorGuaranteed>
fn pat_ty_adjusted(&mut self, pat: PatId) -> Result<Ty<'db>, ErrorGuaranteed>
Returns the type of value that this pattern matches against. Some non-obvious cases:
- a
ref xbinding matches against a value of typeTand givesxthe type&T; we returnT. - 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>).
Sourcefn pat_ty_unadjusted(&mut self, pat: PatId) -> Result<Ty<'db>, ErrorGuaranteed>
fn pat_ty_unadjusted(&mut self, pat: PatId) -> Result<Ty<'db>, ErrorGuaranteed>
Like Self::pat_ty_adjusted, but ignores implicit & patterns.
fn cat_expr(&mut self, expr: ExprId) -> Result<PlaceWithOrigin, ErrorGuaranteed>
Sourcefn cat_expr_(
&mut self,
expr: ExprId,
adjustments: &[Adjustment],
) -> Result<PlaceWithOrigin, ErrorGuaranteed>
fn cat_expr_( &mut self, expr: ExprId, adjustments: &[Adjustment], ) -> Result<PlaceWithOrigin, ErrorGuaranteed>
This recursion helper avoids going through too many adjustments, since only non-overloaded deref recurses.
fn cat_expr_adjusted( &mut self, expr: ExprId, previous: PlaceWithOrigin, adjustment: &Adjustment, ) -> Result<PlaceWithOrigin, ErrorGuaranteed>
fn cat_expr_adjusted_with<F>( &mut self, expr: ExprId, previous: F, adjustment: &Adjustment, ) -> Result<PlaceWithOrigin, ErrorGuaranteed>
fn cat_expr_unadjusted( &mut self, expr: ExprId, ) -> Result<PlaceWithOrigin, ErrorGuaranteed>
fn cat_local( &mut self, id: ExprOrPatIdPacked, expr_ty: Ty<'db>, var_id: BindingId, ) -> Result<PlaceWithOrigin, ErrorGuaranteed>
Sourcefn cat_upvar(
&mut self,
hir_id: ExprOrPatIdPacked,
var_id: BindingId,
) -> Result<PlaceWithOrigin, ErrorGuaranteed>
fn cat_upvar( &mut self, hir_id: ExprOrPatIdPacked, var_id: BindingId, ) -> Result<PlaceWithOrigin, ErrorGuaranteed>
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.
fn cat_rvalue( &self, hir_id: ExprOrPatIdPacked, expr_ty: Ty<'db>, ) -> PlaceWithOrigin
fn cat_projection( &self, node: ExprOrPatIdPacked, base_place: PlaceWithOrigin, ty: Ty<'db>, kind: ProjectionKind, ) -> PlaceWithOrigin
fn cat_overloaded_place( &mut self, expr: ExprId, base: ExprId, ) -> Result<PlaceWithOrigin, ErrorGuaranteed>
fn cat_deref( &mut self, node: ExprOrPatIdPacked, base_place: PlaceWithOrigin, ) -> Result<PlaceWithOrigin, ErrorGuaranteed>
Sourcefn variant_index_for_adt(
&self,
pat_id: PatId,
) -> Result<(u32, VariantId), ErrorGuaranteed>
fn variant_index_for_adt( &self, pat_id: PatId, ) -> Result<(u32, VariantId), ErrorGuaranteed>
Returns the variant index for an ADT used within a Struct or TupleStruct pattern
Here pat_hir_id is the ExprId of the pattern itself.
Sourcefn total_fields_in_tuple(&mut self, pat_id: PatId) -> usize
fn total_fields_in_tuple(&mut self, pat_id: PatId) -> usize
Returns the total number of fields in a tuple used within a Tuple pattern.
Here pat_hir_id is the ExprId of the pattern itself.
Sourcefn cat_pattern<F>(
&mut self,
place_with_id: PlaceWithOrigin,
pat: PatId,
op: &mut F,
) -> Result<(), ErrorGuaranteed>
fn cat_pattern<F>( &mut self, place_with_id: PlaceWithOrigin, pat: PatId, op: &mut F, ) -> Result<(), ErrorGuaranteed>
Here, place is the PlaceWithId 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 PlaceWithId that represents the path that will be taken
to reach the value being matched.
Sourcefn pat_deref_place(
&mut self,
node: ExprOrPatIdPacked,
base_place: PlaceWithOrigin,
inner: PatId,
target_ty: Ty<'db>,
) -> Result<PlaceWithOrigin, ErrorGuaranteed>
fn pat_deref_place( &mut self, node: ExprOrPatIdPacked, base_place: PlaceWithOrigin, inner: PatId, target_ty: Ty<'db>, ) -> Result<PlaceWithOrigin, ErrorGuaranteed>
Represents the place matched on by a deref pattern’s interior.
Sourcefn is_multivariant_adt(&mut self, node: ExprOrPatIdPacked, ty: Ty<'db>) -> bool
fn is_multivariant_adt(&mut self, node: ExprOrPatIdPacked, ty: Ty<'db>) -> bool
Checks whether a type has multiple variants, and therefore, whether a read of the discriminant might be necessary. Note that the actual MIR builder code does a more specific check, filtering out variants that happen to be uninhabited.
Here, it is not practical to perform such a check, because inhabitedness queries require typeck results, and typeck requires closure capture analysis.
Moreover, the language is moving towards uninhabited variants still semantically causing a discriminant read, so we shouldn’t perform any such check.
FIXME(never_patterns): update this comment once the aforementioned MIR builder code is changed to be insensitive to inhhabitedness.
Auto Trait Implementations§
impl<'a, 'db, D> Freeze for ExprUseVisitor<'a, 'db, D>where
D: Freeze,
impl<'a, 'db, D> !RefUnwindSafe for ExprUseVisitor<'a, 'db, D>
impl<'a, 'db, D> !Send for ExprUseVisitor<'a, 'db, D>
impl<'a, 'db, D> !Sync for ExprUseVisitor<'a, 'db, D>
impl<'a, 'db, D> Unpin for ExprUseVisitor<'a, 'db, D>where
D: Unpin,
impl<'a, 'db, D> UnsafeUnpin for ExprUseVisitor<'a, 'db, D>where
D: UnsafeUnpin,
impl<'a, 'db, D> !UnwindSafe for ExprUseVisitor<'a, 'db, D>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T, R> CollectAndApply<T, R> for T
impl<T, R> CollectAndApply<T, R> for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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