@@ -686,17 +686,42 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
686
686
return false ;
687
687
}
688
688
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
+
689
704
let span = obligation. cause . span ;
690
705
let param_env = obligation. param_env ;
691
706
let trait_ref = trait_ref. skip_binder ( ) ;
692
707
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
+
700
725
let new_obligation = Obligation :: new (
701
726
ObligationCause :: dummy ( ) ,
702
727
param_env,
@@ -713,8 +738,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
713
738
714
739
let msg = format ! (
715
740
"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( ) ,
718
743
) ;
719
744
if has_custom_message {
720
745
err. note ( & msg) ;
@@ -730,7 +755,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
730
755
span,
731
756
& format ! (
732
757
"expected an implementor of trait `{}`" ,
733
- obligation . parent_trait_ref . skip_binder ( ) . print_only_trait_path( ) ,
758
+ expected_trait_ref . print_only_trait_path( ) ,
734
759
) ,
735
760
) ;
736
761
@@ -745,16 +770,52 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
745
770
746
771
err. span_suggestion (
747
772
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) ,
750
778
Applicability :: MaybeIncorrect ,
751
779
) ;
752
780
}
753
781
return true ;
754
782
}
755
783
}
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
756
818
}
757
- false
758
819
}
759
820
760
821
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
0 commit comments