@@ -882,6 +882,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
882882 obligation. cause . code ( )
883883 {
884884 & parent_code
885+ } else if let ObligationCauseCode :: ItemObligation ( _) = obligation. cause . code ( ) {
886+ obligation. cause . code ( )
885887 } else if let ExpnKind :: Desugaring ( DesugaringKind :: ForLoop ) =
886888 span. ctxt ( ) . outer_expn_data ( ) . kind
887889 {
@@ -906,102 +908,116 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
906908 let param_env = obligation. param_env ;
907909
908910 // Try to apply the original trait binding obligation by borrowing.
909- let mut try_borrowing =
910- |old_pred : ty:: PolyTraitPredicate < ' tcx > , blacklist : & [ DefId ] | -> bool {
911- if blacklist. contains ( & old_pred. def_id ( ) ) {
912- return false ;
913- }
914- // We map bounds to `&T` and `&mut T`
915- let trait_pred_and_imm_ref = old_pred. map_bound ( |trait_pred| {
916- (
917- trait_pred,
918- self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_static , trait_pred. self_ty ( ) ) ,
919- )
920- } ) ;
921- let trait_pred_and_mut_ref = old_pred. map_bound ( |trait_pred| {
922- (
923- trait_pred,
924- self . tcx . mk_mut_ref ( self . tcx . lifetimes . re_static , trait_pred. self_ty ( ) ) ,
925- )
926- } ) ;
911+ let mut try_borrowing = |old_pred : ty:: PolyTraitPredicate < ' tcx > ,
912+ blacklist : & [ DefId ] |
913+ -> bool {
914+ if blacklist. contains ( & old_pred. def_id ( ) ) {
915+ return false ;
916+ }
917+ // We map bounds to `&T` and `&mut T`
918+ let trait_pred_and_imm_ref = old_pred. map_bound ( |trait_pred| {
919+ (
920+ trait_pred,
921+ self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_static , trait_pred. self_ty ( ) ) ,
922+ )
923+ } ) ;
924+ let trait_pred_and_mut_ref = old_pred. map_bound ( |trait_pred| {
925+ (
926+ trait_pred,
927+ self . tcx . mk_mut_ref ( self . tcx . lifetimes . re_static , trait_pred. self_ty ( ) ) ,
928+ )
929+ } ) ;
927930
928- let mk_result = |trait_pred_and_new_ty| {
929- let obligation =
930- self . mk_trait_obligation_with_new_self_ty ( param_env, trait_pred_and_new_ty) ;
931- self . predicate_must_hold_modulo_regions ( & obligation)
931+ let mk_result = |trait_pred_and_new_ty| {
932+ let obligation =
933+ self . mk_trait_obligation_with_new_self_ty ( param_env, trait_pred_and_new_ty) ;
934+ self . predicate_must_hold_modulo_regions ( & obligation)
935+ } ;
936+ let imm_result = mk_result ( trait_pred_and_imm_ref) ;
937+ let mut_result = mk_result ( trait_pred_and_mut_ref) ;
938+
939+ let ref_inner_ty_result =
940+ if let ObligationCauseCode :: ItemObligation ( _) = obligation. cause . code ( )
941+ && let ty:: Ref ( _, ty, mutability) = old_pred. self_ty ( ) . skip_binder ( ) . kind ( )
942+ {
943+ Some ( ( mk_result ( old_pred. map_bound ( |trait_pred| ( trait_pred, * ty) ) ) , mutability) )
944+ } else {
945+ None
932946 } ;
933- let imm_result = mk_result ( trait_pred_and_imm_ref) ;
934- let mut_result = mk_result ( trait_pred_and_mut_ref) ;
935-
936- if imm_result || mut_result {
937- if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
938- // We have a very specific type of error, where just borrowing this argument
939- // might solve the problem. In cases like this, the important part is the
940- // original type obligation, not the last one that failed, which is arbitrary.
941- // Because of this, we modify the error to refer to the original obligation and
942- // return early in the caller.
943-
944- let msg = format ! ( "the trait bound `{}` is not satisfied" , old_pred) ;
945- if has_custom_message {
946- err. note ( & msg) ;
947- } else {
948- err. message =
949- vec ! [ ( rustc_errors:: DiagnosticMessage :: Str ( msg) , Style :: NoStyle ) ] ;
950- }
951- if snippet. starts_with ( '&' ) {
952- // This is already a literal borrow and the obligation is failing
953- // somewhere else in the obligation chain. Do not suggest non-sense.
954- return false ;
955- }
956- err. span_label (
957- span,
958- & format ! (
959- "expected an implementor of trait `{}`" ,
960- old_pred. print_modifiers_and_trait_path( ) ,
961- ) ,
962- ) ;
963947
964- // This if is to prevent a special edge-case
965- if matches ! (
966- span. ctxt( ) . outer_expn_data( ) . kind,
967- ExpnKind :: Root | ExpnKind :: Desugaring ( DesugaringKind :: ForLoop )
968- ) {
969- // We don't want a borrowing suggestion on the fields in structs,
970- // ```
971- // struct Foo {
972- // the_foos: Vec<Foo>
973- // }
974- // ```
948+ if imm_result || mut_result || ref_inner_ty_result. map_or ( false , |( result, _) | result) {
949+ if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
950+ // We have a very specific type of error, where just borrowing this argument
951+ // might solve the problem. In cases like this, the important part is the
952+ // original type obligation, not the last one that failed, which is arbitrary.
953+ // Because of this, we modify the error to refer to the original obligation and
954+ // return early in the caller.
955+
956+ let msg = format ! ( "the trait bound `{}` is not satisfied" , old_pred) ;
957+ if has_custom_message {
958+ err. note ( & msg) ;
959+ } else {
960+ err. message =
961+ vec ! [ ( rustc_errors:: DiagnosticMessage :: Str ( msg) , Style :: NoStyle ) ] ;
962+ }
963+ if snippet. starts_with ( '&' ) {
964+ // This is already a literal borrow and the obligation is failing
965+ // somewhere else in the obligation chain. Do not suggest non-sense.
966+ return false ;
967+ }
968+ err. span_label (
969+ span,
970+ & format ! (
971+ "expected an implementor of trait `{}`" ,
972+ old_pred. print_modifiers_and_trait_path( ) ,
973+ ) ,
974+ ) ;
975975
976- if imm_result && mut_result {
977- err. span_suggestions (
978- span. shrink_to_lo ( ) ,
979- "consider borrowing here" ,
980- [ "&" . to_string ( ) , "&mut " . to_string ( ) ] . into_iter ( ) ,
981- Applicability :: MaybeIncorrect ,
982- ) ;
983- } else {
984- err. span_suggestion_verbose (
985- span. shrink_to_lo ( ) ,
986- & format ! (
987- "consider{} borrowing here" ,
988- if mut_result { " mutably" } else { "" }
989- ) ,
990- format ! ( "&{}" , if mut_result { "mut " } else { "" } ) ,
991- Applicability :: MaybeIncorrect ,
992- ) ;
993- }
976+ // This if is to prevent a special edge-case
977+ if matches ! (
978+ span. ctxt( ) . outer_expn_data( ) . kind,
979+ ExpnKind :: Root | ExpnKind :: Desugaring ( DesugaringKind :: ForLoop )
980+ ) {
981+ // We don't want a borrowing suggestion on the fields in structs,
982+ // ```
983+ // struct Foo {
984+ // the_foos: Vec<Foo>
985+ // }
986+ // ```
987+
988+ if imm_result && mut_result {
989+ err. span_suggestions (
990+ span. shrink_to_lo ( ) ,
991+ "consider borrowing here" ,
992+ [ "&" . to_string ( ) , "&mut " . to_string ( ) ] . into_iter ( ) ,
993+ Applicability :: MaybeIncorrect ,
994+ ) ;
995+ } else {
996+ let is_mut = mut_result
997+ || ref_inner_ty_result. map_or ( false , |( _, mutabl) | {
998+ matches ! ( mutabl, hir:: Mutability :: Mut )
999+ } ) ;
1000+ err. span_suggestion_verbose (
1001+ span. shrink_to_lo ( ) ,
1002+ & format ! (
1003+ "consider{} borrowing here" ,
1004+ if is_mut { " mutably" } else { "" }
1005+ ) ,
1006+ format ! ( "&{}" , if is_mut { "mut " } else { "" } ) ,
1007+ Applicability :: MaybeIncorrect ,
1008+ ) ;
9941009 }
995- return true ;
9961010 }
1011+ return true ;
9971012 }
998- return false ;
999- } ;
1013+ }
1014+ return false ;
1015+ } ;
10001016
10011017 if let ObligationCauseCode :: ImplDerivedObligation ( cause) = & * code {
10021018 try_borrowing ( cause. derived . parent_trait_pred , & [ ] )
10031019 } else if let ObligationCauseCode :: BindingObligation ( _, _)
1004- | ObligationCauseCode :: ItemObligation ( _ ) = code
1020+ | ObligationCauseCode :: ItemObligation ( .. ) = code
10051021 {
10061022 try_borrowing ( poly_trait_pred, & never_suggest_borrow)
10071023 } else {
0 commit comments