@@ -453,21 +453,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
453453 }
454454 }
455455
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 ) ;
463461 let all_impls = self . tcx . all_impls ( trait_ref. def_id ( ) ) ;
464462
465463 match simp {
466464 Some ( simp) => all_impls. iter ( ) . filter_map ( |& def_id| {
467465 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 ) ;
471467 if let Some ( imp_simp) = imp_simp {
472468 if simp != imp_simp {
473469 return None
@@ -482,10 +478,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
482478 }
483479 }
484480
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+ ) {
489486 if impl_candidates. is_empty ( ) {
490487 return ;
491488 }
@@ -720,10 +717,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
720717 // which is somewhat confusing.
721718 err. help ( & format ! ( "consider adding a `where {}` bound" ,
722719 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+ ) ;
727732 }
728733
729734 // If this error is due to `!: Trait` not implemented but `(): Trait` is
@@ -1081,9 +1086,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10811086
10821087 let substs = self . tcx . mk_substs_trait ( trait_type, & [ ] ) ;
10831088 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+ ) ;
10871094
10881095 if self . predicate_may_hold ( & new_obligation) {
10891096 let sp = self . tcx . sess . source_map ( )
@@ -1105,6 +1112,77 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11051112 }
11061113 }
11071114
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+
11081186 fn suggest_semicolon_removal (
11091187 & self ,
11101188 obligation : & PredicateObligation < ' tcx > ,
0 commit comments