@@ -686,17 +686,42 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
686686 return false ;
687687 }
688688
689+ // Blacklist traits for which it would be nonsensical to suggest borrowing.
690+ // For instance, immutable references are always Copy, so suggesting to
691+ // borrow would always succeed, but it's probably not what the user wanted.
692+ let blacklist: Vec < _ > = [
693+ LangItem :: Copy ,
694+ LangItem :: Clone ,
695+ LangItem :: Pin ,
696+ LangItem :: Unpin ,
697+ LangItem :: Sized ,
698+ LangItem :: Send ,
699+ ]
700+ . iter ( )
701+ . filter_map ( |lang_item| self . tcx . lang_items ( ) . require ( * lang_item) . ok ( ) )
702+ . collect ( ) ;
703+
689704 let span = obligation. cause . span ;
690705 let param_env = obligation. param_env ;
691706 let trait_ref = trait_ref. skip_binder ( ) ;
692707
693- if let ObligationCauseCode :: ImplDerivedObligation ( obligation) = & obligation. cause . code {
694- // Try to apply the original trait binding obligation by borrowing.
695- let self_ty = trait_ref. self_ty ( ) ;
696- let found = self_ty. to_string ( ) ;
697- let new_self_ty = self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_static , self_ty) ;
698- let substs = self . tcx . mk_substs_trait ( new_self_ty, & [ ] ) ;
699- let new_trait_ref = ty:: TraitRef :: new ( obligation. parent_trait_ref . def_id ( ) , substs) ;
708+ let found_ty = trait_ref. self_ty ( ) ;
709+ let found_ty_str = found_ty. to_string ( ) ;
710+ let imm_borrowed_found_ty = self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_static , found_ty) ;
711+ let imm_substs = self . tcx . mk_substs_trait ( imm_borrowed_found_ty, & [ ] ) ;
712+ let mut_borrowed_found_ty = self . tcx . mk_mut_ref ( self . tcx . lifetimes . re_static , found_ty) ;
713+ let mut_substs = self . tcx . mk_substs_trait ( mut_borrowed_found_ty, & [ ] ) ;
714+
715+ // Try to apply the original trait binding obligation by borrowing.
716+ let mut try_borrowing = |new_trait_ref : ty:: TraitRef < ' tcx > ,
717+ expected_trait_ref : ty:: TraitRef < ' tcx > ,
718+ mtbl : bool ,
719+ blacklist : & [ DefId ] |
720+ -> bool {
721+ if blacklist. contains ( & expected_trait_ref. def_id ) {
722+ return false ;
723+ }
724+
700725 let new_obligation = Obligation :: new (
701726 ObligationCause :: dummy ( ) ,
702727 param_env,
@@ -713,8 +738,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
713738
714739 let msg = format ! (
715740 "the trait bound `{}: {}` is not satisfied" ,
716- found ,
717- obligation . parent_trait_ref . skip_binder ( ) . print_only_trait_path( ) ,
741+ found_ty_str ,
742+ expected_trait_ref . print_only_trait_path( ) ,
718743 ) ;
719744 if has_custom_message {
720745 err. note ( & msg) ;
@@ -730,7 +755,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
730755 span,
731756 & format ! (
732757 "expected an implementor of trait `{}`" ,
733- obligation . parent_trait_ref . skip_binder ( ) . print_only_trait_path( ) ,
758+ expected_trait_ref . print_only_trait_path( ) ,
734759 ) ,
735760 ) ;
736761
@@ -745,16 +770,52 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
745770
746771 err. span_suggestion (
747772 span,
748- "consider borrowing here" ,
749- format ! ( "&{}" , snippet) ,
773+ & format ! (
774+ "consider borrowing{} here" ,
775+ if mtbl { " mutably" } else { "" }
776+ ) ,
777+ format ! ( "&{}{}" , if mtbl { "mut " } else { "" } , snippet) ,
750778 Applicability :: MaybeIncorrect ,
751779 ) ;
752780 }
753781 return true ;
754782 }
755783 }
784+ return false ;
785+ } ;
786+
787+ if let ObligationCauseCode :: ImplDerivedObligation ( obligation) = & obligation. cause . code {
788+ let expected_trait_ref = obligation. parent_trait_ref . skip_binder ( ) ;
789+ let new_imm_trait_ref =
790+ ty:: TraitRef :: new ( obligation. parent_trait_ref . def_id ( ) , imm_substs) ;
791+ let new_mut_trait_ref =
792+ ty:: TraitRef :: new ( obligation. parent_trait_ref . def_id ( ) , mut_substs) ;
793+ if try_borrowing ( new_imm_trait_ref, expected_trait_ref, false , & [ ] ) {
794+ return true ;
795+ } else {
796+ return try_borrowing ( new_mut_trait_ref, expected_trait_ref, true , & [ ] ) ;
797+ }
798+ } else if let ObligationCauseCode :: BindingObligation ( _, _)
799+ | ObligationCauseCode :: ItemObligation ( _) = & obligation. cause . code
800+ {
801+ if try_borrowing (
802+ ty:: TraitRef :: new ( trait_ref. def_id , imm_substs) ,
803+ trait_ref,
804+ false ,
805+ & blacklist[ ..] ,
806+ ) {
807+ return true ;
808+ } else {
809+ return try_borrowing (
810+ ty:: TraitRef :: new ( trait_ref. def_id , mut_substs) ,
811+ trait_ref,
812+ true ,
813+ & blacklist[ ..] ,
814+ ) ;
815+ }
816+ } else {
817+ false
756818 }
757- false
758819 }
759820
760821 /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
0 commit comments