@@ -8,11 +8,11 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
88use  rustc_hir as  hir; 
99use  rustc_hir:: def:: { CtorOf ,  DefKind } ; 
1010use  rustc_hir:: lang_items:: LangItem ; 
11- use  rustc_hir:: { Expr ,  ExprKind ,  ItemKind ,  Node ,  Stmt ,  StmtKind } ; 
11+ use  rustc_hir:: { Expr ,  ExprKind ,  ItemKind ,  Node ,  Path ,   QPath ,   Stmt ,  StmtKind ,   TyKind } ; 
1212use  rustc_infer:: infer; 
1313use  rustc_middle:: lint:: in_external_macro; 
1414use  rustc_middle:: ty:: { self ,  Binder ,  Ty } ; 
15- use  rustc_span:: symbol:: kw ; 
15+ use  rustc_span:: symbol:: { kw ,  sym } ; 
1616
1717use  std:: iter; 
1818
@@ -350,6 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
350350    } 
351351
352352    /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. 
353+      #[ instrument( skip( self ,  err) ) ]  
353354    pub ( in  super :: super )  fn  suggest_calling_boxed_future_when_appropriate ( 
354355        & self , 
355356        err :  & mut  DiagnosticBuilder < ' _ > , 
@@ -368,41 +369,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368369        if  pin_did. is_none ( )  || self . tcx . lang_items ( ) . owned_box ( ) . is_none ( )  { 
369370            return  false ; 
370371        } 
371-         match  expected. kind ( )  { 
372-             ty:: Adt ( def,  _)  if  Some ( def. did )  == pin_did => ( ) , 
373-             _ => return  false , 
374-         } 
375372        let  box_found = self . tcx . mk_box ( found) ; 
376373        let  pin_box_found = self . tcx . mk_lang_item ( box_found,  LangItem :: Pin ) . unwrap ( ) ; 
377374        let  pin_found = self . tcx . mk_lang_item ( found,  LangItem :: Pin ) . unwrap ( ) ; 
378-         if  self . can_coerce ( pin_box_found,  expected)  { 
379-             debug ! ( "can coerce {:?} to {:?}, suggesting Box::pin" ,  pin_box_found,  expected) ; 
380-             match  found. kind ( )  { 
381-                 ty:: Adt ( def,  _)  if  def. is_box ( )  => { 
382-                     err. help ( "use `Box::pin`" ) ; 
383-                 } 
384-                 _ => { 
385-                     err. multipart_suggestion ( 
386-                         "you need to pin and box this expression" , 
387-                         vec ! [ 
388-                             ( expr. span. shrink_to_lo( ) ,  "Box::pin(" . to_string( ) ) , 
389-                             ( expr. span. shrink_to_hi( ) ,  ")" . to_string( ) ) , 
390-                         ] , 
391-                         Applicability :: MaybeIncorrect , 
392-                     ) ; 
375+         match  expected. kind ( )  { 
376+             ty:: Adt ( def,  _)  if  Some ( def. did )  == pin_did => { 
377+                 if  self . can_coerce ( pin_box_found,  expected)  { 
378+                     debug ! ( "can coerce {:?} to {:?}, suggesting Box::pin" ,  pin_box_found,  expected) ; 
379+                     match  found. kind ( )  { 
380+                         ty:: Adt ( def,  _)  if  def. is_box ( )  => { 
381+                             err. help ( "use `Box::pin`" ) ; 
382+                         } 
383+                         _ => { 
384+                             err. multipart_suggestion ( 
385+                                 "you need to pin and box this expression" , 
386+                                 vec ! [ 
387+                                     ( expr. span. shrink_to_lo( ) ,  "Box::pin(" . to_string( ) ) , 
388+                                     ( expr. span. shrink_to_hi( ) ,  ")" . to_string( ) ) , 
389+                                 ] , 
390+                                 Applicability :: MaybeIncorrect , 
391+                             ) ; 
392+                         } 
393+                     } 
394+                     true 
395+                 }  else  if  self . can_coerce ( pin_found,  expected)  { 
396+                     match  found. kind ( )  { 
397+                         ty:: Adt ( def,  _)  if  def. is_box ( )  => { 
398+                             err. help ( "use `Box::pin`" ) ; 
399+                             true 
400+                         } 
401+                         _ => false , 
402+                     } 
403+                 }  else  { 
404+                     false 
393405                } 
394406            } 
395-             true 
396-         }  else  if  self . can_coerce ( pin_found,  expected)  { 
397-             match  found. kind ( )  { 
398-                 ty:: Adt ( def,  _)  if  def. is_box ( )  => { 
399-                     err. help ( "use `Box::pin`" ) ; 
400-                     true 
407+             ty:: Adt ( def,  _)  if  def. is_box ( )  && self . can_coerce ( box_found,  expected)  => { 
408+                 // Check if the parent expression is a call to Pin::new.  If it 
409+                 // is and we were expecting a Box, ergo Pin<Box<expected>>, we 
410+                 // can suggest Box::pin. 
411+                 let  parent = self . tcx . hir ( ) . get_parent_node ( expr. hir_id ) ; 
412+                 let  fn_name = match  self . tcx . hir ( ) . find ( parent)  { 
413+                     Some ( Node :: Expr ( Expr  {  kind :  ExprKind :: Call ( fn_name,  _) ,  .. } ) )  => fn_name, 
414+                     _ => return  false , 
415+                 } ; 
416+                 match  fn_name. kind  { 
417+                     ExprKind :: Path ( QPath :: TypeRelative ( 
418+                         hir:: Ty  { 
419+                             kind :  TyKind :: Path ( QPath :: Resolved ( _,  Path  {  res :  recv_ty,  .. } ) ) , 
420+                             ..
421+                         } , 
422+                         method, 
423+                     ) )  if  Some ( recv_ty. def_id ( ) )  == pin_did && method. ident . name  == sym:: new => { 
424+                         err. span_suggestion ( 
425+                             fn_name. span , 
426+                             "use `Box::pin` to pin and box this expression" , 
427+                             "Box::pin" . to_string ( ) , 
428+                             Applicability :: MachineApplicable , 
429+                         ) ; 
430+                         true 
431+                     } 
432+                     _ => false , 
401433                } 
402-                 _ => false , 
403434            } 
404-         }  else  { 
405-             false 
435+             _ => false , 
406436        } 
407437    } 
408438
0 commit comments