Skip to content

Commit 03c6f83

Browse files
authored
Rollup merge of rust-lang#139086 - meithecatte:expr-use-visitor-cleanup, r=compiler-errors
Various cleanup in ExprUseVisitor These are the non-behavior-changing commits from rust-lang#138961.
2 parents 586f90c + 908504e commit 03c6f83

File tree

3 files changed

+62
-100
lines changed

3 files changed

+62
-100
lines changed

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+49-93
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! A different sort of visitor for walking fn bodies. Unlike the
22
//! normal visitor, which just walks the entire body in one shot, the
33
//! `ExprUseVisitor` determines how expressions are being used.
4+
//!
5+
//! In the compiler, this is only used for upvar inference, but there
6+
//! are many uses within clippy.
47
58
use std::cell::{Ref, RefCell};
69
use std::ops::Deref;
@@ -25,7 +28,7 @@ use rustc_middle::ty::{
2528
use rustc_middle::{bug, span_bug};
2629
use rustc_span::{ErrorGuaranteed, Span};
2730
use rustc_trait_selection::infer::InferCtxtExt;
28-
use tracing::{debug, trace};
31+
use tracing::{debug, instrument, trace};
2932

3033
use crate::fn_ctxt::FnCtxt;
3134

@@ -35,11 +38,8 @@ pub trait Delegate<'tcx> {
3538
/// The value found at `place` is moved, depending
3639
/// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
3740
///
38-
/// Use of a `Copy` type in a ByValue context is considered a use
39-
/// by `ImmBorrow` and `borrow` is called instead. This is because
40-
/// a shared borrow is the "minimum access" that would be needed
41-
/// to perform a copy.
42-
///
41+
/// If the value is `Copy`, [`copy`][Self::copy] is called instead, which
42+
/// by default falls back to [`borrow`][Self::borrow].
4343
///
4444
/// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
4545
/// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
@@ -73,6 +73,10 @@ pub trait Delegate<'tcx> {
7373

7474
/// The value found at `place` is being copied.
7575
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
76+
///
77+
/// If an implementation is not provided, use of a `Copy` type in a ByValue context is instead
78+
/// considered a use by `ImmBorrow` and `borrow` is called instead. This is because a shared
79+
/// borrow is the "minimum access" that would be needed to perform a copy.
7680
fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
7781
// In most cases, copying data from `x` is equivalent to doing `*&x`, so by default
7882
// we treat a copy of `x` as a borrow of `x`.
@@ -141,6 +145,8 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
141145
}
142146
}
143147

148+
/// This trait makes `ExprUseVisitor` usable with both [`FnCtxt`]
149+
/// and [`LateContext`], depending on where in the compiler it is used.
144150
pub trait TypeInformationCtxt<'tcx> {
145151
type TypeckResults<'a>: Deref<Target = ty::TypeckResults<'tcx>>
146152
where
@@ -154,7 +160,7 @@ pub trait TypeInformationCtxt<'tcx> {
154160

155161
fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
156162

157-
fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error;
163+
fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error;
158164

159165
fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error>;
160166

@@ -189,7 +195,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
189195
(**self).try_structurally_resolve_type(sp, ty)
190196
}
191197

192-
fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error {
198+
fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error {
193199
self.dcx().span_delayed_bug(span, msg.to_string())
194200
}
195201

@@ -239,7 +245,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
239245
t
240246
}
241247

242-
fn report_error(&self, span: Span, msg: impl ToString) -> ! {
248+
fn report_bug(&self, span: Span, msg: impl ToString) -> ! {
243249
span_bug!(span, "{}", msg.to_string())
244250
}
245251

@@ -268,9 +274,9 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
268274
}
269275
}
270276

271-
/// The ExprUseVisitor type
277+
/// A visitor that reports how each expression is being used.
272278
///
273-
/// This is the code that actually walks the tree.
279+
/// See [module-level docs][self] and [`Delegate`] for details.
274280
pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
275281
cx: Cx,
276282
/// We use a `RefCell` here so that delegates can mutate themselves, but we can
@@ -314,19 +320,17 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
314320
Ok(())
315321
}
316322

