@@ -2494,10 +2494,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24942494 // Try alternative arbitrary self types that could fulfill this call.
24952495 // FIXME: probe for all types that *could* be arbitrary self-types, not
24962496 // 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+ ) ,
25012509 ] {
25022510 match self . lookup_probe_for_diagnostic (
25032511 item_name,
@@ -2531,6 +2539,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25312539 Err ( _) => ( ) ,
25322540 }
25332541
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+ ) ) ;
25342553 for ( rcvr_ty, pre) in & [
25352554 ( Ty :: new_lang_item ( self . tcx , * rcvr_ty, LangItem :: OwnedBox ) , "Box::new" ) ,
25362555 ( Ty :: new_lang_item ( self . tcx , * rcvr_ty, LangItem :: Pin ) , "Pin::new" ) ,
@@ -2554,7 +2573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25542573 // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
25552574 // implement the `AsRef` trait.
25562575 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 ) )
25582577 || 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) ;
25592578 // Make sure the method is defined for the *actual* receiver: we don't
25602579 // want to treat `Box<Self>` as a receiver if it only works because of
@@ -2566,7 +2585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25662585 ) ;
25672586 err. multipart_suggestion (
25682587 "consider wrapping the receiver expression with the \
2569- appropriate type",
2588+ appropriate type",
25702589 vec ! [
25712590 ( rcvr. span. shrink_to_lo( ) , format!( "{pre}({post}" ) ) ,
25722591 ( rcvr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
@@ -2578,6 +2597,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25782597 }
25792598 }
25802599 }
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+ }
25812643 }
25822644 }
25832645 if self . suggest_valid_traits ( err, valid_out_of_scope_traits) {
0 commit comments