@@ -2494,10 +2494,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2494
2494
// Try alternative arbitrary self types that could fulfill this call.
2495
2495
// FIXME: probe for all types that *could* be arbitrary self-types, not
2496
2496
// just this list.
2497
- for ( rcvr_ty, post) in & [
2498
- ( rcvr_ty, "" ) ,
2499
- ( Ty :: new_mut_ref ( self . tcx , self . tcx . lifetimes . re_erased , rcvr_ty) , "&mut " ) ,
2500
- ( Ty :: new_imm_ref ( self . tcx , self . tcx . lifetimes . re_erased , rcvr_ty) , "&" ) ,
2497
+ for ( rcvr_ty, post, pin_call) in & [
2498
+ ( rcvr_ty, "" , None ) ,
2499
+ (
2500
+ Ty :: new_mut_ref ( self . tcx , self . tcx . lifetimes . re_erased , rcvr_ty) ,
2501
+ "&mut " ,
2502
+ Some ( "as_mut" ) ,
2503
+ ) ,
2504
+ (
2505
+ Ty :: new_imm_ref ( self . tcx , self . tcx . lifetimes . re_erased , rcvr_ty) ,
2506
+ "&" ,
2507
+ Some ( "as_ref" ) ,
2508
+ ) ,
2501
2509
] {
2502
2510
match self . lookup_probe_for_diagnostic (
2503
2511
item_name,
@@ -2531,6 +2539,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2531
2539
Err ( _) => ( ) ,
2532
2540
}
2533
2541
2542
+ let pred = ty:: TraitRef :: new (
2543
+ self . tcx ,
2544
+ self . tcx . lang_items ( ) . unpin_trait ( ) . unwrap ( ) ,
2545
+ [ * rcvr_ty] ,
2546
+ ) ;
2547
+ let unpin = self . predicate_must_hold_considering_regions ( & Obligation :: new (
2548
+ self . tcx ,
2549
+ ObligationCause :: misc ( rcvr. span , self . body_id ) ,
2550
+ self . param_env ,
2551
+ pred,
2552
+ ) ) ;
2534
2553
for ( rcvr_ty, pre) in & [
2535
2554
( Ty :: new_lang_item ( self . tcx , * rcvr_ty, LangItem :: OwnedBox ) , "Box::new" ) ,
2536
2555
( Ty :: new_lang_item ( self . tcx , * rcvr_ty, LangItem :: Pin ) , "Pin::new" ) ,
@@ -2554,7 +2573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2554
2573
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
2555
2574
// implement the `AsRef` trait.
2556
2575
let skip = skippable. contains ( & did)
2557
- || ( ( "Pin::new" == * pre) && ( sym:: as_ref == item_name. name ) )
2576
+ || ( ( "Pin::new" == * pre) && ( ( sym:: as_ref == item_name. name ) || !unpin ) )
2558
2577
|| inputs_len. is_some_and ( |inputs_len| pick. item . kind == ty:: AssocKind :: Fn && self . tcx . fn_sig ( pick. item . def_id ) . skip_binder ( ) . skip_binder ( ) . inputs ( ) . len ( ) != inputs_len) ;
2559
2578
// Make sure the method is defined for the *actual* receiver: we don't
2560
2579
// want to treat `Box<Self>` as a receiver if it only works because of
@@ -2566,7 +2585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2566
2585
) ;
2567
2586
err. multipart_suggestion (
2568
2587
"consider wrapping the receiver expression with the \
2569
- appropriate type",
2588
+ appropriate type",
2570
2589
vec ! [
2571
2590
( rcvr. span. shrink_to_lo( ) , format!( "{pre}({post}" ) ) ,
2572
2591
( rcvr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
@@ -2578,6 +2597,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2578
2597
}
2579
2598
}
2580
2599
}
2600
+ // We special case the situation where `Pin::new` wouldn't work, and instead
2601
+ // suggest using the `pin!()` macro instead.
2602
+ if let Some ( new_rcvr_t) = Ty :: new_lang_item ( self . tcx , * rcvr_ty, LangItem :: Pin )
2603
+ // We didn't find an alternative receiver for the method.
2604
+ && !alt_rcvr_sugg
2605
+ // `T: !Unpin`
2606
+ && !unpin
2607
+ // The method isn't `as_ref`, as it would provide a wrong suggestion for `Pin`.
2608
+ && sym:: as_ref != item_name. name
2609
+ // Either `Pin::as_ref` or `Pin::as_mut`.
2610
+ && let Some ( pin_call) = pin_call
2611
+ // Search for `item_name` as a method accessible on `Pin<T>`.
2612
+ && let Ok ( pick) = self . lookup_probe_for_diagnostic (
2613
+ item_name,
2614
+ new_rcvr_t,
2615
+ rcvr,
2616
+ ProbeScope :: AllTraits ,
2617
+ return_type,
2618
+ )
2619
+ // We skip some common traits that we don't want to consider because autoderefs
2620
+ // would take care of them.
2621
+ && !skippable. contains ( & Some ( pick. item . container_id ( self . tcx ) ) )
2622
+ // We don't want to go through derefs.
2623
+ && pick. autoderefs == 0
2624
+ // Check that the method of the same name that was found on the new `Pin<T>`
2625
+ // receiver has the same number of arguments that appear in the user's code.
2626
+ && inputs_len. is_some_and ( |inputs_len| pick. item . kind == ty:: AssocKind :: Fn && self . tcx . fn_sig ( pick. item . def_id ) . skip_binder ( ) . skip_binder ( ) . inputs ( ) . len ( ) == inputs_len)
2627
+ {
2628
+ let indent = self . tcx . sess
2629
+ . source_map ( )
2630
+ . indentation_before ( rcvr. span )
2631
+ . unwrap_or_else ( || " " . to_string ( ) ) ;
2632
+ err. multipart_suggestion (
2633
+ "consider pinning the expression" ,
2634
+ vec ! [
2635
+ ( rcvr. span. shrink_to_lo( ) , format!( "let mut pinned = std::pin::pin!(" ) ) ,
2636
+ ( rcvr. span. shrink_to_hi( ) , format!( ");\n {indent}pinned.{pin_call}()" ) ) ,
2637
+ ] ,
2638
+ Applicability :: MaybeIncorrect ,
2639
+ ) ;
2640
+ // We don't care about the other suggestions.
2641
+ alt_rcvr_sugg = true ;
2642
+ }
2581
2643
}
2582
2644
}
2583
2645
if self . suggest_valid_traits ( err, valid_out_of_scope_traits) {
0 commit comments