323+
#[instrument(skip(self), level = "debug")]
317324
fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
318-
debug!("delegate_consume(place_with_id={:?})", place_with_id);
319-
320325
if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
321326
self.delegate.borrow_mut().copy(place_with_id, diag_expr_id);
322327
} else {
323328
self.delegate.borrow_mut().consume(place_with_id, diag_expr_id);
324329
}
325330
}
326331

332+
#[instrument(skip(self), level = "debug")]
327333
pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
328-
debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id);
329-
330334
// `x.use` will do one of the following
331335
// * if it implements `Copy`, it will be a copy
332336
// * if it implements `UseCloned`, it will be a call to `clone`
@@ -351,18 +355,16 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
351355
}
352356

353357
// FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`.
358+
#[instrument(skip(self), level = "debug")]
354359
pub fn consume_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
355-
debug!("consume_expr(expr={:?})", expr);
356-
357360
let place_with_id = self.cat_expr(expr)?;
358361
self.consume_or_copy(&place_with_id, place_with_id.hir_id);
359362
self.walk_expr(expr)?;
360363
Ok(())
361364
}
362365

366+
#[instrument(skip(self), level = "debug")]
363367
pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
364-
debug!("consume_or_clone_expr(expr={:?})", expr);
365-
366368
let place_with_id = self.cat_expr(expr)?;
367369
self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
368370
self.walk_expr(expr)?;
@@ -376,17 +378,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
376378
Ok(())
377379
}
378380

381+
#[instrument(skip(self), level = "debug")]
379382
fn borrow_expr(&self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) -> Result<(), Cx::Error> {
380-
debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk);
381-
382383
let place_with_id = self.cat_expr(expr)?;
383384
self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
384385
self.walk_expr(expr)
385386
}
386387

388+
#[instrument(skip(self), level = "debug")]
387389
pub fn walk_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
388-
debug!("walk_expr(expr={:?})", expr);
389-
390390
self.walk_adjustment(expr)?;
391391

