@@ -453,21 +453,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
453
453
}
454
454
}
455
455
456
- fn find_similar_impl_candidates ( & self ,
457
- trait_ref : ty:: PolyTraitRef < ' tcx > )
458
- -> Vec < ty:: TraitRef < ' tcx > >
459
- {
460
- let simp = fast_reject:: simplify_type ( self . tcx ,
461
- trait_ref. skip_binder ( ) . self_ty ( ) ,
462
- true ) ;
456
+ fn find_similar_impl_candidates (
457
+ & self ,
458
+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
459
+ ) -> Vec < ty:: TraitRef < ' tcx > > {
460
+ let simp = fast_reject:: simplify_type ( self . tcx , trait_ref. skip_binder ( ) . self_ty ( ) , true ) ;
463
461
let all_impls = self . tcx . all_impls ( trait_ref. def_id ( ) ) ;
464
462
465
463
match simp {
466
464
Some ( simp) => all_impls. iter ( ) . filter_map ( |& def_id| {
467
465
let imp = self . tcx . impl_trait_ref ( def_id) . unwrap ( ) ;
468
- let imp_simp = fast_reject:: simplify_type ( self . tcx ,
469
- imp. self_ty ( ) ,
470
- true ) ;
466
+ let imp_simp = fast_reject:: simplify_type ( self . tcx , imp. self_ty ( ) , true ) ;
471
467
if let Some ( imp_simp) = imp_simp {
472
468
if simp != imp_simp {
473
469
return None
@@ -482,10 +478,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
482
478
}
483
479
}
484
480
485
- fn report_similar_impl_candidates ( & self ,
486
- impl_candidates : Vec < ty:: TraitRef < ' tcx > > ,
487
- err : & mut DiagnosticBuilder < ' _ > )
488
- {
481
+ fn report_similar_impl_candidates (
482
+ & self ,
483
+ impl_candidates : Vec < ty:: TraitRef < ' tcx > > ,
484
+ err : & mut DiagnosticBuilder < ' _ > ,
485
+ ) {
489
486
if impl_candidates. is_empty ( ) {
490
487
return ;
491
488
}
@@ -720,10 +717,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
720
717
// which is somewhat confusing.
721
718
err. help ( & format ! ( "consider adding a `where {}` bound" ,
722
719
trait_ref. to_predicate( ) ) ) ;
723
- } else if !have_alt_message {
724
- // Can't show anything else useful, try to find similar impls.
725
- let impl_candidates = self . find_similar_impl_candidates ( trait_ref) ;
726
- self . report_similar_impl_candidates ( impl_candidates, & mut err) ;
720
+ } else {
721
+ if !have_alt_message {
722
+ // Can't show anything else useful, try to find similar impls.
723
+ let impl_candidates = self . find_similar_impl_candidates ( trait_ref) ;
724
+ self . report_similar_impl_candidates ( impl_candidates, & mut err) ;
725
+ }
726
+ self . suggest_change_mut (
727
+ & obligation,
728
+ & mut err,
729
+ & trait_ref,
730
+ points_at_arg,
731
+ ) ;
727
732
}
728
733
729
734
// If this error is due to `!: Trait` not implemented but `(): Trait` is
@@ -1081,9 +1086,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1081
1086
1082
1087
let substs = self . tcx . mk_substs_trait ( trait_type, & [ ] ) ;
1083
1088
let new_trait_ref = ty:: TraitRef :: new ( trait_ref. def_id , substs) ;
1084
- let new_obligation = Obligation :: new ( ObligationCause :: dummy ( ) ,
1085
- obligation. param_env ,
1086
- new_trait_ref. to_predicate ( ) ) ;
1089
+ let new_obligation = Obligation :: new (
1090
+ ObligationCause :: dummy ( ) ,
1091
+ obligation. param_env ,
1092
+ new_trait_ref. to_predicate ( ) ,
1093
+ ) ;
1087
1094
1088
1095
if self . predicate_may_hold ( & new_obligation) {
1089
1096
let sp = self . tcx . sess . source_map ( )
@@ -1105,6 +1112,77 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1105
1112
}
1106
1113
}
1107
1114
1115
+ /// Check if the trait bound is implemented for a different mutability and note it in the
1116
+ /// final error.
1117
+ fn suggest_change_mut (
1118
+ & self ,
1119
+ obligation : & PredicateObligation < ' tcx > ,
1120
+ err : & mut DiagnosticBuilder < ' tcx > ,
1121
+ trait_ref : & ty:: Binder < ty:: TraitRef < ' tcx > > ,
1122
+ points_at_arg : bool ,
1123
+ ) {
1124
+ let span = obligation. cause . span ;
1125
+ if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
1126
+ let refs_number = snippet. chars ( )
1127
+ . filter ( |c| !c. is_whitespace ( ) )
1128
+ . take_while ( |c| * c == '&' )
1129
+ . count ( ) ;
1130
+ if let Some ( '\'' ) = snippet. chars ( )
1131
+ . filter ( |c| !c. is_whitespace ( ) )
1132
+ . skip ( refs_number)
1133
+ . next ( )
1134
+ { // Do not suggest removal of borrow from type arguments.
1135
+ return ;
1136
+ }
1137
+ let trait_ref = self . resolve_vars_if_possible ( trait_ref) ;
1138
+ if trait_ref. has_infer_types ( ) {
1139
+ // Do not ICE while trying to find if a reborrow would succeed on a trait with
1140
+ // unresolved bindings.
1141
+ return ;
1142
+ }
1143
+
1144
+ if let ty:: Ref ( region, t_type, mutability) = trait_ref. skip_binder ( ) . self_ty ( ) . kind {
1145
+ let trait_type = match mutability {
1146
+ hir:: Mutability :: MutMutable => self . tcx . mk_imm_ref ( region, t_type) ,
1147
+ hir:: Mutability :: MutImmutable => self . tcx . mk_mut_ref ( region, t_type) ,
1148
+ } ;
1149
+
1150
+ let substs = self . tcx . mk_substs_trait ( & trait_type, & [ ] ) ;
1151
+ let new_trait_ref = ty:: TraitRef :: new ( trait_ref. skip_binder ( ) . def_id , substs) ;
1152
+ let new_obligation = Obligation :: new (
1153
+ ObligationCause :: dummy ( ) ,
1154
+ obligation. param_env ,
1155
+ new_trait_ref. to_predicate ( ) ,
1156
+ ) ;
1157
+
1158
+ if self . evaluate_obligation_no_overflow (
1159
+ & new_obligation,
1160
+ ) . must_apply_modulo_regions ( ) {
1161
+ let sp = self . tcx . sess . source_map ( )
1162
+ . span_take_while ( span, |c| c. is_whitespace ( ) || * c == '&' ) ;
1163
+ if points_at_arg &&
1164
+ mutability == hir:: Mutability :: MutImmutable &&
1165
+ refs_number > 0
1166
+ {
1167
+ err. span_suggestion (
1168
+ sp,
1169
+ "consider changing this borrow's mutability" ,
1170
+ "&mut " . to_string ( ) ,
1171
+ Applicability :: MachineApplicable ,
1172
+ ) ;
1173
+ } else {
1174
+ err. note ( & format ! (
1175
+ "`{}` is implemented for `{:?}`, but not for `{:?}`" ,
1176
+ trait_ref,
1177
+ trait_type,
1178
+ trait_ref. skip_binder( ) . self_ty( ) ,
1179
+ ) ) ;
1180
+ }
1181
+ }
1182
+ }
1183
+ }
1184
+ }
1185
+
1108
1186
fn suggest_semicolon_removal (
1109
1187
& self ,
1110
1188
obligation : & PredicateObligation < ' tcx > ,
0 commit comments