@@ -649,39 +649,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
649
649
}
650
650
}
651
651
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 < ' _ > ) {
659
654
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 {
661
657
let binding_parent_id = tcx. hir ( ) . get_parent_node ( pat. hir_id ) ;
662
658
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
+
664
666
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
673
677
) ;
674
678
}
675
- hir:: Node :: Arm ( _) | hir:: Node :: Pat ( _) => {
679
+ hir:: Node :: Param ( _ ) | hir :: Node :: Arm ( _) | hir:: Node :: Pat ( _) => {
676
680
// 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
+ ) ;
685
687
}
686
688
_ => { } // don't provide suggestions in other cases #55175
687
689
}
@@ -1836,6 +1838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1836
1838
box_ty
1837
1839
}
1838
1840
1841
+ // Precondition: Pat is Ref(inner)
1839
1842
fn check_pat_ref (
1840
1843
& self ,
1841
1844
pat : & ' tcx Pat < ' tcx > ,
@@ -1853,7 +1856,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1853
1856
1854
1857
// Take region, inner-type from expected type if we can,
1855
1858
// 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).
1857
1860
debug ! ( "check_pat_ref: expected={:?}" , expected) ;
1858
1861
match * expected. kind ( ) {
1859
1862
ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == mutbl => ( expected, r_ty) ,
@@ -1869,7 +1872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1869
1872
// Look for a case like `fn foo(&foo: u32)` and suggest
1870
1873
// `fn foo(foo: &u32)`
1871
1874
if let Some ( mut err) = err {
1872
- self . borrow_pat_suggestion ( & mut err, pat, inner , expected ) ;
1875
+ self . borrow_pat_suggestion ( & mut err, pat) ;
1873
1876
err. emit ( ) ;
1874
1877
}
1875
1878
( rptr_ty, inner_ty)
0 commit comments