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