@@ -21,7 +21,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
21
21
22
22
use crate :: diagnostics:: BorrowedContentSource ;
23
23
use crate :: util:: FindAssignments ;
24
- use crate :: MirBorrowckCtxt ;
24
+ use crate :: { session_diagnostics , MirBorrowckCtxt } ;
25
25
26
26
#[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
27
27
pub ( crate ) enum AccessKind {
@@ -234,7 +234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
234
234
Some ( mir:: BorrowKind :: Mut { kind : mir:: MutBorrowKind :: Default } ) ,
235
235
|_kind, var_span| {
236
236
let place = self . describe_any_place ( access_place. as_ref ( ) ) ;
237
- crate :: session_diagnostics:: CaptureVarCause :: MutableBorrowUsePlaceClosure {
237
+ session_diagnostics:: CaptureVarCause :: MutableBorrowUsePlaceClosure {
238
238
place,
239
239
var_span,
240
240
}
@@ -667,19 +667,26 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
667
667
/// User cannot make signature of a trait mutable without changing the
668
668
/// trait. So we find if this error belongs to a trait and if so we move
669
669
/// 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 > ) {
671
677
if self . body . local_kind ( local) != LocalKind :: Arg {
672
- return ( false , None ) ;
678
+ return ( false , false , None ) ;
673
679
}
674
680
let my_def = self . body . source . def_id ( ) ;
675
681
let my_hir = self . infcx . tcx . local_def_id_to_hir_id ( my_def. as_local ( ) . unwrap ( ) ) ;
676
682
let Some ( td) =
677
683
self . infcx . tcx . impl_of_method ( my_def) . and_then ( |x| self . infcx . tcx . trait_id_of_impl ( x) )
678
684
else {
679
- return ( false , None ) ;
685
+ return ( false , false , None ) ;
680
686
} ;
681
687
(
682
688
true ,
689
+ td. is_local ( ) ,
683
690
td. as_local ( ) . and_then ( |tld| match self . infcx . tcx . hir_node_by_def_id ( tld) {
684
691
Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Trait ( _, _, _, _, items) , .. } ) => {
685
692
let mut f_in_trait_opt = None ;
@@ -695,19 +702,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
695
702
break ;
696
703
}
697
704
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
711
715
}
712
716
} )
713
717
}
@@ -1061,20 +1065,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
1061
1065
let ( pointer_sigil, pointer_desc) =
1062
1066
if local_decl. ty . is_ref ( ) { ( "&" , "reference" ) } else { ( "*const" , "pointer" ) } ;
1063
1067
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
+ ) ;
1066
1076
return ;
1067
1077
}
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 ;
1073
1079
1074
1080
let label = match * local_decl. local_info ( ) {
1075
1081
LocalInfo :: User ( mir:: BindingForm :: ImplicitSelf ( _) ) => {
1076
1082
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) )
1078
1086
}
1079
1087
1080
1088
LocalInfo :: User ( mir:: BindingForm :: Var ( mir:: VarBindingForm {
@@ -1113,7 +1121,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
1113
1121
// don't create labels for compiler-generated spans
1114
1122
Some ( _) => None ,
1115
1123
None => {
1116
- let label = if name != kw:: SelfLower {
1124
+ let ( has_sugg , decl_span , sugg ) = if name != kw:: SelfLower {
1117
1125
suggest_ampmut (
1118
1126
self . infcx . tcx ,
1119
1127
local_decl. ty ,
@@ -1140,7 +1148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
1140
1148
) ,
1141
1149
}
1142
1150
} ;
1143
- Some ( label )
1151
+ Some ( ( has_sugg , decl_span , sugg , None ) )
1144
1152
}
1145
1153
}
1146
1154
}
@@ -1151,22 +1159,33 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
1151
1159
} ) ) => {
1152
1160
let pattern_span: Span = local_decl. source_info . span ;
1153
1161
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 ) )
1155
1163
}
1156
1164
1157
1165
_ => unreachable ! ( ) ,
1158
1166
} ;
1159
1167
1160
1168
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,
1166
1185
Applicability :: MachineApplicable ,
1167
1186
) ;
1168
1187
}
1169
- Some ( ( false , err_label_span, message) ) => {
1188
+ Some ( ( false , err_label_span, message, _ ) ) => {
1170
1189
let def_id = self . body . source . def_id ( ) ;
1171
1190
let hir_id = if let Some ( local_def_id) = def_id. as_local ( )
1172
1191
&& let Some ( body_id) = self . infcx . tcx . hir ( ) . maybe_body_owned_by ( local_def_id)
0 commit comments