@@ -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} ;
@@ -723,7 +723,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
723
723
post_message,
724
724
pre_message,
725
725
) = 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) ) )
727
727
. unwrap_or_default ( ) ;
728
728
729
729
let OnUnimplementedNote {
@@ -787,6 +787,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
787
787
self . suggest_borrow_on_unsized_slice ( & obligation. cause . code , & mut err) ;
788
788
self . suggest_fn_call ( & obligation, & mut err, & trait_ref, points_at_arg) ;
789
789
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
+ }
790
800
self . suggest_semicolon_removal ( & obligation, & mut err, span, & trait_ref) ;
791
801
792
802
// Try to report a help message
@@ -1302,6 +1312,66 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1302
1312
}
1303
1313
}
1304
1314
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
+
1305
1375
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
1306
1376
/// suggest removing these references until we reach a type that implements the trait.
1307
1377
fn suggest_remove_reference (
0 commit comments