1
1
//! A different sort of visitor for walking fn bodies. Unlike the
2
2
//! normal visitor, which just walks the entire body in one shot, the
3
3
//! `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.
4
7
5
8
use std:: cell:: { Ref , RefCell } ;
6
9
use std:: ops:: Deref ;
@@ -25,7 +28,7 @@ use rustc_middle::ty::{
25
28
use rustc_middle:: { bug, span_bug} ;
26
29
use rustc_span:: { ErrorGuaranteed , Span } ;
27
30
use rustc_trait_selection:: infer:: InferCtxtExt ;
28
- use tracing:: { debug, trace} ;
31
+ use tracing:: { debug, instrument , trace} ;
29
32
30
33
use crate :: fn_ctxt:: FnCtxt ;
31
34
@@ -35,11 +38,8 @@ pub trait Delegate<'tcx> {
35
38
/// The value found at `place` is moved, depending
36
39
/// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
37
40
///
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].
43
43
///
44
44
/// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
45
45
/// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
@@ -73,6 +73,10 @@ pub trait Delegate<'tcx> {
73
73
74
74
/// The value found at `place` is being copied.
75
75
/// `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.
76
80
fn copy ( & mut self , place_with_id : & PlaceWithHirId < ' tcx > , diag_expr_id : HirId ) {
77
81
// In most cases, copying data from `x` is equivalent to doing `*&x`, so by default
78
82
// 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 {
141
145
}
142
146
}
143
147
148
+ /// This trait makes `ExprUseVisitor` usable with both [`FnCtxt`]
149
+ /// and [`LateContext`], depending on where in the compiler it is used.
144
150
pub trait TypeInformationCtxt < ' tcx > {
145
151
type TypeckResults < ' a > : Deref < Target = ty:: TypeckResults < ' tcx > >
146
152
where
@@ -154,7 +160,7 @@ pub trait TypeInformationCtxt<'tcx> {
154
160
155
161
fn try_structurally_resolve_type ( & self , span : Span , ty : Ty < ' tcx > ) -> Ty < ' tcx > ;
156
162
157
- fn report_error ( & self , span : Span , msg : impl ToString ) -> Self :: Error ;
163
+ fn report_bug ( & self , span : Span , msg : impl ToString ) -> Self :: Error ;
158
164
159
165
fn error_reported_in_ty ( & self , ty : Ty < ' tcx > ) -> Result < ( ) , Self :: Error > ;
160
166
@@ -189,7 +195,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
189
195
( * * self ) . try_structurally_resolve_type ( sp, ty)
190
196
}
191
197
192
- fn report_error ( & self , span : Span , msg : impl ToString ) -> Self :: Error {
198
+ fn report_bug ( & self , span : Span , msg : impl ToString ) -> Self :: Error {
193
199
self . dcx ( ) . span_delayed_bug ( span, msg. to_string ( ) )
194
200
}
195
201
@@ -239,7 +245,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
239
245
t
240
246
}
241
247
242
- fn report_error ( & self , span : Span , msg : impl ToString ) -> ! {
248
+ fn report_bug ( & self , span : Span , msg : impl ToString ) -> ! {
243
249
span_bug ! ( span, "{}" , msg. to_string( ) )
244
250
}
245
251
@@ -268,9 +274,9 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
268
274
}
269
275
}
270
276
271
- /// The ExprUseVisitor type
277
+ /// A visitor that reports how each expression is being used.
272
278
///
273
- /// This is the code that actually walks the tree .
279
+ /// See [module-level docs][self] and [`Delegate`] for details .
274
280
pub struct ExprUseVisitor < ' tcx , Cx : TypeInformationCtxt < ' tcx > , D : Delegate < ' tcx > > {
275
281
cx : Cx ,
276
282
/// 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
314
320
Ok ( ( ) )
315
321
}
316
322
323
+ #[ instrument( skip( self ) , level = "debug" ) ]
317
324
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
-
320
325
if self . cx . type_is_copy_modulo_regions ( place_with_id. place . ty ( ) ) {
321
326
self . delegate . borrow_mut ( ) . copy ( place_with_id, diag_expr_id) ;
322
327
} else {
323
328
self . delegate . borrow_mut ( ) . consume ( place_with_id, diag_expr_id) ;
324
329
}
325
330
}
326
331
332
+ #[ instrument( skip( self ) , level = "debug" ) ]
327
333
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
-
330
334
// `x.use` will do one of the following
331
335
// * if it implements `Copy`, it will be a copy
332
336
// * 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
351
355
}
352
356
353
357
// FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`.
358
+ #[ instrument( skip( self ) , level = "debug" ) ]
354
359
pub fn consume_expr ( & self , expr : & hir:: Expr < ' _ > ) -> Result < ( ) , Cx :: Error > {
355
- debug ! ( "consume_expr(expr={:?})" , expr) ;
356
-
357
360
let place_with_id = self . cat_expr ( expr) ?;
358
361
self . consume_or_copy ( & place_with_id, place_with_id. hir_id ) ;
359
362
self . walk_expr ( expr) ?;
360
363
Ok ( ( ) )
361
364
}
362
365
366
+ #[ instrument( skip( self ) , level = "debug" ) ]
363
367
pub fn consume_or_clone_expr ( & self , expr : & hir:: Expr < ' _ > ) -> Result < ( ) , Cx :: Error > {
364
- debug ! ( "consume_or_clone_expr(expr={:?})" , expr) ;
365
-
366
368
let place_with_id = self . cat_expr ( expr) ?;
367
369
self . consume_clone_or_copy ( & place_with_id, place_with_id. hir_id ) ;
368
370
self . walk_expr ( expr) ?;
@@ -376,17 +378,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
376
378
Ok ( ( ) )
377
379
}
378
380
381
+ #[ instrument( skip( self ) , level = "debug" ) ]
379
382
fn borrow_expr ( & self , expr : & hir:: Expr < ' _ > , bk : ty:: BorrowKind ) -> Result < ( ) , Cx :: Error > {
380
- debug ! ( "borrow_expr(expr={:?}, bk={:?})" , expr, bk) ;
381
-
382
383
let place_with_id = self . cat_expr ( expr) ?;
383
384
self . delegate . borrow_mut ( ) . borrow ( & place_with_id, place_with_id. hir_id , bk) ;
384
385
self . walk_expr ( expr)
385
386
}
386
387
388
+ #[ instrument( skip( self ) , level = "debug" ) ]
387
389
pub fn walk_expr ( & self , expr : & hir:: Expr < ' _ > ) -> Result < ( ) , Cx :: Error > {
388
- debug ! ( "walk_expr(expr={:?})" , expr) ;
389
-
390
390
self . walk_adjustment ( expr) ?;
391
391
392
392
match expr. kind {
@@ -733,9 +733,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
733
733
734
734
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved
735
735
/// depending on its type.
736
+ #[ instrument( skip( self ) , level = "debug" ) ]
736
737
fn walk_block ( & self , blk : & hir:: Block < ' _ > ) -> Result < ( ) , Cx :: Error > {
737
- debug ! ( "walk_block(blk.hir_id={})" , blk. hir_id) ;
738
-
739
738
for stmt in blk. stmts {
740
739
self . walk_stmt ( stmt) ?;
741
740
}
@@ -861,7 +860,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
861
860
}
862
861
863
862
/// 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,
865
864
/// after all relevant autoderefs have occurred.
866
865
fn walk_autoref (
867
866
& self ,
@@ -942,14 +941,13 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
942
941
}
943
942
944
943
/// The core driver for walking a pattern
944
+ #[ instrument( skip( self ) , level = "debug" ) ]
945
945
fn walk_pat (
946
946
& self ,
947
947
discr_place : & PlaceWithHirId < ' tcx > ,
948
948
pat : & hir:: Pat < ' _ > ,
949
949
has_guard : bool ,
950
950
) -> Result < ( ) , Cx :: Error > {
951
- debug ! ( "walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})" , discr_place, pat, has_guard) ;
952
-
953
951
let tcx = self . cx . tcx ( ) ;
954
952
self . cat_pattern ( discr_place. clone ( ) , pat, & mut |place, pat| {
955
953
match pat. kind {
@@ -1042,6 +1040,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1042
1040
///
1043
1041
/// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
1044
1042
/// closure as the DefId.
1043
+ #[ instrument( skip( self ) , level = "debug" ) ]
1045
1044
fn walk_captures ( & self , closure_expr : & hir:: Closure < ' _ > ) -> Result < ( ) , Cx :: Error > {
1046
1045
fn upvar_is_local_variable (
1047
1046
upvars : Option < & FxIndexMap < HirId , hir:: Upvar > > ,
@@ -1051,8 +1050,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1051
1050
upvars. map ( |upvars| !upvars. contains_key ( & upvar_id) ) . unwrap_or ( body_owner_is_closure)
1052
1051
}
1053
1052
1054
- debug ! ( "walk_captures({:?})" , closure_expr) ;
1055
-
1056
1053
let tcx = self . cx . tcx ( ) ;
1057
1054
let closure_def_id = closure_expr. def_id ;
1058
1055
// For purposes of this function, coroutine and closures are equivalent.
@@ -1164,55 +1161,17 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1164
1161
}
1165
1162
}
1166
1163
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".
1195
1168
///
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.
1214
1173
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 (
1216
1175
& self ,
1217
1176
id : HirId ,
1218
1177
ty : Option < Ty < ' tcx > > ,
@@ -1222,35 +1181,32 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1222
1181
let ty = self . cx . resolve_vars_if_possible ( ty) ;
1223
1182
self . cx . error_reported_in_ty ( ty) ?;
1224
1183
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) ;
1226
1185
Err ( self
1227
1186
. 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" ) )
1229
1188
} else {
1230
1189
Ok ( ty)
1231
1190
}
1232
1191
}
1233
1192
None => {
1234
1193
// FIXME: We shouldn't be relying on the infcx being tainted.
1235
1194
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) ) ;
1240
1196
}
1241
1197
}
1242
1198
}
1243
1199
1244
1200
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) )
1246
1202
}
1247
1203
1248
1204
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) )
1250
1206
}
1251
1207
1252
1208
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 (
1254
1210
expr. hir_id ,
1255
1211
self . cx . typeck_results ( ) . expr_ty_adjusted_opt ( expr) ,
1256
1212
)
@@ -1285,7 +1241,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1285
1241
self . pat_ty_unadjusted ( pat)
1286
1242
}
1287
1243
1288
- /// Like `TypeckResults::pat_ty` , but ignores implicit `&` patterns.
1244
+ /// Like [`Self::pat_ty_adjusted`] , but ignores implicit `&` patterns.
1289
1245
fn pat_ty_unadjusted ( & self , pat : & hir:: Pat < ' _ > ) -> Result < Ty < ' tcx > , Cx :: Error > {
1290
1246
let base_ty = self . node_ty ( pat. hir_id ) ?;
1291
1247
trace ! ( ?base_ty) ;
@@ -1315,7 +1271,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1315
1271
debug ! ( "By-ref binding of non-derefable type" ) ;
1316
1272
Err ( self
1317
1273
. 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" ) )
1319
1275
}
1320
1276
}
1321
1277
} else {
@@ -1511,7 +1467,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1511
1467
}
1512
1468
}
1513
1469
1514
- def => span_bug ! ( span, "unexpected definition in memory categorization : {:?}" , def) ,
1470
+ def => span_bug ! ( span, "unexpected definition in ExprUseVisitor : {:?}" , def) ,
1515
1471
}
1516
1472
}
1517
1473
@@ -1604,7 +1560,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1604
1560
Some ( ty) => ty,
1605
1561
None => {
1606
1562
debug ! ( "explicit deref of non-derefable type: {:?}" , base_curr_ty) ;
1607
- return Err ( self . cx . report_error (
1563
+ return Err ( self . cx . report_bug (
1608
1564
self . cx . tcx ( ) . hir ( ) . span ( node) ,
1609
1565
"explicit deref of non-derefable type" ,
1610
1566
) ) ;
@@ -1629,7 +1585,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1629
1585
let ty:: Adt ( adt_def, _) = self . cx . try_structurally_resolve_type ( span, ty) . kind ( ) else {
1630
1586
return Err ( self
1631
1587
. 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" ) ) ;
1633
1589
} ;
1634
1590
1635
1591
match res {
@@ -1675,7 +1631,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1675
1631
let ty = self . cx . typeck_results ( ) . node_type ( pat_hir_id) ;
1676
1632
match self . cx . try_structurally_resolve_type ( span, ty) . kind ( ) {
1677
1633
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" ) ) ,
1679
1635
}
1680
1636
}
1681
1637
@@ -1854,7 +1810,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1854
1810
debug ! ( "explicit index of non-indexable type {:?}" , place_with_id) ;
1855
1811
return Err ( self
1856
1812
. cx
1857
- . report_error ( pat. span , "explicit index of non-indexable type" ) ) ;
1813
+ . report_bug ( pat. span , "explicit index of non-indexable type" ) ) ;
1858
1814
} ;
1859
1815
let elt_place = self . cat_projection (
1860
1816
pat. hir_id ,
0 commit comments