@@ -10,7 +10,7 @@ use la_arena::ArenaMap;
1010use stdx:: never;
1111use triomphe:: Arc ;
1212
13- use crate :: { db:: HirDatabase , ClosureId } ;
13+ use crate :: { db:: HirDatabase , mir :: Operand , utils :: ClosureSubst , ClosureId , Interner , Ty , TyExt } ;
1414
1515use super :: {
1616 BasicBlockId , BorrowKind , LocalId , MirBody , MirLowerError , MirSpan , Place , ProjectionElem ,
@@ -24,10 +24,17 @@ pub enum MutabilityReason {
2424 Not ,
2525}
2626
27+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
28+ pub struct MovedOutOfRef {
29+ pub ty : Ty ,
30+ pub span : MirSpan ,
31+ }
32+
2733#[ derive( Debug , Clone , PartialEq , Eq ) ]
2834pub struct BorrowckResult {
2935 pub mir_body : Arc < MirBody > ,
3036 pub mutability_of_locals : ArenaMap < LocalId , MutabilityReason > ,
37+ pub moved_out_of_ref : Vec < MovedOutOfRef > ,
3138}
3239
3340fn all_mir_bodies (
@@ -68,12 +75,107 @@ pub fn borrowck_query(
6875 let r = all_mir_bodies ( db, def)
6976 . map ( |body| {
7077 let body = body?;
71- Ok ( BorrowckResult { mutability_of_locals : mutability_of_locals ( & body) , mir_body : body } )
78+ Ok ( BorrowckResult {
79+ mutability_of_locals : mutability_of_locals ( & body) ,
80+ moved_out_of_ref : moved_out_of_ref ( db, & body) ,
81+ mir_body : body,
82+ } )
7283 } )
7384 . collect :: < Result < Vec < _ > , MirLowerError > > ( ) ?;
7485 Ok ( r. into ( ) )
7586}
7687
88+ fn moved_out_of_ref ( db : & dyn HirDatabase , body : & MirBody ) -> Vec < MovedOutOfRef > {
89+ let mut result = vec ! [ ] ;
90+ let mut for_operand = |op : & Operand , span : MirSpan | match op {
91+ Operand :: Copy ( p) | Operand :: Move ( p) => {
92+ let mut ty: Ty = body. locals [ p. local ] . ty . clone ( ) ;
93+ let mut is_dereference_of_ref = false ;
94+ for proj in & p. projection {
95+ if * proj == ProjectionElem :: Deref && ty. as_reference ( ) . is_some ( ) {
96+ is_dereference_of_ref = true ;
97+ }
98+ ty = proj. projected_ty ( ty, db, |c, subst, f| {
99+ let ( def, _) = db. lookup_intern_closure ( c. into ( ) ) ;
100+ let infer = db. infer ( def) ;
101+ let ( captures, _) = infer. closure_info ( & c) ;
102+ let parent_subst = ClosureSubst ( subst) . parent_subst ( ) ;
103+ captures
104+ . get ( f)
105+ . expect ( "broken closure field" )
106+ . ty
107+ . clone ( )
108+ . substitute ( Interner , parent_subst)
109+ } ) ;
110+ }
111+ if is_dereference_of_ref && !ty. clone ( ) . is_copy ( db, body. owner ) {
112+ result. push ( MovedOutOfRef { span, ty } ) ;
113+ }
114+ }
115+ Operand :: Constant ( _) | Operand :: Static ( _) => ( ) ,
116+ } ;
117+ for ( _, block) in body. basic_blocks . iter ( ) {
118+ for statement in & block. statements {
119+ match & statement. kind {
120+ StatementKind :: Assign ( _, r) => match r {
121+ Rvalue :: ShallowInitBoxWithAlloc ( _) => ( ) ,
122+ Rvalue :: ShallowInitBox ( o, _)
123+ | Rvalue :: UnaryOp ( _, o)
124+ | Rvalue :: Cast ( _, o, _)
125+ | Rvalue :: Repeat ( o, _)
126+ | Rvalue :: Use ( o) => for_operand ( o, statement. span ) ,
127+ Rvalue :: CopyForDeref ( _)
128+ | Rvalue :: Discriminant ( _)
129+ | Rvalue :: Len ( _)
130+ | Rvalue :: Ref ( _, _) => ( ) ,
131+ Rvalue :: CheckedBinaryOp ( _, o1, o2) => {
132+ for_operand ( o1, statement. span ) ;
133+ for_operand ( o2, statement. span ) ;
134+ }
135+ Rvalue :: Aggregate ( _, ops) => {
136+ for op in ops {
137+ for_operand ( op, statement. span ) ;
138+ }
139+ }
140+ } ,
141+ StatementKind :: Deinit ( _)
142+ | StatementKind :: StorageLive ( _)
143+ | StatementKind :: StorageDead ( _)
144+ | StatementKind :: Nop => ( ) ,
145+ }
146+ }
147+ match & block. terminator {
148+ Some ( terminator) => match & terminator. kind {
149+ TerminatorKind :: SwitchInt { discr, .. } => for_operand ( discr, terminator. span ) ,
150+ TerminatorKind :: FalseEdge { .. }
151+ | TerminatorKind :: FalseUnwind { .. }
152+ | TerminatorKind :: Goto { .. }
153+ | TerminatorKind :: Resume
154+ | TerminatorKind :: GeneratorDrop
155+ | TerminatorKind :: Abort
156+ | TerminatorKind :: Return
157+ | TerminatorKind :: Unreachable
158+ | TerminatorKind :: Drop { .. } => ( ) ,
159+ TerminatorKind :: DropAndReplace { value, .. } => {
160+ for_operand ( value, terminator. span ) ;
161+ }
162+ TerminatorKind :: Call { func, args, .. } => {
163+ for_operand ( func, terminator. span ) ;
164+ args. iter ( ) . for_each ( |x| for_operand ( x, terminator. span ) ) ;
165+ }
166+ TerminatorKind :: Assert { cond, .. } => {
167+ for_operand ( cond, terminator. span ) ;
168+ }
169+ TerminatorKind :: Yield { value, .. } => {
170+ for_operand ( value, terminator. span ) ;
171+ }
172+ } ,
173+ None => ( ) ,
174+ }
175+ }
176+ result
177+ }
178+
77179fn is_place_direct ( lvalue : & Place ) -> bool {
78180 !lvalue. projection . iter ( ) . any ( |x| * x == ProjectionElem :: Deref )
79181}
0 commit comments