@@ -8,11 +8,11 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
8
8
use rustc_hir as hir;
9
9
use rustc_hir:: def:: { CtorOf , DefKind } ;
10
10
use 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 } ;
12
12
use rustc_infer:: infer;
13
13
use rustc_middle:: lint:: in_external_macro;
14
14
use rustc_middle:: ty:: { self , Binder , Ty } ;
15
- use rustc_span:: symbol:: kw ;
15
+ use rustc_span:: symbol:: { kw , sym } ;
16
16
17
17
use std:: iter;
18
18
@@ -350,6 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
350
350
}
351
351
352
352
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
353
+ #[ instrument( skip( self , err) ) ]
353
354
pub ( in super :: super ) fn suggest_calling_boxed_future_when_appropriate (
354
355
& self ,
355
356
err : & mut DiagnosticBuilder < ' _ > ,
@@ -368,41 +369,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368
369
if pin_did. is_none ( ) || self . tcx . lang_items ( ) . owned_box ( ) . is_none ( ) {
369
370
return false ;
370
371
}
371
- match expected. kind ( ) {
372
- ty:: Adt ( def, _) if Some ( def. did ) == pin_did => ( ) ,
373
- _ => return false ,
374
- }
375
372
let box_found = self . tcx . mk_box ( found) ;
376
373
let pin_box_found = self . tcx . mk_lang_item ( box_found, LangItem :: Pin ) . unwrap ( ) ;
377
374
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
393
405
}
394
406
}
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 ,
401
433
}
402
- _ => false ,
403
434
}
404
- } else {
405
- false
435
+ _ => false ,
406
436
}
407
437
}
408
438
0 commit comments