@@ -10,7 +10,9 @@ use la_arena::ArenaMap;
1010use stdx:: never;
1111use triomphe:: Arc ;
1212
13- use crate :: { db:: HirDatabase , ClosureId } ;
13+ use crate :: {
14+ db:: HirDatabase , mir:: Operand , utils:: ClosureSubst , ClosureId , Interner , Ty , TyExt , TypeFlags ,
15+ } ;
1416
1517use super :: {
1618 BasicBlockId , BorrowKind , LocalId , MirBody , MirLowerError , MirSpan , Place , ProjectionElem ,
@@ -24,10 +26,17 @@ pub enum MutabilityReason {
2426 Not ,
2527}
2628
29+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
30+ pub struct MovedOutOfRef {
31+ pub ty : Ty ,
32+ pub span : MirSpan ,
33+ }
34+
2735#[ derive( Debug , Clone , PartialEq , Eq ) ]
2836pub struct BorrowckResult {
2937 pub mir_body : Arc < MirBody > ,
3038 pub mutability_of_locals : ArenaMap < LocalId , MutabilityReason > ,
39+ pub moved_out_of_ref : Vec < MovedOutOfRef > ,
3140}
3241
3342fn all_mir_bodies (
@@ -68,12 +77,110 @@ pub fn borrowck_query(
6877 let r = all_mir_bodies ( db, def)
6978 . map ( |body| {
7079 let body = body?;
71- Ok ( BorrowckResult { mutability_of_locals : mutability_of_locals ( & body) , mir_body : body } )
80+ Ok ( BorrowckResult {
81+ mutability_of_locals : mutability_of_locals ( & body) ,
82+ moved_out_of_ref : moved_out_of_ref ( db, & body) ,
83+ mir_body : body,
84+ } )
7285 } )
7386 . collect :: < Result < Vec < _ > , MirLowerError > > ( ) ?;
7487 Ok ( r. into ( ) )
7588}
7689
90+ fn moved_out_of_ref ( db : & dyn HirDatabase , body : & MirBody ) -> Vec < MovedOutOfRef > {
91+ let mut result = vec ! [ ] ;
92+ let mut for_operand = |op : & Operand , span : MirSpan | match op {
93+ Operand :: Copy ( p) | Operand :: Move ( p) => {
94+ let mut ty: Ty = body. locals [ p. local ] . ty . clone ( ) ;
95+ let mut is_dereference_of_ref = false ;
96+ for proj in & p. projection {
97+ if * proj == ProjectionElem :: Deref && ty. as_reference ( ) . is_some ( ) {
98+ is_dereference_of_ref = true ;
99+ }
100+ ty = proj. projected_ty ( ty, db, |c, subst, f| {
101+ let ( def, _) = db. lookup_intern_closure ( c. into ( ) ) ;
102+ let infer = db. infer ( def) ;
103+ let ( captures, _) = infer. closure_info ( & c) ;
104+ let parent_subst = ClosureSubst ( subst) . parent_subst ( ) ;
105+ captures
106+ . get ( f)
107+ . expect ( "broken closure field" )
108+ . ty
109+ . clone ( )
110+ . substitute ( Interner , parent_subst)
111+ } ) ;
112+ }
113+ if is_dereference_of_ref
114+ && !ty. clone ( ) . is_copy ( db, body. owner )
115+ && !ty. data ( Interner ) . flags . intersects ( TypeFlags :: HAS_ERROR )
116+ {
117+ result. push ( MovedOutOfRef { span, ty } ) ;
118+ }
119+ }
120+ Operand :: Constant ( _) | Operand :: Static ( _) => ( ) ,
121+ } ;
122+ for ( _, block) in body. basic_blocks . iter ( ) {
123+ for statement in & block. statements {
124+ match & statement. kind {
125+ StatementKind :: Assign ( _, r) => match r {
126+ Rvalue :: ShallowInitBoxWithAlloc ( _) => ( ) ,
127+ Rvalue :: ShallowInitBox ( o, _)
128+ | Rvalue :: UnaryOp ( _, o)
129+ | Rvalue :: Cast ( _, o, _)
130+ | Rvalue :: Repeat ( o, _)
131+ | Rvalue :: Use ( o) => for_operand ( o, statement. span ) ,
132+ Rvalue :: CopyForDeref ( _)
133+ | Rvalue :: Discriminant ( _)
134+ | Rvalue :: Len ( _)
135+ | Rvalue :: Ref ( _, _) => ( ) ,
136+ Rvalue :: CheckedBinaryOp ( _, o1, o2) => {
137+ for_operand ( o1, statement. span ) ;
138+ for_operand ( o2, statement. span ) ;
139+ }
140+ Rvalue :: Aggregate ( _, ops) => {
141+ for op in ops {
142+ for_operand ( op, statement. span ) ;
143+ }
144+ }
145+ } ,
146+ StatementKind :: Deinit ( _)
147+ | StatementKind :: StorageLive ( _)
148+ | StatementKind :: StorageDead ( _)
149+ | StatementKind :: Nop => ( ) ,
150+ }
151+ }
152+ match & block. terminator {
153+ Some ( terminator) => match & terminator. kind {
154+ TerminatorKind :: SwitchInt { discr, .. } => for_operand ( discr, terminator. span ) ,
155+ TerminatorKind :: FalseEdge { .. }
156+ | TerminatorKind :: FalseUnwind { .. }
157+ | TerminatorKind :: Goto { .. }
158+ | TerminatorKind :: Resume
159+ | TerminatorKind :: GeneratorDrop
160+ | TerminatorKind :: Abort
161+ | TerminatorKind :: Return
162+ | TerminatorKind :: Unreachable
163+ | TerminatorKind :: Drop { .. } => ( ) ,
164+ TerminatorKind :: DropAndReplace { value, .. } => {
165+ for_operand ( value, terminator. span ) ;
166+ }
167+ TerminatorKind :: Call { func, args, .. } => {
168+ for_operand ( func, terminator. span ) ;
169+ args. iter ( ) . for_each ( |x| for_operand ( x, terminator. span ) ) ;
170+ }
171+ TerminatorKind :: Assert { cond, .. } => {
172+ for_operand ( cond, terminator. span ) ;
173+ }
174+ TerminatorKind :: Yield { value, .. } => {
175+ for_operand ( value, terminator. span ) ;
176+ }
177+ } ,
178+ None => ( ) ,
179+ }
180+ }
181+ result
182+ }
183+
77184fn is_place_direct ( lvalue : & Place ) -> bool {
78185 !lvalue. projection . iter ( ) . any ( |x| * x == ProjectionElem :: Deref )
79186}
0 commit comments