@@ -21,7 +21,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
2121
2222use crate :: diagnostics:: BorrowedContentSource ;
2323use crate :: util:: FindAssignments ;
24- use crate :: MirBorrowckCtxt ;
24+ use crate :: { session_diagnostics , MirBorrowckCtxt } ;
2525
2626#[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
2727pub ( crate ) enum AccessKind {
@@ -234,7 +234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
234234 Some ( mir:: BorrowKind :: Mut { kind : mir:: MutBorrowKind :: Default } ) ,
235235 |_kind, var_span| {
236236 let place = self . describe_any_place ( access_place. as_ref ( ) ) ;
237- crate :: session_diagnostics:: CaptureVarCause :: MutableBorrowUsePlaceClosure {
237+ session_diagnostics:: CaptureVarCause :: MutableBorrowUsePlaceClosure {
238238 place,
239239 var_span,
240240 }
@@ -667,19 +667,26 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
667667 /// User cannot make signature of a trait mutable without changing the
668668 /// trait. So we find if this error belongs to a trait and if so we move
669669 /// suggestion to the trait or disable it if it is out of scope of this crate
670- fn is_error_in_trait ( & self , local : Local ) -> ( bool , Option < Span > ) {
670+ ///
671+ /// The returned values are:
672+ /// - is the current item an assoc `fn` of an impl that corresponds to a trait def? if so, we
673+ /// have to suggest changing both the impl `fn` arg and the trait `fn` arg
674+ /// - is the trait from the local crate? If not, we can't suggest changing signatures
675+ /// - `Span` of the argument in the trait definition
676+ fn is_error_in_trait ( & self , local : Local ) -> ( bool , bool , Option < Span > ) {
671677 if self . body . local_kind ( local) != LocalKind :: Arg {
672- return ( false , None ) ;
678+ return ( false , false , None ) ;
673679 }
674680 let my_def = self . body . source . def_id ( ) ;
675681 let my_hir = self . infcx . tcx . local_def_id_to_hir_id ( my_def. as_local ( ) . unwrap ( ) ) ;
676682 let Some ( td) =
677683 self . infcx . tcx . impl_of_method ( my_def) . and_then ( |x| self . infcx . tcx . trait_id_of_impl ( x) )
678684 else {
679- return ( false , None ) ;
685+ return ( false , false , None ) ;
680686 } ;
681687 (
682688 true ,
689+ td. is_local ( ) ,
683690 td. as_local ( ) . and_then ( |tld| match self . infcx . tcx . hir_node_by_def_id ( tld) {
684691 Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Trait ( _, _, _, _, items) , .. } ) => {
685692 let mut f_in_trait_opt = None ;
@@ -695,19 +702,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
695702 break ;
696703 }
697704 f_in_trait_opt. and_then ( |f_in_trait| {
698- match self . infcx . tcx . hir_node ( f_in_trait) {
699- Node :: TraitItem ( hir:: TraitItem {
700- kind :
701- hir:: TraitItemKind :: Fn (
702- hir:: FnSig { decl : hir:: FnDecl { inputs, .. } , .. } ,
703- _,
704- ) ,
705- ..
706- } ) => {
707- let hir:: Ty { span, .. } = * inputs. get ( local. index ( ) - 1 ) ?;
708- Some ( span)
709- }
710- _ => None ,
705+ if let Node :: TraitItem ( ti) = self . infcx . tcx . hir_node ( f_in_trait)
706+ && let hir:: TraitItemKind :: Fn ( sig, _) = ti. kind
707+ && let Some ( ty) = sig. decl . inputs . get ( local. index ( ) - 1 )
708+ && let hir:: TyKind :: Ref ( _, mut_ty) = ty. kind
709+ && let hir:: Mutability :: Not = mut_ty. mutbl
710+ && sig. decl . implicit_self . has_implicit_self ( )
711+ {
712+ Some ( ty. span )
713+ } else {
714+ None
711715 }
712716 } )
713717 }
@@ -1061,20 +1065,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
10611065 let ( pointer_sigil, pointer_desc) =
10621066 if local_decl. ty . is_ref ( ) { ( "&" , "reference" ) } else { ( "*const" , "pointer" ) } ;
10631067
1064- let ( is_trait_sig, local_trait) = self . is_error_in_trait ( local) ;
1065- if is_trait_sig && local_trait. is_none ( ) {
1068+ let ( is_trait_sig, is_local, local_trait) = self . is_error_in_trait ( local) ;
1069+
1070+ if is_trait_sig && !is_local {
1071+ // Do not suggest to change the signature when the trait comes from another crate.
1072+ err. span_label (
1073+ local_decl. source_info . span ,
1074+ format ! ( "this is an immutable {pointer_desc}" ) ,
1075+ ) ;
10661076 return ;
10671077 }
1068-
1069- let decl_span = match local_trait {
1070- Some ( span) => span,
1071- None => local_decl. source_info . span ,
1072- } ;
1078+ let decl_span = local_decl. source_info . span ;
10731079
10741080 let label = match * local_decl. local_info ( ) {
10751081 LocalInfo :: User ( mir:: BindingForm :: ImplicitSelf ( _) ) => {
10761082 let suggestion = suggest_ampmut_self ( self . infcx . tcx , decl_span) ;
1077- Some ( ( true , decl_span, suggestion) )
1083+ let additional =
1084+ local_trait. map ( |span| ( span, suggest_ampmut_self ( self . infcx . tcx , span) ) ) ;
1085+ Some ( ( true , decl_span, suggestion, additional) )
10781086 }
10791087
10801088 LocalInfo :: User ( mir:: BindingForm :: Var ( mir:: VarBindingForm {
@@ -1113,7 +1121,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
11131121 // don't create labels for compiler-generated spans
11141122 Some ( _) => None ,
11151123 None => {
1116- let label = if name != kw:: SelfLower {
1124+ let ( has_sugg , decl_span , sugg ) = if name != kw:: SelfLower {
11171125 suggest_ampmut (
11181126 self . infcx . tcx ,
11191127 local_decl. ty ,
@@ -1140,7 +1148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
11401148 ) ,
11411149 }
11421150 } ;
1143- Some ( label )
1151+ Some ( ( has_sugg , decl_span , sugg , None ) )
11441152 }
11451153 }
11461154 }
@@ -1151,22 +1159,33 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
11511159 } ) ) => {
11521160 let pattern_span: Span = local_decl. source_info . span ;
11531161 suggest_ref_mut ( self . infcx . tcx , pattern_span)
1154- . map ( |span| ( true , span, "mut " . to_owned ( ) ) )
1162+ . map ( |span| ( true , span, "mut " . to_owned ( ) , None ) )
11551163 }
11561164
11571165 _ => unreachable ! ( ) ,
11581166 } ;
11591167
11601168 match label {
1161- Some ( ( true , err_help_span, suggested_code) ) => {
1162- err. span_suggestion_verbose (
1163- err_help_span,
1164- format ! ( "consider changing this to be a mutable {pointer_desc}" ) ,
1165- suggested_code,
1169+ Some ( ( true , err_help_span, suggested_code, additional) ) => {
1170+ let mut sugg = vec ! [ ( err_help_span, suggested_code) ] ;
1171+ if let Some ( s) = additional {
1172+ sugg. push ( s) ;
1173+ }
1174+
1175+ err. multipart_suggestion_verbose (
1176+ format ! (
1177+ "consider changing this to be a mutable {pointer_desc}{}" ,
1178+ if is_trait_sig {
1179+ " in the `impl` method and the `trait` definition"
1180+ } else {
1181+ ""
1182+ }
1183+ ) ,
1184+ sugg,
11661185 Applicability :: MachineApplicable ,
11671186 ) ;
11681187 }
1169- Some ( ( false , err_label_span, message) ) => {
1188+ Some ( ( false , err_label_span, message, _ ) ) => {
11701189 let def_id = self . body . source . def_id ( ) ;
11711190 let hir_id = if let Some ( local_def_id) = def_id. as_local ( )
11721191 && let Some ( body_id) = self . infcx . tcx . hir ( ) . maybe_body_owned_by ( local_def_id)
0 commit comments