@@ -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 , pluralize, Style } ;
3737use std:: fmt;
3838use syntax:: ast;
3939use syntax:: symbol:: { sym, kw} ;
@@ -713,20 +713,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
713713 }
714714 match obligation. predicate {
715715 ty:: Predicate :: Trait ( ref trait_predicate) => {
716- let trait_predicate =
717- self . resolve_vars_if_possible ( trait_predicate) ;
716+ let trait_predicate = self . resolve_vars_if_possible ( trait_predicate) ;
718717
719718 if self . tcx . sess . has_errors ( ) && trait_predicate. references_error ( ) {
720719 return ;
721720 }
722721 let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
723- let ( post_message, pre_message) =
724- self . get_parent_trait_ref ( & obligation. cause . code )
725- . map ( |t| ( format ! ( " in `{}`" , t) , format ! ( "within `{}`, " , t) ) )
722+ let (
723+ post_message,
724+ pre_message,
725+ ) = self . get_parent_trait_ref ( & obligation. cause . code )
726+ . map ( |t| ( format ! ( " in `{}`" , t) , format ! ( "within `{}`, " , t) ) )
726727 . unwrap_or_default ( ) ;
727728
728- let OnUnimplementedNote { message, label, note }
729- = self . on_unimplemented_note ( trait_ref, obligation) ;
729+ let OnUnimplementedNote {
730+ message,
731+ label,
732+ note,
733+ } = self . on_unimplemented_note ( trait_ref, obligation) ;
730734 let have_alt_message = message. is_some ( ) || label. is_some ( ) ;
731735 let is_try = self . tcx . sess . source_map ( ) . span_to_snippet ( span)
732736 . map ( |s| & s == "?" )
@@ -767,6 +771,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
767771 )
768772 } ;
769773
774+ if self . suggest_add_reference_to_arg (
775+ & obligation,
776+ & mut err,
777+ & trait_ref,
778+ points_at_arg,
779+ have_alt_message,
780+ ) {
781+ self . note_obligation_cause ( & mut err, obligation) ;
782+ err. emit ( ) ;
783+ return ;
784+ }
770785 if let Some ( ref s) = label {
771786 // If it has a custom `#[rustc_on_unimplemented]`
772787 // error message, let's display it as the label!
@@ -1298,6 +1313,73 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12981313 }
12991314 }
13001315
1316+ fn suggest_add_reference_to_arg (
1317+ & self ,
1318+ obligation : & PredicateObligation < ' tcx > ,
1319+ err : & mut DiagnosticBuilder < ' tcx > ,
1320+ trait_ref : & ty:: Binder < ty:: TraitRef < ' tcx > > ,
1321+ points_at_arg : bool ,
1322+ has_custom_message : bool ,
1323+ ) -> bool {
1324+ if !points_at_arg {
1325+ return false ;
1326+ }
1327+
1328+ let span = obligation. cause . span ;
1329+ let param_env = obligation. param_env ;
1330+ let trait_ref = trait_ref. skip_binder ( ) ;
1331+
1332+ if let ObligationCauseCode :: ImplDerivedObligation ( obligation) = & obligation. cause . code {
1333+ // Try to apply the original trait binding obligation by borrowing.
1334+ let self_ty = trait_ref. self_ty ( ) ;
1335+ let found = self_ty. to_string ( ) ;
1336+ let new_self_ty = self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_static , self_ty) ;
1337+ let substs = self . tcx . mk_substs_trait ( new_self_ty, & [ ] ) ;
1338+ let new_trait_ref = ty:: TraitRef :: new ( obligation. parent_trait_ref . def_id ( ) , substs) ;
1339+ let new_obligation = Obligation :: new (
1340+ ObligationCause :: dummy ( ) ,
1341+ param_env,
1342+ new_trait_ref. to_predicate ( ) ,
1343+ ) ;
1344+ if self . predicate_must_hold_modulo_regions ( & new_obligation) {
1345+ if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
1346+ // We have a very specific type of error, where just borrowing this argument
1347+ // might solve the problem. In cases like this, the important part is the
1348+ // original type obligation, not the last one that failed, which is arbitrary.
1349+ // Because of this, we modify the error to refer to the original obligation and
1350+ // return early in the caller.
1351+ let msg = format ! (
1352+ "the trait bound `{}: {}` is not satisfied" ,
1353+ found,
1354+ obligation. parent_trait_ref. skip_binder( ) ,
1355+ ) ;
1356+ if has_custom_message {
1357+ err. note ( & msg) ;
1358+ } else {
1359+ err. message = vec ! [ ( msg, Style :: NoStyle ) ] ;
1360+ }
1361+ if snippet. starts_with ( '&' ) {
1362+ // This is already a literal borrow and the obligation is failing
1363+ // somewhere else in the obligation chain. Do not suggest non-sense.
1364+ return false ;
1365+ }
1366+ err. span_label ( span, & format ! (
1367+ "expected an implementor of trait `{}`" ,
1368+ obligation. parent_trait_ref. skip_binder( ) ,
1369+ ) ) ;
1370+ err. span_suggestion (
1371+ span,
1372+ "consider borrowing here" ,
1373+ format ! ( "&{}" , snippet) ,
1374+ Applicability :: MaybeIncorrect ,
1375+ ) ;
1376+ return true ;
1377+ }
1378+ }
1379+ }
1380+ false
1381+ }
1382+
13011383 /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
13021384 /// suggest removing these references until we reach a type that implements the trait.
13031385 fn suggest_remove_reference (
0 commit comments