@@ -3,6 +3,7 @@ use super::{
3
3
SelectionContext ,
4
4
} ;
5
5
6
+ use crate :: autoderef:: Autoderef ;
6
7
use crate :: infer:: InferCtxt ;
7
8
use crate :: traits:: normalize_projection_type;
8
9
@@ -13,11 +14,11 @@ use rustc_hir::def_id::DefId;
13
14
use rustc_hir:: intravisit:: Visitor ;
14
15
use rustc_hir:: lang_items;
15
16
use rustc_hir:: { AsyncGeneratorKind , GeneratorKind , Node } ;
16
- use rustc_middle:: ty:: TypeckTables ;
17
17
use rustc_middle:: ty:: {
18
18
self , suggest_constraining_type_param, AdtKind , DefIdTree , Infer , InferTy , ToPredicate , Ty ,
19
19
TyCtxt , TypeFoldable , WithConstness ,
20
20
} ;
21
+ use rustc_middle:: ty:: { TypeAndMut , TypeckTables } ;
21
22
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
22
23
use rustc_span:: { MultiSpan , Span , DUMMY_SP } ;
23
24
use std:: fmt;
@@ -48,6 +49,14 @@ pub trait InferCtxtExt<'tcx> {
48
49
err : & mut DiagnosticBuilder < ' _ > ,
49
50
) ;
50
51
52
+ fn suggest_dereferences (
53
+ & self ,
54
+ obligation : & PredicateObligation < ' tcx > ,
55
+ err : & mut DiagnosticBuilder < ' tcx > ,
56
+ trait_ref : & ty:: PolyTraitRef < ' tcx > ,
57
+ points_at_arg : bool ,
58
+ ) ;
59
+
51
60
fn get_closure_name (
52
61
& self ,
53
62
def_id : DefId ,
@@ -450,6 +459,62 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
450
459
}
451
460
}
452
461
462
+ /// When after several dereferencing, the reference satisfies the trait
463
+ /// binding. This function provides dereference suggestion for this
464
+ /// specific situation.
465
+ fn suggest_dereferences (
466
+ & self ,
467
+ obligation : & PredicateObligation < ' tcx > ,
468
+ err : & mut DiagnosticBuilder < ' tcx > ,
469
+ trait_ref : & ty:: PolyTraitRef < ' tcx > ,
470
+ points_at_arg : bool ,
471
+ ) {
472
+ // It only make sense when suggesting dereferences for arguments
473
+ if !points_at_arg {
474
+ return ;
475
+ }
476
+ let param_env = obligation. param_env ;
477
+ let body_id = obligation. cause . body_id ;
478
+ let span = obligation. cause . span ;
479
+ let real_trait_ref = match & obligation. cause . code {
480
+ ObligationCauseCode :: ImplDerivedObligation ( cause)
481
+ | ObligationCauseCode :: DerivedObligation ( cause)
482
+ | ObligationCauseCode :: BuiltinDerivedObligation ( cause) => & cause. parent_trait_ref ,
483
+ _ => trait_ref,
484
+ } ;
485
+ let real_ty = match real_trait_ref. self_ty ( ) . no_bound_vars ( ) {
486
+ Some ( ty) => ty,
487
+ None => return ,
488
+ } ;
489
+
490
+ if let ty:: Ref ( region, base_ty, mutbl) = real_ty. kind {
491
+ let mut autoderef = Autoderef :: new ( self , param_env, body_id, span, base_ty) ;
492
+ if let Some ( steps) = autoderef. find_map ( |( ty, steps) | {
493
+ // Re-add the `&`
494
+ let ty = self . tcx . mk_ref ( region, TypeAndMut { ty, mutbl } ) ;
495
+ let obligation =
496
+ self . mk_trait_obligation_with_new_self_ty ( param_env, real_trait_ref, ty) ;
497
+ Some ( steps) . filter ( |_| self . predicate_may_hold ( & obligation) )
498
+ } ) {
499
+ if steps > 0 {
500
+ if let Ok ( src) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
501
+ // Don't care about `&mut` because `DerefMut` is used less
502
+ // often and user will not expect autoderef happens.
503
+ if src. starts_with ( "&" ) {
504
+ let derefs = "*" . repeat ( steps) ;
505
+ err. span_suggestion (
506
+ span,
507
+ "consider adding dereference here" ,
508
+ format ! ( "&{}{}" , derefs, & src[ 1 ..] ) ,
509
+ Applicability :: MachineApplicable ,
510
+ ) ;
511
+ }
512
+ }
513
+ }
514
+ }
515
+ }
516
+ }
517
+
453
518
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
454
519
/// suggestion to borrow the initializer in order to use have a slice instead.
455
520
fn suggest_borrow_on_unsized_slice (
0 commit comments