392392
match expr.kind {
@@ -733,9 +733,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
733733

734734
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved
735735
/// depending on its type.
736+
#[instrument(skip(self), level = "debug")]
736737
fn walk_block(&self, blk: &hir::Block<'_>) -> Result<(), Cx::Error> {
737-
debug!("walk_block(blk.hir_id={})", blk.hir_id);
738-
739738
for stmt in blk.stmts {
740739
self.walk_stmt(stmt)?;
741740
}
@@ -861,7 +860,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
861860
}
862861

863862
/// Walks the autoref `autoref` applied to the autoderef'd
864-
/// `expr`. `base_place` is the mem-categorized form of `expr`
863+
/// `expr`. `base_place` is `expr` represented as a place,
865864
/// after all relevant autoderefs have occurred.
866865
fn walk_autoref(
867866
&self,
@@ -942,14 +941,13 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
942941
}
943942

944943
/// The core driver for walking a pattern
944+
#[instrument(skip(self), level = "debug")]
945945
fn walk_pat(
946946
&self,
947947
discr_place: &PlaceWithHirId<'tcx>,
948948
pat: &hir::Pat<'_>,
949949
has_guard: bool,
950950
) -> Result<(), Cx::Error> {
951-
debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard);
952-
953951
let tcx = self.cx.tcx();
954952
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
955953
match pat.kind {
@@ -1042,6 +1040,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
10421040
///
10431041
/// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
10441042
/// closure as the DefId.
1043+
#[instrument(skip(self), level = "debug")]
10451044
fn walk_captures(&self, closure_expr: &hir::Closure<'_>) -> Result<(), Cx::Error> {
10461045
fn upvar_is_local_variable(
10471046
upvars: Option<&FxIndexMap<HirId, hir::Upvar>>,
@@ -1051,8 +1050,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
10511050
upvars.map(|upvars| !upvars.contains_key(&upvar_id)).unwrap_or(body_owner_is_closure)
10521051
}
10531052

1054-
debug!("walk_captures({:?})", closure_expr);
1055-
10561053
let tcx = self.cx.tcx();
10571054
let closure_def_id = closure_expr.def_id;
10581055
// For purposes of this function, coroutine and closures are equivalent.
@@ -1164,55 +1161,17 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
11641161
}
11651162
}
11661163

1167-
/// The job of the categorization methods is to analyze an expression to
1168-
/// determine what kind of memory is used in evaluating it (for example,
1169-
/// where dereferences occur and what kind of pointer is dereferenced;
1170-
/// whether the memory is mutable, etc.).
1171-
///
1172-
/// Categorization effectively transforms all of our expressions into
1173-
/// expressions of the following forms (the actual enum has many more
1174-
/// possibilities, naturally, but they are all variants of these base
1175-
/// forms):
1176-
/// ```ignore (not-rust)
1177-
/// E = rvalue // some computed rvalue
1178-
/// | x // address of a local variable or argument
1179-
/// | *E // deref of a ptr
1180-
/// | E.comp // access to an interior component
1181-
/// ```
1182-
/// Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
1183-
/// address where the result is to be found. If Expr is a place, then this
1184-
/// is the address of the place. If `Expr` is an rvalue, this is the address of
1185-
/// some temporary spot in memory where the result is stored.
1186-
///
1187-
/// Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)`
1188-
/// as follows:
1189-
///
1190-
/// - `cat`: what kind of expression was this? This is a subset of the
1191-
/// full expression forms which only includes those that we care about
1192-
/// for the purpose of the analysis.
1193-
/// - `mutbl`: mutability of the address `A`.
1194-
/// - `ty`: the type of data found at the address `A`.
1164+
/// The job of the methods whose name starts with `cat_` is to analyze
1165+
/// expressions and construct the corresponding [`Place`]s. The `cat`
1166+
/// stands for "categorize", this is a leftover from long ago when
1167+
/// places were called "categorizations".
11951168
///
1196-
/// The resulting categorization tree differs somewhat from the expressions
1197-
/// themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is
1198-
/// decomposed into two operations: a dereference to reach the array data and
1199-
/// then an index to jump forward to the relevant item.
1200-
///
1201-
/// ## By-reference upvars
1202-
///
1203-
/// One part of the codegen which may be non-obvious is that we translate
1204-
/// closure upvars into the dereference of a borrowed pointer; this more closely
1205-
/// resembles the runtime codegen. So, for example, if we had:
1206-
///
1207-
/// let mut x = 3;
1208-
/// let y = 5;
1209-
/// let inc = || x += y;
1210-
///
1211-
/// Then when we categorize `x` (*within* the closure) we would yield a
1212-
/// result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
1213-
/// tied to `x`. The type of `x'` will be a borrowed pointer.
1169+
/// Note that a [`Place`] differs somewhat from the expression itself. For
1170+
/// example, auto-derefs are explicit. Also, an index `a[b]` is decomposed into
1171+
/// two operations: a dereference to reach the array data and then an index to
1172+
/// jump forward to the relevant item.
12141173
impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
1215-
fn resolve_type_vars_or_error(
1174+
fn resolve_type_vars_or_bug(
12161175
&self,
12171176
id: HirId,
12181177
ty: Option<Ty<'tcx>>,
@@ -1222,35 +1181,32 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
12221181
let ty = self.cx.resolve_vars_if_possible(ty);
12231182
self.cx.error_reported_in_ty(ty)?;
12241183
if ty.is_ty_var() {
1225-
debug!("resolve_type_vars_or_error: infer var from {:?}", ty);
1184+
debug!("resolve_type_vars_or_bug: infer var from {:?}", ty);
12261185
Err(self
12271186
.cx
1228-
.report_error(self.cx.tcx().hir().span(id), "encountered type variable"))
1187+
.report_bug(self.cx.tcx().hir().span(id), "encountered type variable"))
12291188
} else {
12301189
Ok(ty)
12311190
}
12321191
}
12331192
None => {
12341193
// FIXME: We shouldn't be relying on the infcx being tainted.
12351194
self.cx.tainted_by_errors()?;
1236-
bug!(
1237-
"no type for node {} in mem_categorization",
1238-
self.cx.tcx().hir_id_to_string(id)
1239-
);
1195+
bug!("no type for node {} in ExprUseVisitor", self.cx.tcx().hir_id_to_string(id));
12401196
}
12411197
}
12421198
}
12431199

