2 use rustc
::hir
::def
::Namespace
;
3 use rustc
::hir
::def_id
::DefId
;
4 use rustc
::hir
::GeneratorKind
;
6 AggregateKind
, Constant
, Field
, Local
, LocalKind
, Location
, Operand
,
7 Place
, PlaceBase
, PlaceRef
, ProjectionElem
, Rvalue
, Statement
, StatementKind
,
8 Static
, StaticKind
, Terminator
, TerminatorKind
,
10 use rustc
::ty
::{self, DefIdTree, Ty, TyCtxt}
;
11 use rustc
::ty
::layout
::VariantIdx
;
12 use rustc
::ty
::print
::Print
;
13 use rustc_errors
::DiagnosticBuilder
;
15 use syntax
::symbol
::sym
;
17 use super::borrow_set
::BorrowData
;
18 use super::MirBorrowckCtxt
;
19 use crate::dataflow
::move_paths
::{InitLocation, LookupResult}
;
21 pub(super) struct IncludingDowncast(pub(super) bool
);
23 impl<'cx
, 'tcx
> MirBorrowckCtxt
<'cx
, 'tcx
> {
24 /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
25 /// is moved after being invoked.
28 /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
30 /// --> $DIR/issue-42065.rs:16:29
32 /// LL | for (key, value) in dict {
35 pub(super) fn add_moved_or_invoked_closure_note(
38 place
: PlaceRef
<'cx
, 'tcx
>,
39 diag
: &mut DiagnosticBuilder
<'_
>,
41 debug
!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location
, place
);
42 let mut target
= place
.local_or_deref_local();
43 for stmt
in &self.body
[location
.block
].statements
[location
.statement_index
..] {
44 debug
!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt
, target
);
45 if let StatementKind
::Assign(box(into
, Rvalue
::Use(from
))) = &stmt
.kind
{
46 debug
!("add_fnonce_closure_note: into={:?} from={:?}", into
, from
);
48 Operand
::Copy(ref place
) |
49 Operand
::Move(ref place
) if target
== place
.local_or_deref_local() =>
50 target
= into
.local_or_deref_local(),
56 // Check if we are attempting to call a closure after it has been invoked.
57 let terminator
= self.body
[location
.block
].terminator();
58 debug
!("add_moved_or_invoked_closure_note: terminator={:?}", terminator
);
59 if let TerminatorKind
::Call
{
60 func
: Operand
::Constant(box Constant
{
62 ty
: &ty
::TyS { kind: ty::FnDef(id, _), .. }
,
69 } = &terminator
.kind
{
70 debug
!("add_moved_or_invoked_closure_note: id={:?}", id
);
71 if self.infcx
.tcx
.parent(id
) == self.infcx
.tcx
.lang_items().fn_once_trait() {
72 let closure
= match args
.first() {
73 Some(Operand
::Copy(ref place
)) |
74 Some(Operand
::Move(ref place
)) if target
== place
.local_or_deref_local() =>
75 place
.local_or_deref_local().unwrap(),
79 debug
!("add_moved_or_invoked_closure_note: closure={:?}", closure
);
80 if let ty
::Closure(did
, _
) = self.body
.local_decls
[closure
].ty
.kind
{
81 let hir_id
= self.infcx
.tcx
.hir().as_local_hir_id(did
).unwrap();
83 if let Some((span
, name
)) = self.infcx
.tcx
.typeck_tables_of(did
)
84 .closure_kind_origins()
90 "closure cannot be invoked more than once because it moves the \
91 variable `{}` out of its environment",
101 // Check if we are just moving a closure after it has been invoked.
102 if let Some(target
) = target
{
103 if let ty
::Closure(did
, _
) = self.body
.local_decls
[target
].ty
.kind
{
104 let hir_id
= self.infcx
.tcx
.hir().as_local_hir_id(did
).unwrap();
106 if let Some((span
, name
)) = self.infcx
.tcx
.typeck_tables_of(did
)
107 .closure_kind_origins()
113 "closure cannot be moved more than once as it is not `Copy` due to \
114 moving the variable `{}` out of its environment",
123 /// End-user visible description of `place` if one can be found. If the
124 /// place is a temporary for instance, None will be returned.
125 pub(super) fn describe_place(&self, place_ref
: PlaceRef
<'cx
, 'tcx
>) -> Option
<String
> {
126 self.describe_place_with_options(place_ref
, IncludingDowncast(false))
129 /// End-user visible description of `place` if one can be found. If the
130 /// place is a temporary for instance, None will be returned.
131 /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
132 /// `Downcast` and `IncludingDowncast` is true
133 pub(super) fn describe_place_with_options(
135 place
: PlaceRef
<'cx
, 'tcx
>,
136 including_downcast
: IncludingDowncast
,
137 ) -> Option
<String
> {
138 let mut buf
= String
::new();
139 match self.append_place_to_string(place
, &mut buf
, false, &including_downcast
) {
145 /// Appends end-user visible description of `place` to `buf`.
146 fn append_place_to_string(
148 place
: PlaceRef
<'cx
, 'tcx
>,
151 including_downcast
: &IncludingDowncast
,
152 ) -> Result
<(), ()> {
155 base
: PlaceBase
::Local(local
),
158 self.append_local_to_string(*local
, buf
)?
;
162 PlaceBase
::Static(box Static
{
163 kind
: StaticKind
::Promoted(..),
168 buf
.push_str("promoted");
172 PlaceBase
::Static(box Static
{
173 kind
: StaticKind
::Static
,
179 buf
.push_str(&self.infcx
.tcx
.item_name(*def_id
).to_string());
183 projection
: [proj_base @
.., elem
],
186 ProjectionElem
::Deref
=> {
187 let upvar_field_projection
=
188 self.is_upvar_field_projection(place
);
189 if let Some(field
) = upvar_field_projection
{
190 let var_index
= field
.index();
191 let name
= self.upvars
[var_index
].name
.to_string();
192 if self.upvars
[var_index
].by_ref
{
195 buf
.push_str(&format
!("*{}", &name
));
199 // FIXME turn this recursion into iteration
200 self.append_place_to_string(
203 projection
: proj_base
,
210 match (proj_base
, base
) {
211 ([], PlaceBase
::Local(local
)) => {
212 if self.body
.local_decls
[*local
].is_ref_for_guard() {
213 self.append_place_to_string(
216 projection
: proj_base
,
223 // FIXME deduplicate this and the _ => body below
225 self.append_place_to_string(
228 projection
: proj_base
,
239 self.append_place_to_string(
242 projection
: proj_base
,
253 ProjectionElem
::Downcast(..) => {
254 self.append_place_to_string(
257 projection
: proj_base
,
263 if including_downcast
.0 {
267 ProjectionElem
::Field(field
, _ty
) => {
270 let upvar_field_projection
=
271 self.is_upvar_field_projection(place
);
272 if let Some(field
) = upvar_field_projection
{
273 let var_index
= field
.index();
274 let name
= self.upvars
[var_index
].name
.to_string();
277 let field_name
= self.describe_field(PlaceRef
{
279 projection
: proj_base
,
281 self.append_place_to_string(
284 projection
: proj_base
,
290 buf
.push_str(&format
!(".{}", field_name
));
293 ProjectionElem
::Index(index
) => {
296 self.append_place_to_string(
299 projection
: proj_base
,
306 if self.append_local_to_string(*index
, buf
).is_err() {
311 ProjectionElem
::ConstantIndex { .. }
| ProjectionElem
::Subslice { .. }
=> {
313 // Since it isn't possible to borrow an element on a particular index and
314 // then use another while the borrow is held, don't output indices details
315 // to avoid confusing the end-user
316 self.append_place_to_string(
319 projection
: proj_base
,
325 buf
.push_str(&"[..]");
334 /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
335 /// a name, or its name was generated by the compiler, then `Err` is returned
336 fn append_local_to_string(&self, local_index
: Local
, buf
: &mut String
) -> Result
<(), ()> {
337 let local
= &self.body
.local_decls
[local_index
];
339 Some(name
) if !local
.from_compiler_desugaring() => {
340 buf
.push_str(&name
.as_str());
347 /// End-user visible description of the `field`nth field of `base`
348 fn describe_field(&self, place
: PlaceRef
<'cx
, 'tcx
>, field
: Field
) -> String
{
349 // FIXME Place2 Make this work iteratively
352 base
: PlaceBase
::Local(local
),
355 let local
= &self.body
.local_decls
[*local
];
356 self.describe_field_from_ty(&local
.ty
, field
, None
)
359 base
: PlaceBase
::Static(static_
),
362 self.describe_field_from_ty(&static_
.ty
, field
, None
),
365 projection
: [proj_base @
.., elem
],
367 ProjectionElem
::Deref
=> {
368 self.describe_field(PlaceRef
{
370 projection
: proj_base
,
373 ProjectionElem
::Downcast(_
, variant_index
) => {
375 Place
::ty_from(place
.base
, place
.projection
, self.body
, self.infcx
.tcx
).ty
;
376 self.describe_field_from_ty(&base_ty
, field
, Some(*variant_index
))
378 ProjectionElem
::Field(_
, field_type
) => {
379 self.describe_field_from_ty(&field_type
, field
, None
)
381 ProjectionElem
::Index(..)
382 | ProjectionElem
::ConstantIndex { .. }
383 | ProjectionElem
::Subslice { .. }
=> {
384 self.describe_field(PlaceRef
{
386 projection
: proj_base
,
393 /// End-user visible description of the `field_index`nth field of `ty`
394 fn describe_field_from_ty(
398 variant_index
: Option
<VariantIdx
>
401 // If the type is a box, the field is described from the boxed type
402 self.describe_field_from_ty(&ty
.boxed_ty(), field
, variant_index
)
406 let variant
= if let Some(idx
) = variant_index
{
407 assert
!(def
.is_enum());
410 def
.non_enum_variant()
412 variant
.fields
[field
.index()]
416 ty
::Tuple(_
) => field
.index().to_string(),
417 ty
::Ref(_
, ty
, _
) | ty
::RawPtr(ty
::TypeAndMut { ty, .. }
) => {
418 self.describe_field_from_ty(&ty
, field
, variant_index
)
420 ty
::Array(ty
, _
) | ty
::Slice(ty
) =>
421 self.describe_field_from_ty(&ty
, field
, variant_index
),
422 ty
::Closure(def_id
, _
) | ty
::Generator(def_id
, _
, _
) => {
423 // `tcx.upvars(def_id)` returns an `Option`, which is `None` in case
424 // the closure comes from another crate. But in that case we wouldn't
425 // be borrowck'ing it, so we can just unwrap:
426 let (&var_id
, _
) = self.infcx
.tcx
.upvars(def_id
).unwrap()
427 .get_index(field
.index()).unwrap();
429 self.infcx
.tcx
.hir().name(var_id
).to_string()
432 // Might need a revision when the fields in trait RFC is implemented
433 // (https://github.com/rust-lang/rfcs/pull/1546)
435 "End-user description not implemented for field access on `{:?}`",
443 /// Checks if a place is a thread-local static.
444 pub fn is_place_thread_local(&self, place_ref
: PlaceRef
<'cx
, 'tcx
>) -> bool
{
446 base
: PlaceBase
::Static(box Static
{
447 kind
: StaticKind
::Static
,
453 let attrs
= self.infcx
.tcx
.get_attrs(*def_id
);
454 let is_thread_local
= attrs
.iter().any(|attr
| attr
.check_name(sym
::thread_local
));
457 "is_place_thread_local: attrs={:?} is_thread_local={:?}",
458 attrs
, is_thread_local
462 debug
!("is_place_thread_local: no");
467 /// Add a note that a type does not implement `Copy`
468 pub(super) fn note_type_does_not_implement_copy(
470 err
: &mut DiagnosticBuilder
<'a
>,
475 let message
= format
!(
476 "move occurs because {} has type `{}`, which does not implement the `Copy` trait",
480 if let Some(span
) = span
{
481 err
.span_label(span
, message
);
487 pub(super) fn borrowed_content_source(
489 deref_base
: PlaceRef
<'cx
, 'tcx
>,
490 ) -> BorrowedContentSource
<'tcx
> {
491 let tcx
= self.infcx
.tcx
;
493 // Look up the provided place and work out the move path index for it,
494 // we'll use this to check whether it was originally from an overloaded
496 match self.move_data
.rev_lookup
.find(deref_base
) {
497 LookupResult
::Exact(mpi
) | LookupResult
::Parent(Some(mpi
)) => {
498 debug
!("borrowed_content_source: mpi={:?}", mpi
);
500 for i
in &self.move_data
.init_path_map
[mpi
] {
501 let init
= &self.move_data
.inits
[*i
];
502 debug
!("borrowed_content_source: init={:?}", init
);
503 // We're only interested in statements that initialized a value, not the
504 // initializations from arguments.
505 let loc
= match init
.location
{
506 InitLocation
::Statement(stmt
) => stmt
,
510 let bbd
= &self.body
[loc
.block
];
511 let is_terminator
= bbd
.statements
.len() == loc
.statement_index
;
513 "borrowed_content_source: loc={:?} is_terminator={:?}",
519 } else if let Some(Terminator
{
520 kind
: TerminatorKind
::Call
{
522 from_hir_call
: false,
526 }) = bbd
.terminator
{
528 = BorrowedContentSource
::from_call(func
.ty(self.body
, tcx
), tcx
)
535 // Base is a `static` so won't be from an overloaded operator
539 // If we didn't find an overloaded deref or index, then assume it's a
540 // built in deref and check the type of the base.
541 let base_ty
= Place
::ty_from(deref_base
.base
, deref_base
.projection
, self.body
, tcx
).ty
;
542 if base_ty
.is_unsafe_ptr() {
543 BorrowedContentSource
::DerefRawPointer
544 } else if base_ty
.is_mutable_ptr() {
545 BorrowedContentSource
::DerefMutableRef
547 BorrowedContentSource
::DerefSharedRef
552 impl<'cx
, 'tcx
> MirBorrowckCtxt
<'cx
, 'tcx
> {
553 /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
554 /// name where required.
555 pub(super) fn get_name_for_ty(&self, ty
: Ty
<'tcx
>, counter
: usize) -> String
{
556 let mut s
= String
::new();
557 let mut printer
= ty
::print
::FmtPrinter
::new(self.infcx
.tcx
, &mut s
, Namespace
::TypeNS
);
559 // We need to add synthesized lifetimes where appropriate. We do
560 // this by hooking into the pretty printer and telling it to label the
561 // lifetimes without names with the value `'0`.
563 ty
::Ref(ty
::RegionKind
::ReLateBound(_
, br
), _
, _
)
565 ty
::RegionKind
::RePlaceholder(ty
::PlaceholderRegion { name: br, .. }
),
568 ) => printer
.region_highlight_mode
.highlighting_bound_region(*br
, counter
),
572 let _
= ty
.print(printer
);
576 /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
577 /// synthesized lifetime name where required.
578 pub(super) fn get_region_name_for_ty(&self, ty
: Ty
<'tcx
>, counter
: usize) -> String
{
579 let mut s
= String
::new();
580 let mut printer
= ty
::print
::FmtPrinter
::new(self.infcx
.tcx
, &mut s
, Namespace
::TypeNS
);
582 let region
= match ty
.kind
{
583 ty
::Ref(region
, _
, _
) => {
585 ty
::RegionKind
::ReLateBound(_
, br
)
586 | ty
::RegionKind
::RePlaceholder(ty
::PlaceholderRegion { name: br, .. }
) => {
587 printer
.region_highlight_mode
.highlighting_bound_region(*br
, counter
)
594 _
=> bug
!("ty for annotation of borrow region is not a reference"),
597 let _
= region
.print(printer
);
602 // The span(s) associated to a use of a place.
603 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
604 pub(super) enum UseSpans
{
605 // The access is caused by capturing a variable for a closure.
607 // This is true if the captured variable was from a generator.
608 generator_kind
: Option
<GeneratorKind
>,
609 // The span of the args of the closure, including the `move` keyword if
612 // The span of the first use of the captured variable inside the closure.
615 // This access has a single span associated to it: common case.
620 pub(super) fn args_or_use(self) -> Span
{
622 UseSpans
::ClosureUse
{
625 | UseSpans
::OtherUse(span
) => span
,
629 pub(super) fn var_or_use(self) -> Span
{
631 UseSpans
::ClosureUse { var_span: span, .. }
| UseSpans
::OtherUse(span
) => span
,
635 pub(super) fn generator_kind(self) -> Option
<GeneratorKind
> {
637 UseSpans
::ClosureUse { generator_kind, .. }
=> generator_kind
,
642 // Add a span label to the arguments of the closure, if it exists.
643 pub(super) fn args_span_label(
645 err
: &mut DiagnosticBuilder
<'_
>,
646 message
: impl Into
<String
>,
648 if let UseSpans
::ClosureUse { args_span, .. }
= self {
649 err
.span_label(args_span
, message
);
653 // Add a span label to the use of the captured variable, if it exists.
654 pub(super) fn var_span_label(
656 err
: &mut DiagnosticBuilder
<'_
>,
657 message
: impl Into
<String
>,
659 if let UseSpans
::ClosureUse { var_span, .. }
= self {
660 err
.span_label(var_span
, message
);
664 /// Returns `false` if this place is not used in a closure.
665 pub(super) fn for_closure(&self) -> bool
{
667 UseSpans
::ClosureUse { generator_kind, .. }
=> generator_kind
.is_none(),
672 /// Returns `false` if this place is not used in a generator.
673 pub(super) fn for_generator(&self) -> bool
{
675 UseSpans
::ClosureUse { generator_kind, .. }
=> generator_kind
.is_some(),
680 /// Describe the span associated with a use of a place.
681 pub(super) fn describe(&self) -> String
{
683 UseSpans
::ClosureUse { generator_kind, .. }
=> if generator_kind
.is_some() {
684 " in generator".to_string()
686 " in closure".to_string()
692 pub(super) fn or_else
<F
>(self, if_other
: F
) -> Self
697 closure @ UseSpans
::ClosureUse { .. }
=> closure
,
698 UseSpans
::OtherUse(_
) => if_other(),
703 pub(super) enum BorrowedContentSource
<'tcx
> {
707 OverloadedDeref(Ty
<'tcx
>),
708 OverloadedIndex(Ty
<'tcx
>),
711 impl BorrowedContentSource
<'tcx
> {
712 pub(super) fn describe_for_unnamed_place(&self) -> String
{
714 BorrowedContentSource
::DerefRawPointer
=> format
!("a raw pointer"),
715 BorrowedContentSource
::DerefSharedRef
=> format
!("a shared reference"),
716 BorrowedContentSource
::DerefMutableRef
=> {
717 format
!("a mutable reference")
719 BorrowedContentSource
::OverloadedDeref(ty
) => {
722 } else if ty
.is_arc() {
725 format
!("dereference of `{}`", ty
)
728 BorrowedContentSource
::OverloadedIndex(ty
) => format
!("index of `{}`", ty
),
732 pub(super) fn describe_for_named_place(&self) -> Option
<&'
static str> {
734 BorrowedContentSource
::DerefRawPointer
=> Some("raw pointer"),
735 BorrowedContentSource
::DerefSharedRef
=> Some("shared reference"),
736 BorrowedContentSource
::DerefMutableRef
=> Some("mutable reference"),
737 // Overloaded deref and index operators should be evaluated into a
738 // temporary. So we don't need a description here.
739 BorrowedContentSource
::OverloadedDeref(_
)
740 | BorrowedContentSource
::OverloadedIndex(_
) => None
744 pub(super) fn describe_for_immutable_place(&self) -> String
{
746 BorrowedContentSource
::DerefRawPointer
=> format
!("a `*const` pointer"),
747 BorrowedContentSource
::DerefSharedRef
=> format
!("a `&` reference"),
748 BorrowedContentSource
::DerefMutableRef
=> {
749 bug
!("describe_for_immutable_place: DerefMutableRef isn't immutable")
751 BorrowedContentSource
::OverloadedDeref(ty
) => {
754 } else if ty
.is_arc() {
757 format
!("a dereference of `{}`", ty
)
760 BorrowedContentSource
::OverloadedIndex(ty
) => format
!("an index of `{}`", ty
),
764 fn from_call(func
: Ty
<'tcx
>, tcx
: TyCtxt
<'tcx
>) -> Option
<Self> {
766 ty
::FnDef(def_id
, substs
) => {
767 let trait_id
= tcx
.trait_of_item(def_id
)?
;
769 let lang_items
= tcx
.lang_items();
770 if Some(trait_id
) == lang_items
.deref_trait()
771 || Some(trait_id
) == lang_items
.deref_mut_trait()
773 Some(BorrowedContentSource
::OverloadedDeref(substs
.type_at(0)))
774 } else if Some(trait_id
) == lang_items
.index_trait()
775 || Some(trait_id
) == lang_items
.index_mut_trait()
777 Some(BorrowedContentSource
::OverloadedIndex(substs
.type_at(0)))
787 impl<'cx
, 'tcx
> MirBorrowckCtxt
<'cx
, 'tcx
> {
788 /// Finds the spans associated to a move or copy of move_place at location.
789 pub(super) fn move_spans(
791 moved_place
: PlaceRef
<'cx
, 'tcx
>, // Could also be an upvar.
794 use self::UseSpans
::*;
796 let stmt
= match self.body
[location
.block
].statements
.get(location
.statement_index
) {
798 None
=> return OtherUse(self.body
.source_info(location
).span
),
801 debug
!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place
, location
, stmt
);
802 if let StatementKind
::Assign(
803 box(_
, Rvalue
::Aggregate(ref kind
, ref places
))
805 let def_id
= match kind
{
806 box AggregateKind
::Closure(def_id
, _
)
807 | box AggregateKind
::Generator(def_id
, _
, _
) => def_id
,
808 _
=> return OtherUse(stmt
.source_info
.span
),
812 "move_spans: def_id={:?} places={:?}",
815 if let Some((args_span
, generator_kind
, var_span
))
816 = self.closure_span(*def_id
, moved_place
, places
) {
825 OtherUse(stmt
.source_info
.span
)
828 /// Finds the span of arguments of a closure (within `maybe_closure_span`)
829 /// and its usage of the local assigned at `location`.
830 /// This is done by searching in statements succeeding `location`
831 /// and originating from `maybe_closure_span`.
832 pub(super) fn borrow_spans(&self, use_span
: Span
, location
: Location
) -> UseSpans
{
833 use self::UseSpans
::*;
834 debug
!("borrow_spans: use_span={:?} location={:?}", use_span
, location
);
836 let target
= match self.body
[location
.block
]
838 .get(location
.statement_index
)
841 kind
: StatementKind
::Assign(box(ref place
, _
)),
844 if let Some(local
) = place
.as_local() {
847 return OtherUse(use_span
);
850 _
=> return OtherUse(use_span
),
853 if self.body
.local_kind(target
) != LocalKind
::Temp
{
854 // operands are always temporaries.
855 return OtherUse(use_span
);
858 for stmt
in &self.body
[location
.block
].statements
[location
.statement_index
+ 1..] {
859 if let StatementKind
::Assign(
860 box(_
, Rvalue
::Aggregate(ref kind
, ref places
))
862 let (def_id
, is_generator
) = match kind
{
863 box AggregateKind
::Closure(def_id
, _
) => (def_id
, false),
864 box AggregateKind
::Generator(def_id
, _
, _
) => (def_id
, true),
869 "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
870 def_id
, is_generator
, places
872 if let Some((args_span
, generator_kind
, var_span
)) = self.closure_span(
873 *def_id
, Place
::from(target
).as_ref(), places
881 return OtherUse(use_span
);
885 if use_span
!= stmt
.source_info
.span
{
893 /// Finds the span of a captured variable within a closure or generator.
897 target_place
: PlaceRef
<'cx
, 'tcx
>,
898 places
: &Vec
<Operand
<'tcx
>>,
899 ) -> Option
<(Span
, Option
<GeneratorKind
>, Span
)> {
901 "closure_span: def_id={:?} target_place={:?} places={:?}",
902 def_id
, target_place
, places
904 let hir_id
= self.infcx
.tcx
.hir().as_local_hir_id(def_id
)?
;
905 let expr
= &self.infcx
.tcx
.hir().expect_expr(hir_id
).kind
;
906 debug
!("closure_span: hir_id={:?} expr={:?}", hir_id
, expr
);
907 if let hir
::ExprKind
::Closure(
908 .., body_id
, args_span
, _
910 for (upvar
, place
) in self.infcx
.tcx
.upvars(def_id
)?
.values().zip(places
) {
912 Operand
::Copy(place
) |
913 Operand
::Move(place
) if target_place
== place
.as_ref() => {
914 debug
!("closure_span: found captured local {:?}", place
);
915 let body
= self.infcx
.tcx
.hir().body(*body_id
);
916 let generator_kind
= body
.generator_kind();
917 return Some((*args_span
, generator_kind
, upvar
.span
));
927 /// Helper to retrieve span(s) of given borrow from the current MIR
929 pub(super) fn retrieve_borrow_spans(&self, borrow
: &BorrowData
<'_
>) -> UseSpans
{
930 let span
= self.body
.source_info(borrow
.reserve_location
).span
;
931 self.borrow_spans(span
, borrow
.reserve_location
)