@@ -42,7 +42,6 @@ use std::fmt;
42
42
use std:: rc:: Rc ;
43
43
use std:: hash:: { Hash , Hasher } ;
44
44
use syntax:: ast;
45
- use syntax:: symbol:: keywords;
46
45
use syntax_pos:: { MultiSpan , Span } ;
47
46
use errors:: DiagnosticBuilder ;
48
47
@@ -809,32 +808,33 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
809
808
}
810
809
811
810
/// Given a type, if it is an immutable reference, return a suggestion to make it mutable
812
- fn suggest_mut_for_immutable ( & self , pty : & hir:: Ty ) -> Option < String > {
811
+ fn suggest_mut_for_immutable ( & self , pty : & hir:: Ty , is_implicit_self : bool ) -> Option < String > {
813
812
// Check wether the argument is an immutable reference
813
+ debug ! ( "suggest_mut_for_immutable({:?}, {:?})" , pty, is_implicit_self) ;
814
814
if let hir:: TyRptr ( lifetime, hir:: MutTy {
815
815
mutbl : hir:: Mutability :: MutImmutable ,
816
816
ref ty
817
817
} ) = pty. node {
818
818
// Account for existing lifetimes when generating the message
819
- if !lifetime. is_elided ( ) {
820
- if let Ok ( snippet) = self . tcx . sess . codemap ( ) . span_to_snippet ( ty. span ) {
821
- if let Ok ( lifetime_snippet) = self . tcx . sess . codemap ( )
822
- . span_to_snippet ( lifetime. span ) {
823
- return Some ( format ! ( "use `&{} mut {}` here to make mutable" ,
824
- lifetime_snippet,
825
- snippet) ) ;
826
- }
827
- }
828
- } else if let Ok ( snippet) = self . tcx . sess . codemap ( ) . span_to_snippet ( pty. span ) {
829
- if snippet. starts_with ( "&" ) {
830
- return Some ( format ! ( "use `{}` here to make mutable" ,
831
- snippet. replace( "&" , "&mut " ) ) ) ;
832
- }
819
+ let pointee_snippet = match self . tcx . sess . codemap ( ) . span_to_snippet ( ty. span ) {
820
+ Ok ( snippet) => snippet,
821
+ _ => return None
822
+ } ;
823
+
824
+ let lifetime_snippet = if !lifetime. is_elided ( ) {
825
+ format ! ( "{} " , match self . tcx. sess. codemap( ) . span_to_snippet( lifetime. span) {
826
+ Ok ( lifetime_snippet) => lifetime_snippet,
827
+ _ => return None
828
+ } )
833
829
} else {
834
- bug ! ( "couldn't find a snippet for span: {:?}" , pty. span) ;
835
- }
830
+ String :: new ( )
831
+ } ;
832
+ Some ( format ! ( "use `&{}mut {}` here to make mutable" ,
833
+ lifetime_snippet,
834
+ if is_implicit_self { "self" } else { & * pointee_snippet } ) )
835
+ } else {
836
+ None
836
837
}
837
- None
838
838
}
839
839
840
840
fn local_binding_mode ( & self , node_id : ast:: NodeId ) -> hir:: BindingMode {
@@ -849,24 +849,25 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
849
849
}
850
850
}
851
851
852
- fn local_ty ( & self , node_id : ast:: NodeId ) -> Option < & hir:: Ty > {
852
+ fn local_ty ( & self , node_id : ast:: NodeId ) -> ( Option < & hir:: Ty > , bool ) {
853
853
let parent = self . tcx . hir . get_parent_node ( node_id) ;
854
854
let parent_node = self . tcx . hir . get ( parent) ;
855
855
856
856
// The parent node is like a fn
857
857
if let Some ( fn_like) = FnLikeNode :: from_node ( parent_node) {
858
858
// `nid`'s parent's `Body`
859
859
let fn_body = self . tcx . hir . body ( fn_like. body ( ) ) ;
860
- // Get the position of `nid ` in the arguments list
860
+ // Get the position of `node_id ` in the arguments list
861
861
let arg_pos = fn_body. arguments . iter ( ) . position ( |arg| arg. pat . id == node_id) ;
862
862
if let Some ( i) = arg_pos {
863
863
// The argument's `Ty`
864
- Some ( & fn_like. decl ( ) . inputs [ i] )
864
+ ( Some ( & fn_like. decl ( ) . inputs [ i] ) ,
865
+ i == 0 && fn_like. decl ( ) . has_implicit_self )
865
866
} else {
866
- None
867
+ ( None , false )
867
868
}
868
869
} else {
869
- None
870
+ ( None , false )
870
871
}
871
872
}
872
873
@@ -880,8 +881,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
880
881
let let_span = self . tcx . hir . span ( node_id) ;
881
882
if let hir:: BindingMode :: BindByValue ( ..) = self . local_binding_mode ( node_id) {
882
883
if let Ok ( snippet) = self . tcx . sess . codemap ( ) . span_to_snippet ( let_span) {
883
- if self . tcx . hir . name ( node_id ) == keywords :: SelfValue . name ( ) &&
884
- snippet != "self" {
884
+ let ( _ , is_implicit_self ) = self . local_ty ( node_id ) ;
885
+ if is_implicit_self && snippet != "self" {
885
886
// avoid suggesting `mut &self`.
886
887
return
887
888
}
@@ -906,8 +907,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
906
907
}
907
908
}
908
909
hir:: BindingMode :: BindByValue ( ..) => {
909
- if let Some ( local_ty) = self . local_ty ( node_id) {
910
- if let Some ( msg) = self . suggest_mut_for_immutable ( local_ty) {
910
+ if let ( Some ( local_ty) , is_implicit_self) = self . local_ty ( node_id) {
911
+ if let Some ( msg) =
912
+ self . suggest_mut_for_immutable ( local_ty, is_implicit_self) {
911
913
db. span_label ( local_ty. span , & msg) ;
912
914
}
913
915
}
@@ -921,7 +923,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
921
923
} ;
922
924
923
925
if let hir_map:: Node :: NodeField ( ref field) = self . tcx . hir . get ( node_id) {
924
- if let Some ( msg) = self . suggest_mut_for_immutable ( & field. ty ) {
926
+ if let Some ( msg) = self . suggest_mut_for_immutable ( & field. ty , false ) {
925
927
db. span_label ( field. ty . span , & msg) ;
926
928
}
927
929
}
0 commit comments