@@ -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 , pluralize, Style } ;
37
37
use std:: fmt;
38
38
use syntax:: ast;
39
39
use syntax:: symbol:: { sym, kw} ;
@@ -713,20 +713,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
713
713
}
714
714
match obligation. predicate {
715
715
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) ;
718
717
719
718
if self . tcx . sess . has_errors ( ) && trait_predicate. references_error ( ) {
720
719
return ;
721
720
}
722
721
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) ) )
726
727
. unwrap_or_default ( ) ;
727
728
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) ;
730
734
let have_alt_message = message. is_some ( ) || label. is_some ( ) ;
731
735
let is_try = self . tcx . sess . source_map ( ) . span_to_snippet ( span)
732
736
. map ( |s| & s == "?" )
@@ -767,6 +771,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
767
771
)
768
772
} ;
769
773
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
+ }
770
785
if let Some ( ref s) = label {
771
786
// If it has a custom `#[rustc_on_unimplemented]`
772
787
// error message, let's display it as the label!
@@ -1298,6 +1313,73 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1298
1313
}
1299
1314
}
1300
1315
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
+
1301
1383
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
1302
1384
/// suggest removing these references until we reach a type that implements the trait.
1303
1385
fn suggest_remove_reference (
0 commit comments