@@ -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
@@ -36,11 +37,27 @@ pub struct MovedOutOfRef {
3637 pub span : MirSpan ,
3738}
3839
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+
3954#[ derive( Debug , Clone , PartialEq , Eq ) ]
4055pub struct BorrowckResult {
4156 pub mir_body : Arc < MirBody > ,
4257 pub mutability_of_locals : ArenaMap < LocalId , MutabilityReason > ,
4358 pub moved_out_of_ref : Vec < MovedOutOfRef > ,
59+ pub partially_moved : Vec < PartiallyMoved > ,
60+ pub borrow_regions : Vec < BorrowRegion > ,
4461}
4562
4663fn all_mir_bodies (
@@ -80,6 +97,8 @@ pub fn borrowck_query(
8097 res. push ( BorrowckResult {
8198 mutability_of_locals : mutability_of_locals ( db, & body) ,
8299 moved_out_of_ref : moved_out_of_ref ( db, & body) ,
100+ partially_moved : partially_moved ( db, & body) ,
101+ borrow_regions : borrow_regions ( db, & body) ,
83102 mir_body : body,
84103 } ) ;
85104 } ) ?;
@@ -188,6 +207,149 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
188207 result
189208}
190209
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+
191353#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
192354enum ProjectionCase {
193355 /// Projection is a local
0 commit comments