@@ -284,30 +284,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
284284 let var_hir_id = upvar_id. var_path . hir_id ;
285285 closure_captures. insert ( var_hir_id, upvar_id) ;
286286
287- let mut new_capture_kind = capture_info. capture_kind ;
288- if let Some ( existing_capture_kind) =
287+ let new_capture_kind = if let Some ( capture_kind) =
289288 self . typeck_results . borrow_mut ( ) . upvar_capture_map . get ( & upvar_id)
290289 {
291- // FIXME(@azhng): refactor this later
292- new_capture_kind = match ( existing_capture_kind, new_capture_kind) {
293- ( ty:: UpvarCapture :: ByValue ( Some ( _) ) , _) => * existing_capture_kind,
294- ( _, ty:: UpvarCapture :: ByValue ( Some ( _) ) ) => new_capture_kind,
295- ( ty:: UpvarCapture :: ByValue ( _) , _) | ( _, ty:: UpvarCapture :: ByValue ( _) ) => {
296- ty:: UpvarCapture :: ByValue ( None )
297- }
298- ( ty:: UpvarCapture :: ByRef ( existing_ref) , ty:: UpvarCapture :: ByRef ( new_ref) ) => {
299- match ( existing_ref. kind , new_ref. kind ) {
300- // Take RHS:
301- ( ty:: ImmBorrow , ty:: UniqueImmBorrow | ty:: MutBorrow )
302- | ( ty:: UniqueImmBorrow , ty:: MutBorrow ) => new_capture_kind,
303- // Take LHS:
304- ( ty:: ImmBorrow , ty:: ImmBorrow )
305- | ( ty:: UniqueImmBorrow , ty:: ImmBorrow | ty:: UniqueImmBorrow )
306- | ( ty:: MutBorrow , _) => * existing_capture_kind,
307- }
308- }
309- } ;
310- }
290+ // upvar_capture_map only stores the UpvarCapture (CaptureKind),
291+ // so we create a fake capture info with no expression.
292+ let fake_capture_info =
293+ ty:: CaptureInfo { expr_id : None , capture_kind : capture_kind. clone ( ) } ;
294+ self . determine_capture_info ( fake_capture_info, capture_info. clone ( ) ) . capture_kind
295+ } else {
296+ capture_info. capture_kind
297+ } ;
311298 self . typeck_results . borrow_mut ( ) . upvar_capture_map . insert ( upvar_id, new_capture_kind) ;
312299 }
313300
@@ -353,6 +340,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
353340 fn should_log_capture_analysis ( & self , closure_def_id : DefId ) -> bool {
354341 self . tcx . has_attr ( closure_def_id, sym:: rustc_capture_analysis)
355342 }
343+
344+ /// Helper function to determine if we need to escalate CaptureKind from
345+ /// CaptureInfo A to B and returns the escalated CaptureInfo.
346+ /// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
347+ ///
348+ /// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
349+ /// on the `CaptureInfo` containing an associated expression id.
350+ ///
351+ /// If both the CaptureKind and Expression are considered to be equivalent,
352+ /// then `CaptureInfo` A is preferred.
353+ fn determine_capture_info (
354+ & self ,
355+ capture_info_a : ty:: CaptureInfo < ' tcx > ,
356+ capture_info_b : ty:: CaptureInfo < ' tcx > ,
357+ ) -> ty:: CaptureInfo < ' tcx > {
358+ // If the capture kind is equivalent then, we don't need to escalate and can compare the
359+ // expressions.
360+ let eq_capture_kind = match ( capture_info_a. capture_kind , capture_info_b. capture_kind ) {
361+ ( ty:: UpvarCapture :: ByValue ( _) , ty:: UpvarCapture :: ByValue ( _) ) => true ,
362+ ( ty:: UpvarCapture :: ByRef ( ref_a) , ty:: UpvarCapture :: ByRef ( ref_b) ) => {
363+ ref_a. kind == ref_b. kind
364+ }
365+ _ => false ,
366+ } ;
367+
368+ if eq_capture_kind {
369+ match ( capture_info_a. expr_id , capture_info_b. expr_id ) {
370+ ( Some ( _) , _) | ( None , None ) => capture_info_a,
371+ ( None , Some ( _) ) => capture_info_b,
372+ }
373+ } else {
374+ match ( capture_info_a. capture_kind , capture_info_b. capture_kind ) {
375+ ( ty:: UpvarCapture :: ByValue ( _) , _) => capture_info_a,
376+ ( _, ty:: UpvarCapture :: ByValue ( _) ) => capture_info_b,
377+ ( ty:: UpvarCapture :: ByRef ( ref_a) , ty:: UpvarCapture :: ByRef ( ref_b) ) => {
378+ match ( ref_a. kind , ref_b. kind ) {
379+ // Take LHS:
380+ ( ty:: UniqueImmBorrow | ty:: MutBorrow , ty:: ImmBorrow )
381+ | ( ty:: MutBorrow , ty:: UniqueImmBorrow ) => capture_info_a,
382+
383+ // Take RHS:
384+ ( ty:: ImmBorrow , ty:: UniqueImmBorrow | ty:: MutBorrow )
385+ | ( ty:: UniqueImmBorrow , ty:: MutBorrow ) => capture_info_b,
386+
387+ ( ty:: ImmBorrow , ty:: ImmBorrow )
388+ | ( ty:: UniqueImmBorrow , ty:: UniqueImmBorrow )
389+ | ( ty:: MutBorrow , ty:: MutBorrow ) => {
390+ bug ! ( "Expected unequal capture kinds" ) ;
391+ }
392+ }
393+ }
394+ }
395+ }
396+ }
356397}
357398
358399struct InferBorrowKind < ' a , ' tcx > {
@@ -426,16 +467,10 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
426467 capture_kind : ty:: UpvarCapture :: ByValue ( Some ( usage_span) ) ,
427468 } ;
428469
429- let curr_info = self . capture_information . get ( & place_with_id. place ) ;
430- let updated_info = match curr_info {
431- Some ( info) => match info. capture_kind {
432- ty:: UpvarCapture :: ByRef ( _) | ty:: UpvarCapture :: ByValue ( None ) => capture_info,
433- _ => * info,
434- } ,
435- None => capture_info,
436- } ;
470+ let curr_info = self . capture_information [ & place_with_id. place ] ;
471+ let updated_info = self . fcx . determine_capture_info ( curr_info, capture_info) ;
437472
438- self . capture_information . insert ( place_with_id. place . clone ( ) , updated_info) ;
473+ self . capture_information [ & place_with_id. place ] = updated_info;
439474 }
440475
441476 /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
@@ -532,42 +567,28 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
532567 diag_expr_id : hir:: HirId ,
533568 kind : ty:: BorrowKind ,
534569 ) {
535- let capture_info = self
536- . capture_information
537- . get ( & place_with_id. place )
538- . unwrap_or_else ( || bug ! ( "Upar capture info missing" ) ) ;
539- // We init capture_information for each element
570+ let curr_capture_info = self . capture_information [ & place_with_id. place ] ;
540571
541572 debug ! (
542- "adjust_upvar_borrow_kind(place={:?}, , diag_expr_id={:?}, capture_info={:?}, kind={:?})" ,
543- place_with_id, diag_expr_id, capture_info , kind
573+ "adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})" ,
574+ place_with_id, diag_expr_id, curr_capture_info , kind
544575 ) ;
545576
546- match capture_info. capture_kind {
547- ty:: UpvarCapture :: ByValue ( _) => {
548- // Upvar is already by-value, the strongest criteria.
549- }
550- ty:: UpvarCapture :: ByRef ( upvar_borrow) => {
551- match ( upvar_borrow. kind , kind) {
552- // Take RHS:
553- ( ty:: ImmBorrow , ty:: UniqueImmBorrow | ty:: MutBorrow )
554- | ( ty:: UniqueImmBorrow , ty:: MutBorrow ) => {
555- if let Some ( ty:: CaptureInfo { expr_id, capture_kind } ) =
556- self . capture_information . get_mut ( & place_with_id. place )
557- {
558- * expr_id = Some ( diag_expr_id) ;
559- if let ty:: UpvarCapture :: ByRef ( borrow_kind) = capture_kind {
560- borrow_kind. kind = kind;
561- }
562- }
563- }
564- // Take LHS:
565- ( ty:: ImmBorrow , ty:: ImmBorrow )
566- | ( ty:: UniqueImmBorrow , ty:: ImmBorrow | ty:: UniqueImmBorrow )
567- | ( ty:: MutBorrow , _) => { }
568- }
569- }
570- }
577+ if let ty:: UpvarCapture :: ByValue ( _) = curr_capture_info. capture_kind {
578+ // It's already captured by value, we don't need to do anything here
579+ return ;
580+ } else if let ty:: UpvarCapture :: ByRef ( curr_upvar_borrow) = curr_capture_info. capture_kind {
581+ // Use the same region as the current capture information
582+ // Doesn't matter since only one of the UpvarBorrow will be used.
583+ let new_upvar_borrow = ty:: UpvarBorrow { kind, region : curr_upvar_borrow. region } ;
584+
585+ let capture_info = ty:: CaptureInfo {
586+ expr_id : Some ( diag_expr_id) ,
587+ capture_kind : ty:: UpvarCapture :: ByRef ( new_upvar_borrow) ,
588+ } ;
589+ let updated_info = self . fcx . determine_capture_info ( curr_capture_info, capture_info) ;
590+ self . capture_information [ & place_with_id. place ] = updated_info;
591+ } ;
571592 }
572593
573594 fn adjust_closure_kind (
@@ -622,7 +643,6 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
622643
623644 debug ! ( "Capturing new place {:?}" , place_with_id) ;
624645
625- let tcx = self . fcx . tcx ;
626646 let capture_kind =
627647 self . fcx . init_capture_kind ( self . capture_clause , upvar_id, self . closure_span ) ;
628648
0 commit comments