@@ -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} ;
@@ -723,7 +723,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
723723 post_message,
724724 pre_message,
725725 ) = self . get_parent_trait_ref ( & obligation. cause . code )
726- . map ( |t| ( format ! ( " in `{}`" , t) , format ! ( "within `{}`, " , t) ) )
726+ . map ( |t| ( format ! ( " in `{}`" , t) , format ! ( "within `{}`, " , t) ) )
727727 . unwrap_or_default ( ) ;
728728
729729 let OnUnimplementedNote {
@@ -787,6 +787,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
787787 self . suggest_borrow_on_unsized_slice ( & obligation. cause . code , & mut err) ;
788788 self . suggest_fn_call ( & obligation, & mut err, & trait_ref, points_at_arg) ;
789789 self . suggest_remove_reference ( & obligation, & mut err, & trait_ref) ;
790+ if self . suggest_add_reference_to_arg (
791+ & obligation,
792+ & mut err,
793+ & trait_ref,
794+ points_at_arg,
795+ ) {
796+ self . note_obligation_cause ( & mut err, obligation) ;
797+ err. emit ( ) ;
798+ return ;
799+ }
790800 self . suggest_semicolon_removal ( & obligation, & mut err, span, & trait_ref) ;
791801
792802 // Try to report a help message
@@ -1302,6 +1312,66 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13021312 }
13031313 }
13041314
1315+ fn suggest_add_reference_to_arg (
1316+ & self ,
1317+ obligation : & PredicateObligation < ' tcx > ,
1318+ err : & mut DiagnosticBuilder < ' tcx > ,
1319+ trait_ref : & ty:: Binder < ty:: TraitRef < ' tcx > > ,
1320+ points_at_arg : bool ,
1321+ ) -> bool {
1322+ if !points_at_arg {
1323+ return false ;
1324+ }
1325+
1326+ let span = obligation. cause . span ;
1327+ let param_env = obligation. param_env ;
1328+ let trait_ref = trait_ref. skip_binder ( ) ;
1329+
1330+ if let ObligationCauseCode :: ImplDerivedObligation ( obligation) = & obligation. cause . code {
1331+ // Try to apply the original trait binding obligation by borrowing.
1332+ let self_ty = trait_ref. self_ty ( ) ;
1333+ let found = self_ty. to_string ( ) ;
1334+ let new_self_ty = self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_static , self_ty) ;
1335+ let substs = self . tcx . mk_substs_trait ( new_self_ty, & [ ] ) ;
1336+ let new_trait_ref = ty:: TraitRef :: new ( obligation. parent_trait_ref . def_id ( ) , substs) ;
1337+ let new_obligation = Obligation :: new (
1338+ ObligationCause :: dummy ( ) ,
1339+ param_env,
1340+ new_trait_ref. to_predicate ( ) ,
1341+ ) ;
1342+ if self . predicate_may_hold ( & new_obligation) {
1343+ if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
1344+ // We have a very specific type of error, where just borrowing this argument
1345+ // might solve the problem. In cases like this, the important part is the
1346+ // original type obligation, not the last one that failed, which is arbitrary.
1347+ // Because of this, we modify the error to refer to the original obligation and
1348+ // return early in the caller.
1349+ err. message = vec ! [ (
1350+ format!(
1351+ "the trait bound `{}: {}` is not satisfied" ,
1352+ found,
1353+ obligation. parent_trait_ref. skip_binder( ) ,
1354+ ) ,
1355+ Style :: NoStyle ,
1356+ ) ] ;
1357+ if snippet. starts_with ( '&' ) {
1358+ // This is already a literal borrow and the obligation is failing
1359+ // somewhere else in the obligation chain. Do not suggest non-sense.
1360+ return false ;
1361+ }
1362+ err. span_suggestion (
1363+ span,
1364+ "consider borrowing here" ,
1365+ format ! ( "&{}" , snippet) ,
1366+ Applicability :: MachineApplicable ,
1367+ ) ;
1368+ return true ;
1369+ }
1370+ }
1371+ }
1372+ false
1373+ }
1374+
13051375 /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
13061376 /// suggest removing these references until we reach a type that implements the trait.
13071377 fn suggest_remove_reference (
0 commit comments