@@ -7,6 +7,7 @@ use std::iter;
7
7
8
8
use hir_def:: { DefWithBodyId , HasModule } ;
9
9
use la_arena:: ArenaMap ;
10
+ use rustc_hash:: FxHashMap ;
10
11
use stdx:: never;
11
12
use triomphe:: Arc ;
12
13
@@ -33,11 +34,27 @@ pub struct MovedOutOfRef {
33
34
pub span : MirSpan ,
34
35
}
35
36
37
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
38
+ pub struct PartiallyMoved {
39
+ pub ty : Ty ,
40
+ pub span : MirSpan ,
41
+ pub local : LocalId ,
42
+ }
43
+
44
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
45
+ pub struct BorrowRegion {
46
+ pub local : LocalId ,
47
+ pub kind : BorrowKind ,
48
+ pub places : Vec < MirSpan > ,
49
+ }
50
+
36
51
#[ derive( Debug , Clone , PartialEq , Eq ) ]
37
52
pub struct BorrowckResult {
38
53
pub mir_body : Arc < MirBody > ,
39
54
pub mutability_of_locals : ArenaMap < LocalId , MutabilityReason > ,
40
55
pub moved_out_of_ref : Vec < MovedOutOfRef > ,
56
+ pub partially_moved : Vec < PartiallyMoved > ,
57
+ pub borrow_regions : Vec < BorrowRegion > ,
41
58
}
42
59
43
60
fn all_mir_bodies (
@@ -77,6 +94,8 @@ pub fn borrowck_query(
77
94
res. push ( BorrowckResult {
78
95
mutability_of_locals : mutability_of_locals ( db, & body) ,
79
96
moved_out_of_ref : moved_out_of_ref ( db, & body) ,
97
+ partially_moved : partially_moved ( db, & body) ,
98
+ borrow_regions : borrow_regions ( db, & body) ,
80
99
mir_body : body,
81
100
} ) ;
82
101
} ) ?;
@@ -185,6 +204,149 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
185
204
result
186
205
}
187
206
207
+ fn partially_moved ( db : & dyn HirDatabase , body : & MirBody ) -> Vec < PartiallyMoved > {
208
+ let mut result = vec ! [ ] ;
209
+ let mut for_operand = |op : & Operand , span : MirSpan | match op {
210
+ Operand :: Copy ( p) | Operand :: Move ( p) => {
211
+ let mut ty: Ty = body. locals [ p. local ] . ty . clone ( ) ;
212
+ for proj in p. projection . lookup ( & body. projection_store ) {
213
+ ty = proj. projected_ty (
214
+ ty,
215
+ db,
216
+ |c, subst, f| {
217
+ let ( def, _) = db. lookup_intern_closure ( c. into ( ) ) ;
218
+ let infer = db. infer ( def) ;
219
+ let ( captures, _) = infer. closure_info ( & c) ;
220
+ let parent_subst = ClosureSubst ( subst) . parent_subst ( ) ;
221
+ captures
222
+ . get ( f)
223
+ . expect ( "broken closure field" )
224
+ . ty
225
+ . clone ( )
226
+ . substitute ( Interner , parent_subst)
227
+ } ,
228
+ body. owner . module ( db. upcast ( ) ) . krate ( ) ,
229
+ ) ;
230
+ }
231
+ if !ty. clone ( ) . is_copy ( db, body. owner )
232
+ && !ty. data ( Interner ) . flags . intersects ( TypeFlags :: HAS_ERROR )
233
+ {
234
+ result. push ( PartiallyMoved { span, ty, local : p. local } ) ;
235
+ }
236
+ }
237
+ Operand :: Constant ( _) | Operand :: Static ( _) => ( ) ,
238
+ } ;
239
+ for ( _, block) in body. basic_blocks . iter ( ) {
240
+ db. unwind_if_cancelled ( ) ;
241
+ for statement in & block. statements {
242
+ match & statement. kind {
243
+ StatementKind :: Assign ( _, r) => match r {
244
+ Rvalue :: ShallowInitBoxWithAlloc ( _) => ( ) ,
245
+ Rvalue :: ShallowInitBox ( o, _)
246
+ | Rvalue :: UnaryOp ( _, o)
247
+ | Rvalue :: Cast ( _, o, _)
248
+ | Rvalue :: Repeat ( o, _)
249
+ | Rvalue :: Use ( o) => for_operand ( o, statement. span ) ,
250
+ Rvalue :: CopyForDeref ( _)
251
+ | Rvalue :: Discriminant ( _)
252
+ | Rvalue :: Len ( _)
253
+ | Rvalue :: Ref ( _, _) => ( ) ,
254
+ Rvalue :: CheckedBinaryOp ( _, o1, o2) => {
255
+ for_operand ( o1, statement. span ) ;
256
+ for_operand ( o2, statement. span ) ;
257
+ }
258
+ Rvalue :: Aggregate ( _, ops) => {
259
+ for op in ops. iter ( ) {
260
+ for_operand ( op, statement. span ) ;
261
+ }
262
+ }
263
+ } ,
264
+ StatementKind :: FakeRead ( _)
265
+ | StatementKind :: Deinit ( _)
266
+ | StatementKind :: StorageLive ( _)
267
+ | StatementKind :: StorageDead ( _)
268
+ | StatementKind :: Nop => ( ) ,
269
+ }
270
+ }
271
+ match & block. terminator {
272
+ Some ( terminator) => match & terminator. kind {
273
+ TerminatorKind :: SwitchInt { discr, .. } => for_operand ( discr, terminator. span ) ,
274
+ TerminatorKind :: FalseEdge { .. }
275
+ | TerminatorKind :: FalseUnwind { .. }
276
+ | TerminatorKind :: Goto { .. }
277
+ | TerminatorKind :: UnwindResume
278
+ | TerminatorKind :: GeneratorDrop
279
+ | TerminatorKind :: Abort
280
+ | TerminatorKind :: Return
281
+ | TerminatorKind :: Unreachable
282
+ | TerminatorKind :: Drop { .. } => ( ) ,
283
+ TerminatorKind :: DropAndReplace { value, .. } => {
284
+ for_operand ( value, terminator. span ) ;
285
+ }
286
+ TerminatorKind :: Call { func, args, .. } => {
287
+ for_operand ( func, terminator. span ) ;
288
+ args. iter ( ) . for_each ( |it| for_operand ( it, terminator. span ) ) ;
289
+ }
290
+ TerminatorKind :: Assert { cond, .. } => {
291
+ for_operand ( cond, terminator. span ) ;
292
+ }
293
+ TerminatorKind :: Yield { value, .. } => {
294
+ for_operand ( value, terminator. span ) ;
295
+ }
296
+ } ,
297
+ None => ( ) ,
298
+ }
299
+ }
300
+ result. shrink_to_fit ( ) ;
301
+ result
302
+ }
303
+
304
+ fn borrow_regions ( db : & dyn HirDatabase , body : & MirBody ) -> Vec < BorrowRegion > {
305
+ let mut borrows = FxHashMap :: default ( ) ;
306
+ for ( _, block) in body. basic_blocks . iter ( ) {
307
+ db. unwind_if_cancelled ( ) ;
308
+ for statement in & block. statements {
309
+ match & statement. kind {
310
+ StatementKind :: Assign ( _, r) => match r {
311
+ Rvalue :: Ref ( kind, p) => {
312
+ borrows
313
+ . entry ( p. local )
314
+ . and_modify ( |it : & mut BorrowRegion | {
315
+ it. places . push ( statement. span ) ;
316
+ } )
317
+ . or_insert_with ( || BorrowRegion {
318
+ local : p. local ,
319
+ kind : * kind,
320
+ places : vec ! [ statement. span] ,
321
+ } ) ;
322
+ }
323
+ _ => ( ) ,
324
+ } ,
325
+ _ => ( ) ,
326
+ }
327
+ }
328
+ match & block. terminator {
329
+ Some ( terminator) => match & terminator. kind {
330
+ TerminatorKind :: FalseEdge { .. }
331
+ | TerminatorKind :: FalseUnwind { .. }
332
+ | TerminatorKind :: Goto { .. }
333
+ | TerminatorKind :: UnwindResume
334
+ | TerminatorKind :: GeneratorDrop
335
+ | TerminatorKind :: Abort
336
+ | TerminatorKind :: Return
337
+ | TerminatorKind :: Unreachable
338
+ | TerminatorKind :: Drop { .. } => ( ) ,
339
+ TerminatorKind :: DropAndReplace { .. } => { }
340
+ TerminatorKind :: Call { .. } => { }
341
+ _ => ( ) ,
342
+ } ,
343
+ None => ( ) ,
344
+ }
345
+ }
346
+
347
+ borrows. into_values ( ) . collect ( )
348
+ }
349
+
188
350
#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
189
351
enum ProjectionCase {
190
352
/// Projection is a local
0 commit comments