@@ -33,7 +33,7 @@ use crate::ty::subst::Subst;
3333use crate :: ty:: SubtypePredicate ;
3434use crate :: util:: nodemap:: { FxHashMap , FxHashSet } ;
3535
36- use errors:: { Applicability , DiagnosticBuilder , pluralize } ;
36+ use errors:: { Applicability , DiagnosticBuilder , pluralise , Style } ;
3737use std:: fmt;
3838use syntax:: ast;
3939use syntax:: symbol:: { sym, kw} ;
@@ -721,7 +721,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
721721 post_message,
722722 pre_message,
723723 ) = self . get_parent_trait_ref ( & obligation. cause . code )
724- . map ( |t| ( format ! ( " in `{}`" , t) , format ! ( "within `{}`, " , t) ) )
724+ . map ( |t| ( format ! ( " in `{}`" , t) , format ! ( "within `{}`, " , t) ) )
725725 . unwrap_or_default ( ) ;
726726
727727 let OnUnimplementedNote {
@@ -785,6 +785,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
785785 self . suggest_borrow_on_unsized_slice ( & obligation. cause . code , & mut err) ;
786786 self . suggest_fn_call ( & obligation, & mut err, & trait_ref, points_at_arg) ;
787787 self . suggest_remove_reference ( & obligation, & mut err, & trait_ref) ;
788+ if self . suggest_add_reference_to_arg (
789+ & obligation,
790+ & mut err,
791+ & trait_ref,
792+ points_at_arg,
793+ ) {
794+ self . note_obligation_cause ( & mut err, obligation) ;
795+ err. emit ( ) ;
796+ return ;
797+ }
788798 self . suggest_semicolon_removal ( & obligation, & mut err, span, & trait_ref) ;
789799
790800 // Try to report a help message
@@ -1300,6 +1310,66 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13001310 }
13011311 }
13021312
1313+ fn suggest_add_reference_to_arg (
1314+ & self ,
1315+ obligation : & PredicateObligation < ' tcx > ,
1316+ err : & mut DiagnosticBuilder < ' tcx > ,
1317+ trait_ref : & ty:: Binder < ty:: TraitRef < ' tcx > > ,
1318+ points_at_arg : bool ,
1319+ ) -> bool {
1320+ if !points_at_arg {
1321+ return false ;
1322+ }
1323+
1324+ let span = obligation. cause . span ;
1325+ let param_env = obligation. param_env ;
1326+ let trait_ref = trait_ref. skip_binder ( ) ;
1327+
1328+ if let ObligationCauseCode :: ImplDerivedObligation ( obligation) = & obligation. cause . code {
1329+ // Try to apply the original trait binding obligation by borrowing.
1330+ let self_ty = trait_ref. self_ty ( ) ;
1331+ let found = self_ty. to_string ( ) ;
1332+ let new_self_ty = self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_static , self_ty) ;
1333+ let substs = self . tcx . mk_substs_trait ( new_self_ty, & [ ] ) ;
1334+ let new_trait_ref = ty:: TraitRef :: new ( obligation. parent_trait_ref . def_id ( ) , substs) ;
1335+ let new_obligation = Obligation :: new (
1336+ ObligationCause :: dummy ( ) ,
1337+ param_env,
1338+ new_trait_ref. to_predicate ( ) ,
1339+ ) ;
1340+ if self . predicate_may_hold ( & new_obligation) {
1341+ if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
1342+ // We have a very specific type of error, where just borrowing this argument
1343+ // might solve the problem. In cases like this, the important part is the
1344+ // original type obligation, not the last one that failed, which is arbitrary.
1345+ // Because of this, we modify the error to refer to the original obligation and
1346+ // return early in the caller.
1347+ err. message = vec ! [ (
1348+ format!(
1349+ "the trait bound `{}: {}` is not satisfied" ,
1350+ found,
1351+ obligation. parent_trait_ref. skip_binder( ) ,
1352+ ) ,
1353+ Style :: NoStyle ,
1354+ ) ] ;
1355+ if snippet. starts_with ( '&' ) {
1356+ // This is already a literal borrow and the obligation is failing
1357+ // somewhere else in the obligation chain. Do not suggest non-sense.
1358+ return false ;
1359+ }
1360+ err. span_suggestion (
1361+ span,
1362+ "consider borrowing here" ,
1363+ format ! ( "&{}" , snippet) ,
1364+ Applicability :: MachineApplicable ,
1365+ ) ;
1366+ return true ;
1367+ }
1368+ }
1369+ }
1370+ false
1371+ }
1372+
13031373 /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
13041374 /// suggest removing these references until we reach a type that implements the trait.
13051375 fn suggest_remove_reference (
0 commit comments