12441200
fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, Cx::Error> {
1245-
self.resolve_type_vars_or_error(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
1201+
self.resolve_type_vars_or_bug(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
12461202
}
12471203

12481204
fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1249-
self.resolve_type_vars_or_error(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
1205+
self.resolve_type_vars_or_bug(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
12501206
}
12511207

12521208
fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1253-
self.resolve_type_vars_or_error(
1209+
self.resolve_type_vars_or_bug(
12541210
expr.hir_id,
12551211
self.cx.typeck_results().expr_ty_adjusted_opt(expr),
12561212
)
@@ -1285,7 +1241,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
12851241
self.pat_ty_unadjusted(pat)
12861242
}
12871243

1288-
/// Like `TypeckResults::pat_ty`, but ignores implicit `&` patterns.
1244+
/// Like [`Self::pat_ty_adjusted`], but ignores implicit `&` patterns.
12891245
fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, Cx::Error> {
12901246
let base_ty = self.node_ty(pat.hir_id)?;
12911247
trace!(?base_ty);
@@ -1315,7 +1271,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
13151271
debug!("By-ref binding of non-derefable type");
13161272
Err(self
13171273
.cx
1318-
.report_error(pat.span, "by-ref binding of non-derefable type"))
1274+
.report_bug(pat.span, "by-ref binding of non-derefable type"))
13191275
}
13201276
}
13211277
} else {
@@ -1511,7 +1467,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
15111467
}
15121468
}
15131469

1514-
def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def),
1470+
def => span_bug!(span, "unexpected definition in ExprUseVisitor: {:?}", def),
15151471
}
15161472
}
15171473

@@ -1604,7 +1560,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
16041560
Some(ty) => ty,
16051561
None => {
16061562
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
1607-
return Err(self.cx.report_error(
1563+
return Err(self.cx.report_bug(
16081564
self.cx.tcx().hir().span(node),
16091565
"explicit deref of non-derefable type",
16101566
));
@@ -1629,7 +1585,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
16291585
let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else {
16301586
return Err(self
16311587
.cx
1632-
.report_error(span, "struct or tuple struct pattern not applied to an ADT"));
1588+
.report_bug(span, "struct or tuple struct pattern not applied to an ADT"));
16331589
};
16341590

16351591
match res {
@@ -1675,7 +1631,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
16751631
let ty = self.cx.typeck_results().node_type(pat_hir_id);
16761632
match self.cx.try_structurally_resolve_type(span, ty).kind() {
16771633
ty::Tuple(args) => Ok(args.len()),
1678-
_ => Err(self.cx.report_error(span, "tuple pattern not applied to a tuple")),
1634+
_ => Err(self.cx.report_bug(span, "tuple pattern not applied to a tuple")),
16791635
}
16801636
}
16811637

@@ -1854,7 +1810,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
18541810
debug!("explicit index of non-indexable type {:?}", place_with_id);
18551811
return Err(self
18561812
.cx
1857-
.report_error(pat.span, "explicit index of non-indexable type"));
1813+
.report_bug(pat.span, "explicit index of non-indexable type"));
18581814
};
18591815
let elt_place = self.cat_projection(
18601816
pat.hir_id,

compiler/rustc_hir_typeck/src/upvar.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
//! from there).
1919
//!
2020
//! The fact that we are inferring borrow kinds as we go results in a
21-
//! semi-hacky interaction with mem-categorization. In particular,
22-
//! mem-categorization will query the current borrow kind as it
23-
//! categorizes, and we'll return the *current* value, but this may get
21+
//! semi-hacky interaction with the way `ExprUseVisitor` is computing
22+
//! `Place`s. In particular, it will query the current borrow kind as it
23+
//! goes, and we'll return the *current* value, but this may get
2424
//! adjusted later. Therefore, in this module, we generally ignore the
25-
//! borrow kind (and derived mutabilities) that are returned from
26-
//! mem-categorization, since they may be inaccurate. (Another option
25+
//! borrow kind (and derived mutabilities) that `ExprUseVisitor` returns
26+
//! within `Place`s, since they may be inaccurate. (Another option
2727
//! would be to use a unification scheme, where instead of returning a
2828
//! concrete borrow kind like `ty::ImmBorrow`, we return a
2929
//! `ty::InferBorrow(upvar_id)` or something like that, but this would

0 commit comments

Comments
 (0)