@@ -6,9 +6,9 @@ use crate::ty::expr_sig;
6
6
use crate :: { get_parent_expr_for_hir, higher} ;
7
7
use rustc_ast:: ast;
8
8
use rustc_ast:: util:: parser:: AssocOp ;
9
+ use rustc_data_structures:: fx:: FxHashSet ;
9
10
use rustc_errors:: Applicability ;
10
- use rustc_hir as hir;
11
- use rustc_hir:: { Closure , ExprKind , HirId , MutTy , TyKind } ;
11
+ use rustc_hir:: { self as hir, Closure , ExprKind , HirId , MutTy , Node , TyKind } ;
12
12
use rustc_hir_typeck:: expr_use_visitor:: { Delegate , ExprUseVisitor , PlaceBase , PlaceWithHirId } ;
13
13
use rustc_lint:: { EarlyContext , LateContext , LintContext } ;
14
14
use rustc_middle:: hir:: place:: ProjectionKind ;
@@ -743,8 +743,10 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti
743
743
let mut visitor = DerefDelegate {
744
744
cx,
745
745
closure_span : closure. span ,
746
+ closure_arg_id : closure_body. params [ 0 ] . pat . hir_id ,
746
747
closure_arg_is_type_annotated_double_ref,
747
748
next_pos : closure. span . lo ( ) ,
749
+ checked_borrows : FxHashSet :: default ( ) ,
748
750
suggestion_start : String :: new ( ) ,
749
751
applicability : Applicability :: MachineApplicable ,
750
752
} ;
@@ -770,10 +772,15 @@ struct DerefDelegate<'a, 'tcx> {
770
772
cx : & ' a LateContext < ' tcx > ,
771
773
/// The span of the input closure to adapt
772
774
closure_span : Span ,
775
+ /// The `hir_id` of the closure argument being checked
776
+ closure_arg_id : HirId ,
773
777
/// Indicates if the arg of the closure is a type annotated double reference
774
778
closure_arg_is_type_annotated_double_ref : bool ,
775
779
/// last position of the span to gradually build the suggestion
776
780
next_pos : BytePos ,
781
+ /// `hir_id` that has been checked. This is used to avoid checking the same hir_id multiple
782
+ /// times when inside macro expansions.
783
+ checked_borrows : FxHashSet < HirId > ,
777
784
/// starting part of the gradually built suggestion
778
785
suggestion_start : String ,
779
786
/// confidence on the built suggestion
@@ -840,6 +847,11 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
840
847
fn borrow ( & mut self , cmt : & PlaceWithHirId < ' tcx > , _: HirId , _: ty:: BorrowKind ) {
841
848
if let PlaceBase :: Local ( id) = cmt. place . base {
842
849
let span = self . cx . tcx . hir_span ( cmt. hir_id ) ;
850
+ if !self . checked_borrows . insert ( cmt. hir_id ) {
851
+ // already checked this span and hir_id, skip
852
+ return ;
853
+ }
854
+
843
855
let start_span = Span :: new ( self . next_pos , span. lo ( ) , span. ctxt ( ) , None ) ;
844
856
let mut start_snip = snippet_with_applicability ( self . cx , start_span, ".." , & mut self . applicability ) ;
845
857
@@ -848,7 +860,11 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
848
860
// full identifier that includes projection (i.e.: `fp.field`)
849
861
let ident_str_with_proj = snippet ( self . cx , span, ".." ) . to_string ( ) ;
850
862
851
- if cmt. place . projections . is_empty ( ) {
863
+ if let Node :: Pat ( pat) = self . cx . tcx . hir_node ( id)
864
+ && pat. hir_id != self . closure_arg_id
865
+ {
866
+ let _ = write ! ( self . suggestion_start, "{start_snip}{ident_str_with_proj}" ) ;
867
+ } else if cmt. place . projections . is_empty ( ) {
852
868
// handle item without any projection, that needs an explicit borrowing
853
869
// i.e.: suggest `&x` instead of `x`
854
870
let _: fmt:: Result = write ! ( self . suggestion_start, "{start_snip}&{ident_str}" ) ;
0 commit comments