@@ -33,7 +33,7 @@ use crate::ty::subst::Subst;
33
33
use crate :: ty:: SubtypePredicate ;
34
34
use crate :: util:: nodemap:: { FxHashMap , FxHashSet } ;
35
35
36
- use errors:: { Applicability , DiagnosticBuilder , pluralize } ;
36
+ use errors:: { Applicability , DiagnosticBuilder , pluralise , Style } ;
37
37
use std:: fmt;
38
38
use syntax:: ast;
39
39
use syntax:: symbol:: { sym, kw} ;
@@ -721,7 +721,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
721
721
post_message,
722
722
pre_message,
723
723
) = 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) ) )
725
725
. unwrap_or_default ( ) ;
726
726
727
727
let OnUnimplementedNote {
@@ -785,6 +785,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
785
785
self . suggest_borrow_on_unsized_slice ( & obligation. cause . code , & mut err) ;
786
786
self . suggest_fn_call ( & obligation, & mut err, & trait_ref, points_at_arg) ;
787
787
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
+ }
788
798
self . suggest_semicolon_removal ( & obligation, & mut err, span, & trait_ref) ;
789
799
790
800
// Try to report a help message
@@ -1300,6 +1310,66 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1300
1310
}
1301
1311
}
1302
1312
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
+
1303
1373
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
1304
1374
/// suggest removing these references until we reach a type that implements the trait.
1305
1375
fn suggest_remove_reference (
0 commit comments