@@ -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