@@ -6,7 +6,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
66use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
77use rustc_middle:: {
88 hir:: place:: PlaceBase ,
9- mir:: { self , ClearCrossCrate , Local , LocalDecl , LocalInfo , Location } ,
9+ mir:: { self , ClearCrossCrate , Local , LocalDecl , LocalInfo , LocalKind , Location } ,
1010} ;
1111use rustc_span:: source_map:: DesugaringKind ;
1212use rustc_span:: symbol:: { kw, Symbol } ;
@@ -424,15 +424,28 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
424424
425425 match label {
426426 Some ( ( true , err_help_span, suggested_code) ) => {
427- err. span_suggestion (
428- err_help_span,
429- & format ! (
430- "consider changing this to be a mutable {}" ,
431- pointer_desc
432- ) ,
433- suggested_code,
434- Applicability :: MachineApplicable ,
435- ) ;
427+ let ( is_trait_sig, local_trait) = self . is_error_in_trait ( local) ;
428+ if !is_trait_sig {
429+ err. span_suggestion (
430+ err_help_span,
431+ & format ! (
432+ "consider changing this to be a mutable {}" ,
433+ pointer_desc
434+ ) ,
435+ suggested_code,
436+ Applicability :: MachineApplicable ,
437+ ) ;
438+ } else if let Some ( x) = local_trait {
439+ err. span_suggestion (
440+ x,
441+ & format ! (
442+ "consider changing that to be a mutable {}" ,
443+ pointer_desc
444+ ) ,
445+ suggested_code,
446+ Applicability :: MachineApplicable ,
447+ ) ;
448+ }
436449 }
437450 Some ( ( false , err_label_span, message) ) => {
438451 err. span_label ( err_label_span, & message) ;
@@ -503,6 +516,65 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
503516 err. buffer ( & mut self . errors_buffer ) ;
504517 }
505518
519+ /// User cannot make signature of a trait mutable without changing the
520+ /// trait. So we find if this error belongs to a trait and if so we move
521+ /// suggestion to the trait or disable it if it is out of scope of this crate
522+ fn is_error_in_trait ( & self , local : Local ) -> ( bool , Option < Span > ) {
523+ if self . body . local_kind ( local) != LocalKind :: Arg {
524+ return ( false , None ) ;
525+ }
526+ let hir_map = self . infcx . tcx . hir ( ) ;
527+ let my_def = self . body . source . def_id ( ) ;
528+ let my_hir = hir_map. local_def_id_to_hir_id ( my_def. as_local ( ) . unwrap ( ) ) ;
529+ let td = if let Some ( a) =
530+ self . infcx . tcx . impl_of_method ( my_def) . and_then ( |x| self . infcx . tcx . trait_id_of_impl ( x) )
531+ {
532+ a
533+ } else {
534+ return ( false , None ) ;
535+ } ;
536+ (
537+ true ,
538+ td. as_local ( ) . and_then ( |tld| {
539+ let h = hir_map. local_def_id_to_hir_id ( tld) ;
540+ match hir_map. find ( h) {
541+ Some ( Node :: Item ( hir:: Item {
542+ kind : hir:: ItemKind :: Trait ( _, _, _, _, items) ,
543+ ..
544+ } ) ) => {
545+ let mut f_in_trait_opt = None ;
546+ for hir:: TraitItemRef { id : fi, kind : k, .. } in * items {
547+ let hi = fi. hir_id ( ) ;
548+ if !matches ! ( k, hir:: AssocItemKind :: Fn { .. } ) {
549+ continue ;
550+ }
551+ if hir_map. name ( hi) != hir_map. name ( my_hir) {
552+ continue ;
553+ }
554+ f_in_trait_opt = Some ( hi) ;
555+ break ;
556+ }
557+ f_in_trait_opt. and_then ( |f_in_trait| match hir_map. find ( f_in_trait) {
558+ Some ( Node :: TraitItem ( hir:: TraitItem {
559+ kind :
560+ hir:: TraitItemKind :: Fn (
561+ hir:: FnSig { decl : hir:: FnDecl { inputs, .. } , .. } ,
562+ _,
563+ ) ,
564+ ..
565+ } ) ) => {
566+ let hir:: Ty { span, .. } = inputs[ local. index ( ) - 1 ] ;
567+ Some ( span)
568+ }
569+ _ => None ,
570+ } )
571+ }
572+ _ => None ,
573+ }
574+ } ) ,
575+ )
576+ }
577+
506578 // point to span of upvar making closure call require mutable borrow
507579 fn show_mutating_upvar (
508580 & self ,
0 commit comments