11//! Post-inference closure analysis: captures and closure kind.
22
3- use std:: { cmp, convert :: Infallible , mem} ;
3+ use std:: { cmp, mem} ;
44
5- use either :: Either ;
5+ use base_db :: Crate ;
66use hir_def:: {
7- DefWithBodyId , FieldId , HasModule , TupleFieldId , TupleId , VariantId ,
7+ DefWithBodyId , FieldId , HasModule , VariantId ,
88 expr_store:: path:: Path ,
99 hir:: {
1010 Array , AsmOperand , BinaryOp , BindingId , CaptureBy , Expr , ExprId , ExprOrPatId , Pat , PatId ,
@@ -23,33 +23,97 @@ use syntax::utils::is_raw_identifier;
2323use crate :: {
2424 Adjust , Adjustment , BindingMode ,
2525 db:: { HirDatabase , InternedClosure , InternedClosureId } ,
26+ display:: { DisplayTarget , HirDisplay as _} ,
2627 infer:: InferenceContext ,
27- mir:: { BorrowKind , MirSpan , MutBorrowKind , ProjectionElem } ,
28- next_solver:: { DbInterner , GenericArgs , StoredEarlyBinder , StoredTy , Ty , TyKind } ,
28+ mir:: { BorrowKind , MirSpan , MutBorrowKind } ,
29+ next_solver:: {
30+ DbInterner , ErrorGuaranteed , GenericArgs , ParamEnv , StoredEarlyBinder , StoredTy , Ty ,
31+ TyKind ,
32+ infer:: { InferCtxt , traits:: ObligationCause } ,
33+ obligation_ctxt:: ObligationCtxt ,
34+ } ,
2935 traits:: FnTrait ,
3036} ;
3137
3238// The below functions handle capture and closure kind (Fn, FnMut, ..)
3339
40+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
41+ pub ( crate ) enum HirPlaceProjection {
42+ Deref ,
43+ Field ( FieldId ) ,
44+ TupleField ( u32 ) ,
45+ }
46+
47+ impl HirPlaceProjection {
48+ fn projected_ty < ' db > (
49+ self ,
50+ infcx : & InferCtxt < ' db > ,
51+ env : ParamEnv < ' db > ,
52+ mut base : Ty < ' db > ,
53+ krate : Crate ,
54+ ) -> Ty < ' db > {
55+ let interner = infcx. interner ;
56+ let db = interner. db ;
57+ if base. is_ty_error ( ) {
58+ return Ty :: new_error ( interner, ErrorGuaranteed ) ;
59+ }
60+
61+ if matches ! ( base. kind( ) , TyKind :: Alias ( ..) ) {
62+ let mut ocx = ObligationCtxt :: new ( infcx) ;
63+ match ocx. structurally_normalize_ty ( & ObligationCause :: dummy ( ) , env, base) {
64+ Ok ( it) => base = it,
65+ Err ( _) => return Ty :: new_error ( interner, ErrorGuaranteed ) ,
66+ }
67+ }
68+ match self {
69+ HirPlaceProjection :: Deref => match base. kind ( ) {
70+ TyKind :: RawPtr ( inner, _) | TyKind :: Ref ( _, inner, _) => inner,
71+ TyKind :: Adt ( adt_def, subst) if adt_def. is_box ( ) => subst. type_at ( 0 ) ,
72+ _ => {
73+ never ! (
74+ "Overloaded deref on type {} is not a projection" ,
75+ base. display( db, DisplayTarget :: from_crate( db, krate) )
76+ ) ;
77+ Ty :: new_error ( interner, ErrorGuaranteed )
78+ }
79+ } ,
80+ HirPlaceProjection :: Field ( f) => match base. kind ( ) {
81+ TyKind :: Adt ( _, subst) => {
82+ db. field_types ( f. parent ) [ f. local_id ] . get ( ) . instantiate ( interner, subst)
83+ }
84+ ty => {
85+ never ! ( "Only adt has field, found {:?}" , ty) ;
86+ Ty :: new_error ( interner, ErrorGuaranteed )
87+ }
88+ } ,
89+ HirPlaceProjection :: TupleField ( idx) => match base. kind ( ) {
90+ TyKind :: Tuple ( subst) => {
91+ subst. as_slice ( ) . get ( idx as usize ) . copied ( ) . unwrap_or_else ( || {
92+ never ! ( "Out of bound tuple field" ) ;
93+ Ty :: new_error ( interner, ErrorGuaranteed )
94+ } )
95+ }
96+ ty => {
97+ never ! ( "Only tuple has tuple field: {:?}" , ty) ;
98+ Ty :: new_error ( interner, ErrorGuaranteed )
99+ }
100+ } ,
101+ }
102+ }
103+ }
104+
34105#[ derive( Debug , Clone , PartialEq , Eq , Hash , salsa:: Update ) ]
35106pub ( crate ) struct HirPlace {
36107 pub ( crate ) local : BindingId ,
37- pub ( crate ) projections : Vec < ProjectionElem < Infallible > > ,
108+ pub ( crate ) projections : Vec < HirPlaceProjection > ,
38109}
39110
40111impl HirPlace {
41112 fn ty < ' db > ( & self , ctx : & mut InferenceContext < ' _ , ' db > ) -> Ty < ' db > {
113+ let krate = ctx. krate ( ) ;
42114 let mut ty = ctx. table . resolve_completely ( ctx. result . binding_ty ( self . local ) ) ;
43115 for p in & self . projections {
44- ty = p. projected_ty (
45- & ctx. table . infer_ctxt ,
46- ctx. table . param_env ,
47- ty,
48- |_, _, _| {
49- unreachable ! ( "Closure field only happens in MIR" ) ;
50- } ,
51- ctx. owner . module ( ctx. db ) . krate ( ctx. db ) ,
52- ) ;
116+ ty = p. projected_ty ( ctx. infcx ( ) , ctx. table . param_env , ty, krate) ;
53117 }
54118 ty
55119 }
@@ -62,7 +126,7 @@ impl HirPlace {
62126 if let CaptureKind :: ByRef ( BorrowKind :: Mut {
63127 kind : MutBorrowKind :: Default | MutBorrowKind :: TwoPhasedBorrow ,
64128 } ) = current_capture
65- && self . projections [ len..] . contains ( & ProjectionElem :: Deref )
129+ && self . projections [ len..] . contains ( & HirPlaceProjection :: Deref )
66130 {
67131 current_capture =
68132 CaptureKind :: ByRef ( BorrowKind :: Mut { kind : MutBorrowKind :: ClosureCapture } ) ;
@@ -98,7 +162,7 @@ impl CapturedItem {
98162
99163 /// Returns whether this place has any field (aka. non-deref) projections.
100164 pub fn has_field_projections ( & self ) -> bool {
101- self . place . projections . iter ( ) . any ( |it| !matches ! ( it, ProjectionElem :: Deref ) )
165+ self . place . projections . iter ( ) . any ( |it| !matches ! ( it, HirPlaceProjection :: Deref ) )
102166 }
103167
104168 pub fn ty < ' db > ( & self , db : & ' db dyn HirDatabase , subst : GenericArgs < ' db > ) -> Ty < ' db > {
@@ -120,8 +184,8 @@ impl CapturedItem {
120184 let mut result = body[ self . place . local ] . name . as_str ( ) . to_owned ( ) ;
121185 for proj in & self . place . projections {
122186 match proj {
123- ProjectionElem :: Deref => { }
124- ProjectionElem :: Field ( Either :: Left ( f ) ) => {
187+ HirPlaceProjection :: Deref => { }
188+ HirPlaceProjection :: Field ( f ) => {
125189 let variant_data = f. parent . fields ( db) ;
126190 match variant_data. shape {
127191 FieldsShape :: Record => {
@@ -138,14 +202,8 @@ impl CapturedItem {
138202 FieldsShape :: Unit => { }
139203 }
140204 }
141- ProjectionElem :: Field ( Either :: Right ( f) ) => format_to ! ( result, "_{}" , f. index) ,
142- & ProjectionElem :: ClosureField ( field) => format_to ! ( result, "_{field}" ) ,
143- ProjectionElem :: Index ( _)
144- | ProjectionElem :: ConstantIndex { .. }
145- | ProjectionElem :: Subslice { .. }
146- | ProjectionElem :: OpaqueCast ( _) => {
147- never ! ( "Not happen in closure capture" ) ;
148- continue ;
205+ HirPlaceProjection :: TupleField ( idx) => {
206+ format_to ! ( result, "_{idx}" )
149207 }
150208 }
151209 }
@@ -163,8 +221,8 @@ impl CapturedItem {
163221 for proj in & self . place . projections {
164222 match proj {
165223 // In source code autoderef kicks in.
166- ProjectionElem :: Deref => { }
167- ProjectionElem :: Field ( Either :: Left ( f ) ) => {
224+ HirPlaceProjection :: Deref => { }
225+ HirPlaceProjection :: Field ( f ) => {
168226 let variant_data = f. parent . fields ( db) ;
169227 match variant_data. shape {
170228 FieldsShape :: Record => format_to ! (
@@ -184,19 +242,8 @@ impl CapturedItem {
184242 FieldsShape :: Unit => { }
185243 }
186244 }
187- ProjectionElem :: Field ( Either :: Right ( f) ) => {
188- let field = f. index ;
189- format_to ! ( result, ".{field}" ) ;
190- }
191- & ProjectionElem :: ClosureField ( field) => {
192- format_to ! ( result, ".{field}" ) ;
193- }
194- ProjectionElem :: Index ( _)
195- | ProjectionElem :: ConstantIndex { .. }
196- | ProjectionElem :: Subslice { .. }
197- | ProjectionElem :: OpaqueCast ( _) => {
198- never ! ( "Not happen in closure capture" ) ;
199- continue ;
245+ HirPlaceProjection :: TupleField ( idx) => {
246+ format_to ! ( result, ".{idx}" )
200247 }
201248 }
202249 }
@@ -205,7 +252,7 @@ impl CapturedItem {
205252 . projections
206253 . iter ( )
207254 . rev ( )
208- . take_while ( |proj| matches ! ( proj, ProjectionElem :: Deref ) )
255+ . take_while ( |proj| matches ! ( proj, HirPlaceProjection :: Deref ) )
209256 . count ( ) ;
210257 result. insert_str ( 0 , & "*" . repeat ( final_derefs_count) ) ;
211258 result
@@ -219,11 +266,11 @@ impl CapturedItem {
219266 let mut field_need_paren = false ;
220267 for proj in & self . place . projections {
221268 match proj {
222- ProjectionElem :: Deref => {
269+ HirPlaceProjection :: Deref => {
223270 result = format ! ( "*{result}" ) ;
224271 field_need_paren = true ;
225272 }
226- ProjectionElem :: Field ( Either :: Left ( f ) ) => {
273+ HirPlaceProjection :: Field ( f ) => {
227274 if field_need_paren {
228275 result = format ! ( "({result})" ) ;
229276 }
@@ -243,28 +290,13 @@ impl CapturedItem {
243290 result = format ! ( "{result}.{field}" ) ;
244291 field_need_paren = false ;
245292 }
246- ProjectionElem :: Field ( Either :: Right ( f) ) => {
247- let field = f. index ;
248- if field_need_paren {
249- result = format ! ( "({result})" ) ;
250- }
251- result = format ! ( "{result}.{field}" ) ;
252- field_need_paren = false ;
253- }
254- & ProjectionElem :: ClosureField ( field) => {
293+ HirPlaceProjection :: TupleField ( idx) => {
255294 if field_need_paren {
256295 result = format ! ( "({result})" ) ;
257296 }
258- result = format ! ( "{result}.{field }" ) ;
297+ result = format ! ( "{result}.{idx }" ) ;
259298 field_need_paren = false ;
260299 }
261- ProjectionElem :: Index ( _)
262- | ProjectionElem :: ConstantIndex { .. }
263- | ProjectionElem :: Subslice { .. }
264- | ProjectionElem :: OpaqueCast ( _) => {
265- never ! ( "Not happen in closure capture" ) ;
266- continue ;
267- }
268300 }
269301 }
270302 result
@@ -345,7 +377,9 @@ impl<'db> InferenceContext<'_, 'db> {
345377 let mut place = self . place_of_expr ( * expr) ?;
346378 let field = self . result . field_resolution ( tgt_expr) ?;
347379 self . current_capture_span_stack . push ( MirSpan :: ExprId ( tgt_expr) ) ;
348- place. projections . push ( ProjectionElem :: Field ( field) ) ;
380+ place. projections . push ( field. either ( HirPlaceProjection :: Field , |f| {
381+ HirPlaceProjection :: TupleField ( f. index )
382+ } ) ) ;
349383 return Some ( place) ;
350384 }
351385 Expr :: UnaryOp { expr, op : UnaryOp :: Deref } => {
@@ -357,7 +391,7 @@ impl<'db> InferenceContext<'_, 'db> {
357391 if is_builtin_deref {
358392 let mut place = self . place_of_expr ( * expr) ?;
359393 self . current_capture_span_stack . push ( MirSpan :: ExprId ( tgt_expr) ) ;
360- place. projections . push ( ProjectionElem :: Deref ) ;
394+ place. projections . push ( HirPlaceProjection :: Deref ) ;
361395 return Some ( place) ;
362396 }
363397 }
@@ -832,9 +866,6 @@ impl<'db> InferenceContext<'_, 'db> {
832866 & self . table . infer_ctxt ,
833867 self . table . param_env ,
834868 ty,
835- |_, _, _| {
836- unreachable ! ( "Closure field only happens in MIR" ) ;
837- } ,
838869 self . owner . module ( self . db ) . krate ( self . db ) ,
839870 ) ;
840871 if ty. is_raw_ptr ( ) || ty. is_union ( ) {
@@ -853,7 +884,7 @@ impl<'db> InferenceContext<'_, 'db> {
853884 let mut current_captures = std:: mem:: take ( & mut self . current_captures ) ;
854885 for capture in & mut current_captures {
855886 if let Some ( first_deref) =
856- capture. place . projections . iter ( ) . position ( |proj| * proj == ProjectionElem :: Deref )
887+ capture. place . projections . iter ( ) . position ( |proj| * proj == HirPlaceProjection :: Deref )
857888 {
858889 self . truncate_capture_spans ( capture, first_deref) ;
859890 capture. place . projections . truncate ( first_deref) ;
@@ -876,7 +907,7 @@ impl<'db> InferenceContext<'_, 'db> {
876907 }
877908 match it. next ( ) {
878909 Some ( it) => {
879- lookup_place. projections . push ( it . clone ( ) ) ;
910+ lookup_place. projections . push ( * it ) ;
880911 }
881912 None => break None ,
882913 }
@@ -903,7 +934,7 @@ impl<'db> InferenceContext<'_, 'db> {
903934 fn consume_with_pat ( & mut self , mut place : HirPlace , tgt_pat : PatId ) {
904935 let adjustments_count =
905936 self . result . pat_adjustments . get ( & tgt_pat) . map ( |it| it. len ( ) ) . unwrap_or_default ( ) ;
906- place. projections . extend ( ( 0 ..adjustments_count) . map ( |_| ProjectionElem :: Deref ) ) ;
937+ place. projections . extend ( ( 0 ..adjustments_count) . map ( |_| HirPlaceProjection :: Deref ) ) ;
907938 self . current_capture_span_stack
908939 . extend ( ( 0 ..adjustments_count) . map ( |_| MirSpan :: PatId ( tgt_pat) ) ) ;
909940 ' reset_span_stack: {
@@ -920,10 +951,7 @@ impl<'db> InferenceContext<'_, 'db> {
920951 for ( & arg, i) in it {
921952 let mut p = place. clone ( ) ;
922953 self . current_capture_span_stack . push ( MirSpan :: PatId ( arg) ) ;
923- p. projections . push ( ProjectionElem :: Field ( Either :: Right ( TupleFieldId {
924- tuple : TupleId ( !0 ) , // dummy this, as its unused anyways
925- index : i as u32 ,
926- } ) ) ) ;
954+ p. projections . push ( HirPlaceProjection :: TupleField ( i as u32 ) ) ;
927955 self . consume_with_pat ( p, arg) ;
928956 self . current_capture_span_stack . pop ( ) ;
929957 }
@@ -950,10 +978,10 @@ impl<'db> InferenceContext<'_, 'db> {
950978 } ;
951979 let mut p = place. clone ( ) ;
952980 self . current_capture_span_stack . push ( MirSpan :: PatId ( arg) ) ;
953- p. projections . push ( ProjectionElem :: Field ( Either :: Left ( FieldId {
981+ p. projections . push ( HirPlaceProjection :: Field ( FieldId {
954982 parent : variant,
955983 local_id,
956- } ) ) ) ;
984+ } ) ) ;
957985 self . consume_with_pat ( p, arg) ;
958986 self . current_capture_span_stack . pop ( ) ;
959987 }
@@ -1005,10 +1033,10 @@ impl<'db> InferenceContext<'_, 'db> {
10051033 for ( & arg, ( i, _) ) in it {
10061034 let mut p = place. clone ( ) ;
10071035 self . current_capture_span_stack . push ( MirSpan :: PatId ( arg) ) ;
1008- p. projections . push ( ProjectionElem :: Field ( Either :: Left ( FieldId {
1036+ p. projections . push ( HirPlaceProjection :: Field ( FieldId {
10091037 parent : variant,
10101038 local_id : i,
1011- } ) ) ) ;
1039+ } ) ) ;
10121040 self . consume_with_pat ( p, arg) ;
10131041 self . current_capture_span_stack . pop ( ) ;
10141042 }
@@ -1017,7 +1045,7 @@ impl<'db> InferenceContext<'_, 'db> {
10171045 }
10181046 Pat :: Ref { pat, mutability : _ } => {
10191047 self . current_capture_span_stack . push ( MirSpan :: PatId ( tgt_pat) ) ;
1020- place. projections . push ( ProjectionElem :: Deref ) ;
1048+ place. projections . push ( HirPlaceProjection :: Deref ) ;
10211049 self . consume_with_pat ( place, * pat) ;
10221050 self . current_capture_span_stack . pop ( ) ;
10231051 }
@@ -1071,7 +1099,7 @@ impl<'db> InferenceContext<'_, 'db> {
10711099 CaptureKind :: ByRef ( BorrowKind :: Mut {
10721100 kind: MutBorrowKind :: Default | MutBorrowKind :: TwoPhasedBorrow
10731101 } )
1074- ) && !item. place . projections . contains ( & ProjectionElem :: Deref )
1102+ ) && !item. place . projections . contains ( & HirPlaceProjection :: Deref )
10751103 {
10761104 // FIXME: remove the `mutated_bindings_in_closure` completely and add proper fake reads in
10771105 // MIR. I didn't do that due duplicate diagnostics.
@@ -1221,7 +1249,7 @@ fn apply_adjusts_to_place(
12211249 match & adj. kind {
12221250 Adjust :: Deref ( None ) => {
12231251 current_capture_span_stack. push ( span) ;
1224- r. projections . push ( ProjectionElem :: Deref ) ;
1252+ r. projections . push ( HirPlaceProjection :: Deref ) ;
12251253 }
12261254 _ => return None ,
12271255 }
0 commit comments