@@ -649,39 +649,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
649649 }
650650 }
651651
652- fn borrow_pat_suggestion (
653- & self ,
654- err : & mut Diagnostic ,
655- pat : & Pat < ' _ > ,
656- inner : & Pat < ' _ > ,
657- expected : Ty < ' tcx > ,
658- ) {
652+ // Precondition: pat is a Ref(_) pattern
653+ fn borrow_pat_suggestion ( & self , err : & mut Diagnostic , pat : & Pat < ' _ > ) {
659654 let tcx = self . tcx ;
660- if let PatKind :: Binding ( ..) = inner. kind {
655+ if let PatKind :: Ref ( inner, mutbl) = pat. kind
656+ && let PatKind :: Binding ( _, _, binding, ..) = inner. kind {
661657 let binding_parent_id = tcx. hir ( ) . get_parent_node ( pat. hir_id ) ;
662658 let binding_parent = tcx. hir ( ) . get ( binding_parent_id) ;
663- debug ! ( "inner {:?} pat {:?} parent {:?}" , inner, pat, binding_parent) ;
659+ debug ! ( ?inner, ?pat, ?binding_parent) ;
660+
661+ let mutability = match mutbl {
662+ ast:: Mutability :: Mut => "mut" ,
663+ ast:: Mutability :: Not => "" ,
664+ } ;
665+
664666 match binding_parent {
665- hir:: Node :: Param ( hir:: Param { span, .. } )
666- if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( inner. span ) =>
667- {
668- err. span_suggestion (
669- * span,
670- & format ! ( "did you mean `{snippet}`" ) ,
671- format ! ( " &{expected}" ) ,
672- Applicability :: MachineApplicable ,
667+ // Check that there is explicit type (ie this is not a closure param with inferred type)
668+ // so we don't suggest moving something to the type that does not exist
669+ hir:: Node :: Param ( hir:: Param { ty_span, .. } ) if binding. span != * ty_span => {
670+ err. multipart_suggestion_verbose (
671+ format ! ( "to take parameter `{binding}` by reference, move `&{mutability}` to the type" ) ,
672+ vec ! [
673+ ( pat. span. until( inner. span) , "" . to_owned( ) ) ,
674+ ( ty_span. shrink_to_lo( ) , format!( "&{}" , mutbl. prefix_str( ) ) ) ,
675+ ] ,
676+ Applicability :: MachineApplicable
673677 ) ;
674678 }
675- hir:: Node :: Arm ( _) | hir:: Node :: Pat ( _) => {
679+ hir:: Node :: Param ( _ ) | hir :: Node :: Arm ( _) | hir:: Node :: Pat ( _) => {
676680 // rely on match ergonomics or it might be nested `&&pat`
677- if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( inner. span ) {
678- err. span_suggestion (
679- pat. span ,
680- "you can probably remove the explicit borrow" ,
681- snippet,
682- Applicability :: MaybeIncorrect ,
683- ) ;
684- }
681+ err. span_suggestion_verbose (
682+ pat. span . until ( inner. span ) ,
683+ format ! ( "consider removing `&{mutability}` from the pattern" ) ,
684+ "" ,
685+ Applicability :: MaybeIncorrect ,
686+ ) ;
685687 }
686688 _ => { } // don't provide suggestions in other cases #55175
687689 }
@@ -1836,6 +1838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18361838 box_ty
18371839 }
18381840
1841+ // Precondition: Pat is Ref(inner)
18391842 fn check_pat_ref (
18401843 & self ,
18411844 pat : & ' tcx Pat < ' tcx > ,
@@ -1853,7 +1856,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18531856
18541857 // Take region, inner-type from expected type if we can,
18551858 // to avoid creating needless variables. This also helps with
1856- // the bad interactions of the given hack detailed in (note_1).
1859+ // the bad interactions of the given hack detailed in (note_1).
18571860 debug ! ( "check_pat_ref: expected={:?}" , expected) ;
18581861 match * expected. kind ( ) {
18591862 ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == mutbl => ( expected, r_ty) ,
@@ -1869,7 +1872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18691872 // Look for a case like `fn foo(&foo: u32)` and suggest
18701873 // `fn foo(foo: &u32)`
18711874 if let Some ( mut err) = err {
1872- self . borrow_pat_suggestion ( & mut err, pat, inner , expected ) ;
1875+ self . borrow_pat_suggestion ( & mut err, pat) ;
18731876 err. emit ( ) ;
18741877 }
18751878 ( rptr_ty, inner_ty)
0 commit comments