@@ -7,6 +7,7 @@ use std::iter;
77
88use hir_def:: { DefWithBodyId , HasModule } ;
99use la_arena:: ArenaMap ;
10+ use rustc_hash:: FxHashMap ;
1011use stdx:: never;
1112use triomphe:: Arc ;
1213
@@ -33,11 +34,27 @@ pub struct MovedOutOfRef {
3334 pub span : MirSpan ,
3435}
3536
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+
3651#[ derive( Debug , Clone , PartialEq , Eq ) ]
3752pub struct BorrowckResult {
3853 pub mir_body : Arc < MirBody > ,
3954 pub mutability_of_locals : ArenaMap < LocalId , MutabilityReason > ,
4055 pub moved_out_of_ref : Vec < MovedOutOfRef > ,
56+ pub partially_moved : Vec < PartiallyMoved > ,
57+ pub borrow_regions : Vec < BorrowRegion > ,
4158}
4259
4360fn all_mir_bodies (
@@ -77,6 +94,8 @@ pub fn borrowck_query(
7794 res. push ( BorrowckResult {
7895 mutability_of_locals : mutability_of_locals ( db, & body) ,
7996 moved_out_of_ref : moved_out_of_ref ( db, & body) ,
97+ partially_moved : partially_moved ( db, & body) ,
98+ borrow_regions : borrow_regions ( db, & body) ,
8099 mir_body : body,
81100 } ) ;
82101 } ) ?;
@@ -185,6 +204,149 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
185204 result
186205}
187206
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+
188350#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
189351enum ProjectionCase {
190352 /// Projection is a local
0 commit comments