55
66use std:: iter;
77
8- use hir_def:: DefWithBodyId ;
8+ use hir_def:: { DefWithBodyId , HasModule } ;
99use 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,115 @@ 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 (
101+ ty,
102+ db,
103+ |c, subst, f| {
104+ let ( def, _) = db. lookup_intern_closure ( c. into ( ) ) ;
105+ let infer = db. infer ( def) ;
106+ let ( captures, _) = infer. closure_info ( & c) ;
107+ let parent_subst = ClosureSubst ( subst) . parent_subst ( ) ;
108+ captures
109+ . get ( f)
110+ . expect ( "broken closure field" )
111+ . ty
112+ . clone ( )
113+ . substitute ( Interner , parent_subst)
114+ } ,
115+ body. owner . module ( db. upcast ( ) ) . krate ( ) ,
116+ ) ;
117+ }
118+ if is_dereference_of_ref
119+ && !ty. clone ( ) . is_copy ( db, body. owner )
120+ && !ty. data ( Interner ) . flags . intersects ( TypeFlags :: HAS_ERROR )
121+ {
122+ result. push ( MovedOutOfRef { span, ty } ) ;
123+ }
124+ }
125+ Operand :: Constant ( _) | Operand :: Static ( _) => ( ) ,
126+ } ;
127+ for ( _, block) in body. basic_blocks . iter ( ) {
128+ for statement in & block. statements {
129+ match & statement. kind {
130+ StatementKind :: Assign ( _, r) => match r {
131+ Rvalue :: ShallowInitBoxWithAlloc ( _) => ( ) ,
132+ Rvalue :: ShallowInitBox ( o, _)
133+ | Rvalue :: UnaryOp ( _, o)
134+ | Rvalue :: Cast ( _, o, _)
135+ | Rvalue :: Repeat ( o, _)
136+ | Rvalue :: Use ( o) => for_operand ( o, statement. span ) ,
137+ Rvalue :: CopyForDeref ( _)
138+ | Rvalue :: Discriminant ( _)
139+ | Rvalue :: Len ( _)
140+ | Rvalue :: Ref ( _, _) => ( ) ,
141+ Rvalue :: CheckedBinaryOp ( _, o1, o2) => {
142+ for_operand ( o1, statement. span ) ;
143+ for_operand ( o2, statement. span ) ;
144+ }
145+ Rvalue :: Aggregate ( _, ops) => {
146+ for op in ops {
147+ for_operand ( op, statement. span ) ;
148+ }
149+ }
150+ } ,
151+ StatementKind :: Deinit ( _)
152+ | StatementKind :: StorageLive ( _)
153+ | StatementKind :: StorageDead ( _)
154+ | StatementKind :: Nop => ( ) ,
155+ }
156+ }
157+ match & block. terminator {
158+ Some ( terminator) => match & terminator. kind {
159+ TerminatorKind :: SwitchInt { discr, .. } => for_operand ( discr, terminator. span ) ,
160+ TerminatorKind :: FalseEdge { .. }
161+ | TerminatorKind :: FalseUnwind { .. }
162+ | TerminatorKind :: Goto { .. }
163+ | TerminatorKind :: Resume
164+ | TerminatorKind :: GeneratorDrop
165+ | TerminatorKind :: Abort
166+ | TerminatorKind :: Return
167+ | TerminatorKind :: Unreachable
168+ | TerminatorKind :: Drop { .. } => ( ) ,
169+ TerminatorKind :: DropAndReplace { value, .. } => {
170+ for_operand ( value, terminator. span ) ;
171+ }
172+ TerminatorKind :: Call { func, args, .. } => {
173+ for_operand ( func, terminator. span ) ;
174+ args. iter ( ) . for_each ( |x| for_operand ( x, terminator. span ) ) ;
175+ }
176+ TerminatorKind :: Assert { cond, .. } => {
177+ for_operand ( cond, terminator. span ) ;
178+ }
179+ TerminatorKind :: Yield { value, .. } => {
180+ for_operand ( value, terminator. span ) ;
181+ }
182+ } ,
183+ None => ( ) ,
184+ }
185+ }
186+ result
187+ }
188+
77189fn is_place_direct ( lvalue : & Place ) -> bool {
78190 !lvalue. projection . iter ( ) . any ( |x| * x == ProjectionElem :: Deref )
79191}
0 commit comments