1use std::collections::BTreeMap;
4
5use rustc_abi::{FieldIdx, VariantIdx};
6use rustc_data_structures::fx::FxIndexMap;
7use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
8use rustc_hir::def::{CtorKind, Namespace};
9use rustc_hir::{self as hir, CoroutineKind, LangItem};
10use rustc_index::IndexSlice;
11use rustc_infer::infer::{
12 BoundRegionConversionTime, NllRegionVariableOrigin, RegionVariableOrigin,
13};
14use rustc_infer::traits::SelectionError;
15use rustc_middle::bug;
16use rustc_middle::mir::tcx::PlaceTy;
17use rustc_middle::mir::{
18 AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
19 LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement,
20 StatementKind, Terminator, TerminatorKind, find_self_call,
21};
22use rustc_middle::ty::print::Print;
23use rustc_middle::ty::{self, Ty, TyCtxt};
24use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};
25use rustc_span::def_id::LocalDefId;
26use rustc_span::source_map::Spanned;
27use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
28use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
29use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
30use rustc_trait_selection::infer::InferCtxtExt;
31use rustc_trait_selection::traits::{
32 FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
33};
34use tracing::debug;
35
36use super::MirBorrowckCtxt;
37use super::borrow_set::BorrowData;
38use crate::constraints::OutlivesConstraint;
39use crate::fluent_generated as fluent;
40use crate::nll::ConstraintDescription;
41use crate::session_diagnostics::{
42 CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
43 CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
44};
45
46mod find_all_local_uses;
47mod find_use;
48mod outlives_suggestion;
49mod region_name;
50mod var_name;
51
52mod bound_region_errors;
53mod conflict_errors;
54mod explain_borrow;
55mod move_errors;
56mod mutability_errors;
57mod opaque_suggestions;
58mod region_errors;
59
60pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};
61pub(crate) use move_errors::{IllegalMoveOriginKind, MoveError};
62pub(crate) use mutability_errors::AccessKind;
63pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder;
64pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
65pub(crate) use region_name::{RegionName, RegionNameSource};
66pub(crate) use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;
67
68pub(super) struct DescribePlaceOpt {
69 including_downcast: bool,
70
71 including_tuple_field: bool,
74}
75
76pub(super) struct IncludingTupleField(pub(super) bool);
77
78enum BufferedDiag<'infcx> {
79 Error(Diag<'infcx>),
80 NonError(Diag<'infcx, ()>),
81}
82
83impl<'infcx> BufferedDiag<'infcx> {
84 fn sort_span(&self) -> Span {
85 match self {
86 BufferedDiag::Error(diag) => diag.sort_span,
87 BufferedDiag::NonError(diag) => diag.sort_span,
88 }
89 }
90}
91
92#[derive(Default)]
93pub(crate) struct BorrowckDiagnosticsBuffer<'infcx, 'tcx> {
94 buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'infcx>)>,
109
110 buffered_mut_errors: FxIndexMap<Span, (Diag<'infcx>, usize)>,
111
112 buffered_diags: Vec<BufferedDiag<'infcx>>,
114}
115
116impl<'infcx, 'tcx> BorrowckDiagnosticsBuffer<'infcx, 'tcx> {
117 pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
118 self.buffered_diags.push(BufferedDiag::NonError(diag));
119 }
120}
121
122impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
123 pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) {
124 self.diags_buffer.buffered_diags.push(BufferedDiag::Error(diag));
125 }
126
127 pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
128 self.diags_buffer.buffer_non_error(diag);
129 }
130
131 pub(crate) fn buffer_move_error(
132 &mut self,
133 move_out_indices: Vec<MoveOutIndex>,
134 place_and_err: (PlaceRef<'tcx>, Diag<'infcx>),
135 ) -> bool {
136 if let Some((_, diag)) =
137 self.diags_buffer.buffered_move_errors.insert(move_out_indices, place_and_err)
138 {
139 diag.cancel();
141 false
142 } else {
143 true
144 }
145 }
146
147 pub(crate) fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'infcx>, usize)> {
148 self.diags_buffer.buffered_mut_errors.swap_remove(&span)
150 }
151
152 pub(crate) fn buffer_mut_error(&mut self, span: Span, diag: Diag<'infcx>, count: usize) {
153 self.diags_buffer.buffered_mut_errors.insert(span, (diag, count));
154 }
155
156 pub(crate) fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
157 let mut res = self.infcx.tainted_by_errors();
158
159 for (_, (_, diag)) in std::mem::take(&mut self.diags_buffer.buffered_move_errors) {
161 self.buffer_error(diag);
163 }
164 for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
165 if count > 10 {
166 #[allow(rustc::diagnostic_outside_of_impl)]
167 #[allow(rustc::untranslatable_diagnostic)]
168 diag.note(format!("...and {} other attempted mutable borrows", count - 10));
169 }
170 self.buffer_error(diag);
171 }
172
173 if !self.diags_buffer.buffered_diags.is_empty() {
174 self.diags_buffer.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
175 for buffered_diag in self.diags_buffer.buffered_diags.drain(..) {
176 match buffered_diag {
177 BufferedDiag::Error(diag) => res = Some(diag.emit()),
178 BufferedDiag::NonError(diag) => diag.emit(),
179 }
180 }
181 }
182
183 res
184 }
185
186 pub(crate) fn has_buffered_diags(&self) -> bool {
187 self.diags_buffer.buffered_diags.is_empty()
188 }
189
190 pub(crate) fn has_move_error(
191 &self,
192 move_out_indices: &[MoveOutIndex],
193 ) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> {
194 self.diags_buffer.buffered_move_errors.get(move_out_indices)
195 }
196}
197
198impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
199 #[allow(rustc::diagnostic_outside_of_impl)] pub(super) fn add_moved_or_invoked_closure_note(
212 &self,
213 location: Location,
214 place: PlaceRef<'tcx>,
215 diag: &mut Diag<'infcx>,
216 ) -> bool {
217 debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
218 let mut target = place.local_or_deref_local();
219 for stmt in &self.body[location.block].statements[location.statement_index..] {
220 debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
221 if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind {
222 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
223 match from {
224 Operand::Copy(place) | Operand::Move(place)
225 if target == place.local_or_deref_local() =>
226 {
227 target = into.local_or_deref_local()
228 }
229 _ => {}
230 }
231 }
232 }
233
234 let terminator = self.body[location.block].terminator();
236 debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
237 if let TerminatorKind::Call {
238 func: Operand::Constant(box ConstOperand { const_, .. }),
239 args,
240 ..
241 } = &terminator.kind
242 {
243 if let ty::FnDef(id, _) = *const_.ty().kind() {
244 debug!("add_moved_or_invoked_closure_note: id={:?}", id);
245 if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
246 let closure = match args.first() {
247 Some(Spanned {
248 node: Operand::Copy(place) | Operand::Move(place), ..
249 }) if target == place.local_or_deref_local() => {
250 place.local_or_deref_local().unwrap()
251 }
252 _ => return false,
253 };
254
255 debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
256 if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
257 let did = did.expect_local();
258 if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
259 diag.subdiagnostic(OnClosureNote::InvokedTwice {
260 place_name: &ty::place_to_string_for_capture(
261 self.infcx.tcx,
262 hir_place,
263 ),
264 span: *span,
265 });
266 return true;
267 }
268 }
269 }
270 }
271 }
272
273 if let Some(target) = target {
275 if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
276 let did = did.expect_local();
277 if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
278 diag.subdiagnostic(OnClosureNote::MovedTwice {
279 place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
280 span: *span,
281 });
282 return true;
283 }
284 }
285 }
286 false
287 }
288
289 pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String {
292 match self.describe_place(place_ref) {
293 Some(mut descr) => {
294 descr.reserve(2);
296 descr.insert(0, '`');
297 descr.push('`');
298 descr
299 }
300 None => "value".to_string(),
301 }
302 }
303
304 pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
307 self.describe_place_with_options(
308 place_ref,
309 DescribePlaceOpt { including_downcast: false, including_tuple_field: true },
310 )
311 }
312
313 pub(super) fn describe_place_with_options(
318 &self,
319 place: PlaceRef<'tcx>,
320 opt: DescribePlaceOpt,
321 ) -> Option<String> {
322 let local = place.local;
323 let mut autoderef_index = None;
324 let mut buf = String::new();
325 let mut ok = self.append_local_to_string(local, &mut buf);
326
327 for (index, elem) in place.projection.into_iter().enumerate() {
328 match elem {
329 ProjectionElem::Deref => {
330 if index == 0 {
331 if self.body.local_decls[local].is_ref_for_guard() {
332 continue;
333 }
334 if let LocalInfo::StaticRef { def_id, .. } =
335 *self.body.local_decls[local].local_info()
336 {
337 buf.push_str(self.infcx.tcx.item_name(def_id).as_str());
338 ok = Ok(());
339 continue;
340 }
341 }
342 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
343 local,
344 projection: place.projection.split_at(index + 1).0,
345 }) {
346 let var_index = field.index();
347 buf = self.upvars[var_index].to_string(self.infcx.tcx);
348 ok = Ok(());
349 if !self.upvars[var_index].is_by_ref() {
350 buf.insert(0, '*');
351 }
352 } else {
353 if autoderef_index.is_none() {
354 autoderef_index = match place.projection.iter().rposition(|elem| {
355 !matches!(
356 elem,
357 ProjectionElem::Deref | ProjectionElem::Downcast(..)
358 )
359 }) {
360 Some(index) => Some(index + 1),
361 None => Some(0),
362 };
363 }
364 if index >= autoderef_index.unwrap() {
365 buf.insert(0, '*');
366 }
367 }
368 }
369 ProjectionElem::Downcast(..) if opt.including_downcast => return None,
370 ProjectionElem::Downcast(..) => (),
371 ProjectionElem::OpaqueCast(..) => (),
372 ProjectionElem::Subtype(..) => (),
373 ProjectionElem::UnwrapUnsafeBinder(_) => (),
374 ProjectionElem::Field(field, _ty) => {
375 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
377 local,
378 projection: place.projection.split_at(index + 1).0,
379 }) {
380 buf = self.upvars[field.index()].to_string(self.infcx.tcx);
381 ok = Ok(());
382 } else {
383 let field_name = self.describe_field(
384 PlaceRef { local, projection: place.projection.split_at(index).0 },
385 *field,
386 IncludingTupleField(opt.including_tuple_field),
387 );
388 if let Some(field_name_str) = field_name {
389 buf.push('.');
390 buf.push_str(&field_name_str);
391 }
392 }
393 }
394 ProjectionElem::Index(index) => {
395 buf.push('[');
396 if self.append_local_to_string(*index, &mut buf).is_err() {
397 buf.push('_');
398 }
399 buf.push(']');
400 }
401 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
402 buf.push_str("[..]");
406 }
407 }
408 }
409 ok.ok().map(|_| buf)
410 }
411
412 fn describe_name(&self, place: PlaceRef<'tcx>) -> Option<Symbol> {
413 for elem in place.projection.into_iter() {
414 match elem {
415 ProjectionElem::Downcast(Some(name), _) => {
416 return Some(*name);
417 }
418 _ => {}
419 }
420 }
421 None
422 }
423
424 fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
427 let decl = &self.body.local_decls[local];
428 match self.local_names[local] {
429 Some(name) if !decl.from_compiler_desugaring() => {
430 buf.push_str(name.as_str());
431 Ok(())
432 }
433 _ => Err(()),
434 }
435 }
436
437 fn describe_field(
439 &self,
440 place: PlaceRef<'tcx>,
441 field: FieldIdx,
442 including_tuple_field: IncludingTupleField,
443 ) -> Option<String> {
444 let place_ty = match place {
445 PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
446 PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
447 ProjectionElem::Deref
448 | ProjectionElem::Index(..)
449 | ProjectionElem::ConstantIndex { .. }
450 | ProjectionElem::Subslice { .. } => {
451 PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
452 }
453 ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
454 ProjectionElem::Subtype(ty)
455 | ProjectionElem::OpaqueCast(ty)
456 | ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
457 ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
458 },
459 };
460 self.describe_field_from_ty(
461 place_ty.ty,
462 field,
463 place_ty.variant_index,
464 including_tuple_field,
465 )
466 }
467
468 fn describe_field_from_ty(
470 &self,
471 ty: Ty<'_>,
472 field: FieldIdx,
473 variant_index: Option<VariantIdx>,
474 including_tuple_field: IncludingTupleField,
475 ) -> Option<String> {
476 if let Some(boxed_ty) = ty.boxed_ty() {
477 self.describe_field_from_ty(boxed_ty, field, variant_index, including_tuple_field)
479 } else {
480 match *ty.kind() {
481 ty::Adt(def, _) => {
482 let variant = if let Some(idx) = variant_index {
483 assert!(def.is_enum());
484 def.variant(idx)
485 } else {
486 def.non_enum_variant()
487 };
488 if !including_tuple_field.0 && variant.ctor_kind() == Some(CtorKind::Fn) {
489 return None;
490 }
491 Some(variant.fields[field].name.to_string())
492 }
493 ty::Tuple(_) => Some(field.index().to_string()),
494 ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
495 self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
496 }
497 ty::Array(ty, _) | ty::Slice(ty) => {
498 self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
499 }
500 ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
501 let def_id = def_id.expect_local();
506 let var_id =
507 self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
508
509 Some(self.infcx.tcx.hir().name(var_id).to_string())
510 }
511 _ => {
512 bug!("End-user description not implemented for field access on `{:?}`", ty);
515 }
516 }
517 }
518 }
519
520 pub(super) fn borrowed_content_source(
521 &self,
522 deref_base: PlaceRef<'tcx>,
523 ) -> BorrowedContentSource<'tcx> {
524 let tcx = self.infcx.tcx;
525
526 match self.move_data.rev_lookup.find(deref_base) {
530 LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
531 debug!("borrowed_content_source: mpi={:?}", mpi);
532
533 for i in &self.move_data.init_path_map[mpi] {
534 let init = &self.move_data.inits[*i];
535 debug!("borrowed_content_source: init={:?}", init);
536 let InitLocation::Statement(loc) = init.location else { continue };
539
540 let bbd = &self.body[loc.block];
541 let is_terminator = bbd.statements.len() == loc.statement_index;
542 debug!(
543 "borrowed_content_source: loc={:?} is_terminator={:?}",
544 loc, is_terminator,
545 );
546 if !is_terminator {
547 continue;
548 } else if let Some(Terminator {
549 kind:
550 TerminatorKind::Call {
551 func,
552 call_source: CallSource::OverloadedOperator,
553 ..
554 },
555 ..
556 }) = &bbd.terminator
557 {
558 if let Some(source) =
559 BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
560 {
561 return source;
562 }
563 }
564 }
565 }
566 _ => (),
568 };
569
570 let base_ty = deref_base.ty(self.body, tcx).ty;
573 if base_ty.is_raw_ptr() {
574 BorrowedContentSource::DerefRawPointer
575 } else if base_ty.is_mutable_ptr() {
576 BorrowedContentSource::DerefMutableRef
577 } else {
578 BorrowedContentSource::DerefSharedRef
579 }
580 }
581
582 pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
585 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
586
587 if let ty::Ref(region, ..) = ty.kind() {
591 match **region {
592 ty::ReBound(_, ty::BoundRegion { kind: br, .. })
593 | ty::RePlaceholder(ty::PlaceholderRegion {
594 bound: ty::BoundRegion { kind: br, .. },
595 ..
596 }) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
597 _ => {}
598 }
599 }
600
601 ty.print(&mut printer).unwrap();
602 printer.into_buffer()
603 }
604
605 pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
608 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
609
610 let region = if let ty::Ref(region, ..) = ty.kind() {
611 match **region {
612 ty::ReBound(_, ty::BoundRegion { kind: br, .. })
613 | ty::RePlaceholder(ty::PlaceholderRegion {
614 bound: ty::BoundRegion { kind: br, .. },
615 ..
616 }) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
617 _ => {}
618 }
619 region
620 } else {
621 bug!("ty for annotation of borrow region is not a reference");
622 };
623
624 region.print(&mut printer).unwrap();
625 printer.into_buffer()
626 }
627
628 fn add_placeholder_from_predicate_note<G: EmissionGuarantee>(
631 &self,
632 err: &mut Diag<'_, G>,
633 path: &[OutlivesConstraint<'tcx>],
634 ) {
635 let predicate_span = path.iter().find_map(|constraint| {
636 let outlived = constraint.sub;
637 if let Some(origin) = self.regioncx.var_infos.get(outlived)
638 && let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(_)) =
639 origin.origin
640 && let ConstraintCategory::Predicate(span) = constraint.category
641 {
642 Some(span)
643 } else {
644 None
645 }
646 });
647
648 if let Some(span) = predicate_span {
649 err.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
650 }
651 }
652
653 fn add_sized_or_copy_bound_info<G: EmissionGuarantee>(
656 &self,
657 err: &mut Diag<'_, G>,
658 blamed_category: ConstraintCategory<'tcx>,
659 path: &[OutlivesConstraint<'tcx>],
660 ) {
661 for sought_category in [ConstraintCategory::SizedBound, ConstraintCategory::CopyBound] {
662 if sought_category != blamed_category
663 && let Some(sought_constraint) = path.iter().find(|c| c.category == sought_category)
664 {
665 let label = format!(
666 "requirement occurs due to {}",
667 sought_category.description().trim_end()
668 );
669 err.span_label(sought_constraint.span, label);
670 }
671 }
672 }
673}
674
675#[derive(Copy, Clone, PartialEq, Eq, Debug)]
677pub(super) enum UseSpans<'tcx> {
678 ClosureUse {
680 closure_kind: hir::ClosureKind,
682 args_span: Span,
685 capture_kind_span: Span,
688 path_span: Span,
691 },
692 FnSelfUse {
695 var_span: Span,
697 fn_call_span: Span,
699 fn_span: Span,
701 kind: CallKind<'tcx>,
702 },
703 PatUse(Span),
705 OtherUse(Span),
707}
708
709impl UseSpans<'_> {
710 pub(super) fn args_or_use(self) -> Span {
711 match self {
712 UseSpans::ClosureUse { args_span: span, .. }
713 | UseSpans::PatUse(span)
714 | UseSpans::OtherUse(span) => span,
715 UseSpans::FnSelfUse { var_span, .. } => var_span,
716 }
717 }
718
719 pub(super) fn var_or_use_path_span(self) -> Span {
721 match self {
722 UseSpans::ClosureUse { path_span: span, .. }
723 | UseSpans::PatUse(span)
724 | UseSpans::OtherUse(span) => span,
725 UseSpans::FnSelfUse { var_span, .. } => var_span,
726 }
727 }
728
729 pub(super) fn var_or_use(self) -> Span {
731 match self {
732 UseSpans::ClosureUse { capture_kind_span: span, .. }
733 | UseSpans::PatUse(span)
734 | UseSpans::OtherUse(span) => span,
735 UseSpans::FnSelfUse { var_span, .. } => var_span,
736 }
737 }
738
739 pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
741 match self {
742 UseSpans::ClosureUse {
743 closure_kind: hir::ClosureKind::Coroutine(coroutine_kind),
744 ..
745 } => Some(coroutine_kind),
746 _ => None,
747 }
748 }
749
750 #[allow(rustc::diagnostic_outside_of_impl)]
752 pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {
753 if let UseSpans::ClosureUse { args_span, .. } = self {
754 err.subdiagnostic(f(args_span));
755 }
756 }
757
758 #[allow(rustc::diagnostic_outside_of_impl)]
761 pub(super) fn var_path_only_subdiag(
762 self,
763 err: &mut Diag<'_>,
764 action: crate::InitializationRequiringAction,
765 ) {
766 use CaptureVarPathUseCause::*;
767
768 use crate::InitializationRequiringAction::*;
769 if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
770 match closure_kind {
771 hir::ClosureKind::Coroutine(_) => {
772 err.subdiagnostic(match action {
773 Borrow => BorrowInCoroutine { path_span },
774 MatchOn | Use => UseInCoroutine { path_span },
775 Assignment => AssignInCoroutine { path_span },
776 PartialAssignment => AssignPartInCoroutine { path_span },
777 });
778 }
779 hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
780 err.subdiagnostic(match action {
781 Borrow => BorrowInClosure { path_span },
782 MatchOn | Use => UseInClosure { path_span },
783 Assignment => AssignInClosure { path_span },
784 PartialAssignment => AssignPartInClosure { path_span },
785 });
786 }
787 }
788 }
789 }
790
791 #[allow(rustc::diagnostic_outside_of_impl)]
793 pub(super) fn var_subdiag(
794 self,
795 err: &mut Diag<'_>,
796 kind: Option<rustc_middle::mir::BorrowKind>,
797 f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
798 ) {
799 if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
800 if capture_kind_span != path_span {
801 err.subdiagnostic(match kind {
802 Some(kd) => match kd {
803 rustc_middle::mir::BorrowKind::Shared
804 | rustc_middle::mir::BorrowKind::Fake(_) => {
805 CaptureVarKind::Immut { kind_span: capture_kind_span }
806 }
807
808 rustc_middle::mir::BorrowKind::Mut { .. } => {
809 CaptureVarKind::Mut { kind_span: capture_kind_span }
810 }
811 },
812 None => CaptureVarKind::Move { kind_span: capture_kind_span },
813 });
814 };
815 let diag = f(closure_kind, path_span);
816 err.subdiagnostic(diag);
817 }
818 }
819
820 pub(super) fn for_closure(&self) -> bool {
822 match *self {
823 UseSpans::ClosureUse { closure_kind, .. } => {
824 matches!(closure_kind, hir::ClosureKind::Closure)
825 }
826 _ => false,
827 }
828 }
829
830 pub(super) fn for_coroutine(&self) -> bool {
832 match *self {
833 UseSpans::ClosureUse { closure_kind, .. } => {
835 matches!(closure_kind, hir::ClosureKind::Coroutine(..))
836 }
837 _ => false,
838 }
839 }
840
841 pub(super) fn or_else<F>(self, if_other: F) -> Self
842 where
843 F: FnOnce() -> Self,
844 {
845 match self {
846 closure @ UseSpans::ClosureUse { .. } => closure,
847 UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
848 fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
849 }
850 }
851}
852
853pub(super) enum BorrowedContentSource<'tcx> {
854 DerefRawPointer,
855 DerefMutableRef,
856 DerefSharedRef,
857 OverloadedDeref(Ty<'tcx>),
858 OverloadedIndex(Ty<'tcx>),
859}
860
861impl<'tcx> BorrowedContentSource<'tcx> {
862 pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
863 match *self {
864 BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
865 BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
866 BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
867 BorrowedContentSource::OverloadedDeref(ty) => ty
868 .ty_adt_def()
869 .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
870 name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
871 _ => None,
872 })
873 .unwrap_or_else(|| format!("dereference of `{ty}`")),
874 BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"),
875 }
876 }
877
878 pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
879 match *self {
880 BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
881 BorrowedContentSource::DerefSharedRef => Some("shared reference"),
882 BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
883 BorrowedContentSource::OverloadedDeref(_)
886 | BorrowedContentSource::OverloadedIndex(_) => None,
887 }
888 }
889
890 pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
891 match *self {
892 BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(),
893 BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(),
894 BorrowedContentSource::DerefMutableRef => {
895 bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
896 }
897 BorrowedContentSource::OverloadedDeref(ty) => ty
898 .ty_adt_def()
899 .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
900 name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
901 _ => None,
902 })
903 .unwrap_or_else(|| format!("dereference of `{ty}`")),
904 BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"),
905 }
906 }
907
908 fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
909 match *func.kind() {
910 ty::FnDef(def_id, args) => {
911 let trait_id = tcx.trait_of_item(def_id)?;
912
913 if tcx.is_lang_item(trait_id, LangItem::Deref)
914 || tcx.is_lang_item(trait_id, LangItem::DerefMut)
915 {
916 Some(BorrowedContentSource::OverloadedDeref(args.type_at(0)))
917 } else if tcx.is_lang_item(trait_id, LangItem::Index)
918 || tcx.is_lang_item(trait_id, LangItem::IndexMut)
919 {
920 Some(BorrowedContentSource::OverloadedIndex(args.type_at(0)))
921 } else {
922 None
923 }
924 }
925 _ => None,
926 }
927 }
928}
929
930struct CapturedMessageOpt {
932 is_partial_move: bool,
933 is_loop_message: bool,
934 is_move_msg: bool,
935 is_loop_move: bool,
936 has_suggest_reborrow: bool,
937 maybe_reinitialized_locations_is_empty: bool,
938}
939
940impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
941 pub(super) fn move_spans(
943 &self,
944 moved_place: PlaceRef<'tcx>, location: Location,
946 ) -> UseSpans<'tcx> {
947 use self::UseSpans::*;
948
949 let Some(stmt) = self.body[location.block].statements.get(location.statement_index) else {
950 return OtherUse(self.body.source_info(location).span);
951 };
952
953 debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
954 if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
955 && let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) = **kind
956 {
957 debug!("move_spans: def_id={:?} places={:?}", def_id, places);
958 let def_id = def_id.expect_local();
959 if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
960 self.closure_span(def_id, moved_place, places)
961 {
962 return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
963 }
964 }
965
966 if let StatementKind::FakeRead(box (cause, place)) = stmt.kind {
969 match cause {
970 FakeReadCause::ForMatchedPlace(Some(closure_def_id))
971 | FakeReadCause::ForLet(Some(closure_def_id)) => {
972 debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
973 let places = &[Operand::Move(place)];
974 if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
975 self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
976 {
977 return ClosureUse {
978 closure_kind,
979 args_span,
980 capture_kind_span,
981 path_span,
982 };
983 }
984 }
985 _ => {}
986 }
987 }
988
989 let normal_ret =
990 if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
991 PatUse(stmt.source_info.span)
992 } else {
993 OtherUse(stmt.source_info.span)
994 };
995
996 let target_temp = match stmt.kind {
1008 StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
1009 temp.as_local().unwrap()
1010 }
1011 _ => return normal_ret,
1012 };
1013
1014 debug!("move_spans: target_temp = {:?}", target_temp);
1015
1016 if let Some(Terminator {
1017 kind: TerminatorKind::Call { fn_span, call_source, .. }, ..
1018 }) = &self.body[location.block].terminator
1019 {
1020 let Some((method_did, method_args)) =
1021 find_self_call(self.infcx.tcx, self.body, target_temp, location.block)
1022 else {
1023 return normal_ret;
1024 };
1025
1026 let kind = call_kind(
1027 self.infcx.tcx,
1028 self.infcx.typing_env(self.infcx.param_env),
1029 method_did,
1030 method_args,
1031 *fn_span,
1032 call_source.from_hir_call(),
1033 Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
1034 );
1035
1036 return FnSelfUse {
1037 var_span: stmt.source_info.span,
1038 fn_call_span: *fn_span,
1039 fn_span: self.infcx.tcx.def_span(method_did),
1040 kind,
1041 };
1042 }
1043
1044 normal_ret
1045 }
1046
1047 pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
1052 use self::UseSpans::*;
1053 debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
1054
1055 let target = match self.body[location.block].statements.get(location.statement_index) {
1056 Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => {
1057 if let Some(local) = place.as_local() {
1058 local
1059 } else {
1060 return OtherUse(use_span);
1061 }
1062 }
1063 _ => return OtherUse(use_span),
1064 };
1065
1066 if self.body.local_kind(target) != LocalKind::Temp {
1067 return OtherUse(use_span);
1069 }
1070
1071 let maybe_additional_statement =
1073 if let TerminatorKind::Drop { target: drop_target, .. } =
1074 self.body[location.block].terminator().kind
1075 {
1076 self.body[drop_target].statements.first()
1077 } else {
1078 None
1079 };
1080
1081 let statements =
1082 self.body[location.block].statements[location.statement_index + 1..].iter();
1083
1084 for stmt in statements.chain(maybe_additional_statement) {
1085 if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
1086 let (&def_id, is_coroutine) = match kind {
1087 box AggregateKind::Closure(def_id, _) => (def_id, false),
1088 box AggregateKind::Coroutine(def_id, _) => (def_id, true),
1089 _ => continue,
1090 };
1091 let def_id = def_id.expect_local();
1092
1093 debug!(
1094 "borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",
1095 def_id, is_coroutine, places
1096 );
1097 if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
1098 self.closure_span(def_id, Place::from(target).as_ref(), places)
1099 {
1100 return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
1101 } else {
1102 return OtherUse(use_span);
1103 }
1104 }
1105
1106 if use_span != stmt.source_info.span {
1107 break;
1108 }
1109 }
1110
1111 OtherUse(use_span)
1112 }
1113
1114 fn closure_span(
1118 &self,
1119 def_id: LocalDefId,
1120 target_place: PlaceRef<'tcx>,
1121 places: &IndexSlice<FieldIdx, Operand<'tcx>>,
1122 ) -> Option<(Span, hir::ClosureKind, Span, Span)> {
1123 debug!(
1124 "closure_span: def_id={:?} target_place={:?} places={:?}",
1125 def_id, target_place, places
1126 );
1127 let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
1128 let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
1129 debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
1130 if let hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr {
1131 for (captured_place, place) in
1132 self.infcx.tcx.closure_captures(def_id).iter().zip(places)
1133 {
1134 match place {
1135 Operand::Copy(place) | Operand::Move(place)
1136 if target_place == place.as_ref() =>
1137 {
1138 debug!("closure_span: found captured local {:?}", place);
1139 return Some((
1140 fn_decl_span,
1141 kind,
1142 captured_place.get_capture_kind_span(self.infcx.tcx),
1143 captured_place.get_path_span(self.infcx.tcx),
1144 ));
1145 }
1146 _ => {}
1147 }
1148 }
1149 }
1150 None
1151 }
1152
1153 pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
1156 let span = self.body.source_info(borrow.reserve_location).span;
1157 self.borrow_spans(span, borrow.reserve_location)
1158 }
1159
1160 #[allow(rustc::diagnostic_outside_of_impl)]
1161 #[allow(rustc::untranslatable_diagnostic)] fn explain_captures(
1163 &mut self,
1164 err: &mut Diag<'infcx>,
1165 span: Span,
1166 move_span: Span,
1167 move_spans: UseSpans<'tcx>,
1168 moved_place: Place<'tcx>,
1169 msg_opt: CapturedMessageOpt,
1170 ) {
1171 let CapturedMessageOpt {
1172 is_partial_move: is_partial,
1173 is_loop_message,
1174 is_move_msg,
1175 is_loop_move,
1176 has_suggest_reborrow,
1177 maybe_reinitialized_locations_is_empty,
1178 } = msg_opt;
1179 if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
1180 let place_name = self
1181 .describe_place(moved_place.as_ref())
1182 .map(|n| format!("`{n}`"))
1183 .unwrap_or_else(|| "value".to_owned());
1184 match kind {
1185 CallKind::FnCall { fn_trait_id, self_ty }
1186 if self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) =>
1187 {
1188 err.subdiagnostic(CaptureReasonLabel::Call {
1189 fn_call_span,
1190 place_name: &place_name,
1191 is_partial,
1192 is_loop_message,
1193 });
1194 if let ty::Param(param_ty) = *self_ty.kind()
1216 && let generics = self.infcx.tcx.generics_of(self.mir_def_id())
1217 && let param = generics.type_param(param_ty, self.infcx.tcx)
1218 && let Some(hir_generics) = self
1219 .infcx
1220 .tcx
1221 .typeck_root_def_id(self.mir_def_id().to_def_id())
1222 .as_local()
1223 .and_then(|def_id| self.infcx.tcx.hir().get_generics(def_id))
1224 && let spans = hir_generics
1225 .predicates
1226 .iter()
1227 .filter_map(|pred| match pred.kind {
1228 hir::WherePredicateKind::BoundPredicate(pred) => Some(pred),
1229 _ => None,
1230 })
1231 .filter(|pred| {
1232 if let Some((id, _)) = pred.bounded_ty.as_generic_param() {
1233 id == param.def_id
1234 } else {
1235 false
1236 }
1237 })
1238 .flat_map(|pred| pred.bounds)
1239 .filter_map(|bound| {
1240 if let Some(trait_ref) = bound.trait_ref()
1241 && let Some(trait_def_id) = trait_ref.trait_def_id()
1242 && trait_def_id == fn_trait_id
1243 {
1244 Some(bound.span())
1245 } else {
1246 None
1247 }
1248 })
1249 .collect::<Vec<Span>>()
1250 && !spans.is_empty()
1251 {
1252 let mut span: MultiSpan = spans.clone().into();
1253 for sp in spans {
1254 span.push_span_label(sp, fluent::borrowck_moved_a_fn_once_in_call_def);
1255 }
1256 span.push_span_label(
1257 fn_call_span,
1258 fluent::borrowck_moved_a_fn_once_in_call,
1259 );
1260 err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call);
1261 } else {
1262 err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
1263 }
1264 }
1265 CallKind::Operator { self_arg, trait_id, .. } => {
1266 let self_arg = self_arg.unwrap();
1267 err.subdiagnostic(CaptureReasonLabel::OperatorUse {
1268 fn_call_span,
1269 place_name: &place_name,
1270 is_partial,
1271 is_loop_message,
1272 });
1273 if self.fn_self_span_reported.insert(fn_span) {
1274 let lang = self.infcx.tcx.lang_items();
1275 err.subdiagnostic(
1276 if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]
1277 .contains(&Some(trait_id))
1278 {
1279 CaptureReasonNote::UnOpMoveByOperator { span: self_arg.span }
1280 } else {
1281 CaptureReasonNote::LhsMoveByOperator { span: self_arg.span }
1282 },
1283 );
1284 }
1285 }
1286 CallKind::Normal { self_arg, desugaring, method_did, method_args } => {
1287 let self_arg = self_arg.unwrap();
1288 let mut has_sugg = false;
1289 let tcx = self.infcx.tcx;
1290 if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
1293 self.explain_iterator_advancement_in_for_loop_if_applicable(
1294 err,
1295 span,
1296 &move_spans,
1297 );
1298
1299 let func = tcx.def_path_str(method_did);
1300 err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
1301 func,
1302 place_name: place_name.clone(),
1303 span: self_arg.span,
1304 });
1305 }
1306 let parent_did = tcx.parent(method_did);
1307 let parent_self_ty =
1308 matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
1309 .then_some(parent_did)
1310 .and_then(|did| match tcx.type_of(did).instantiate_identity().kind() {
1311 ty::Adt(def, ..) => Some(def.did()),
1312 _ => None,
1313 });
1314 let is_option_or_result = parent_self_ty.is_some_and(|def_id| {
1315 matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
1316 });
1317 if is_option_or_result && maybe_reinitialized_locations_is_empty {
1318 err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
1319 }
1320 if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
1321 let ty = moved_place.ty(self.body, tcx).ty;
1322 let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
1323 Some(def_id) => type_known_to_meet_bound_modulo_regions(
1324 self.infcx,
1325 self.infcx.param_env,
1326 Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),
1327 def_id,
1328 ),
1329 _ => false,
1330 };
1331 if suggest {
1332 err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
1333 ty,
1334 span: move_span.shrink_to_lo(),
1335 });
1336 }
1337
1338 err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
1339 fn_call_span,
1340 place_name: &place_name,
1341 is_partial,
1342 is_loop_message,
1343 });
1344 if let ty::Ref(_, _, hir::Mutability::Mut) =
1348 moved_place.ty(self.body, self.infcx.tcx).ty.kind()
1349 {
1350 if !is_loop_move && !has_suggest_reborrow {
1355 self.suggest_reborrow(
1356 err,
1357 move_span.shrink_to_lo(),
1358 moved_place.as_ref(),
1359 );
1360 }
1361 }
1362 } else {
1363 if let Some((CallDesugaringKind::Await, _)) = desugaring {
1364 err.subdiagnostic(CaptureReasonLabel::Await {
1365 fn_call_span,
1366 place_name: &place_name,
1367 is_partial,
1368 is_loop_message,
1369 });
1370 } else {
1371 err.subdiagnostic(CaptureReasonLabel::MethodCall {
1372 fn_call_span,
1373 place_name: &place_name,
1374 is_partial,
1375 is_loop_message,
1376 });
1377 }
1378 let ty = moved_place.ty(self.body, tcx).ty;
1380
1381 if let ty::Adt(def, args) = ty.peel_refs().kind()
1382 && tcx.is_lang_item(def.did(), LangItem::Pin)
1383 && let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind()
1384 && let self_ty = self.infcx.instantiate_binder_with_fresh_vars(
1385 fn_call_span,
1386 BoundRegionConversionTime::FnCall,
1387 tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0),
1388 )
1389 && self.infcx.can_eq(self.infcx.param_env, ty, self_ty)
1390 {
1391 err.subdiagnostic(CaptureReasonSuggest::FreshReborrow {
1392 span: move_span.shrink_to_hi(),
1393 });
1394 has_sugg = true;
1395 }
1396 if let Some(clone_trait) = tcx.lang_items().clone_trait() {
1397 let sugg = if moved_place
1398 .iter_projections()
1399 .any(|(_, elem)| matches!(elem, ProjectionElem::Deref))
1400 {
1401 let (start, end) = if let Some(expr) = self.find_expr(move_span)
1402 && let Some(_) = self.clone_on_reference(expr)
1403 && let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind
1404 {
1405 (move_span.shrink_to_lo(), move_span.with_lo(rcvr.span.hi()))
1406 } else {
1407 (move_span.shrink_to_lo(), move_span.shrink_to_hi())
1408 };
1409 vec![
1410 (start, format!("<{ty} as Clone>::clone(&")),
1415 (end, ")".to_string()),
1416 ]
1417 } else {
1418 vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
1419 };
1420 if let Some(errors) = self.infcx.type_implements_trait_shallow(
1421 clone_trait,
1422 ty,
1423 self.infcx.param_env,
1424 ) && !has_sugg
1425 {
1426 let msg = match &errors[..] {
1427 [] => "you can `clone` the value and consume it, but this \
1428 might not be your desired behavior"
1429 .to_string(),
1430 [error] => {
1431 format!(
1432 "you could `clone` the value and consume it, if the \
1433 `{}` trait bound could be satisfied",
1434 error.obligation.predicate,
1435 )
1436 }
1437 _ => {
1438 format!(
1439 "you could `clone` the value and consume it, if the \
1440 following trait bounds could be satisfied: {}",
1441 listify(&errors, |e: &FulfillmentError<'tcx>| format!(
1442 "`{}`",
1443 e.obligation.predicate
1444 ))
1445 .unwrap(),
1446 )
1447 }
1448 };
1449 err.multipart_suggestion_verbose(
1450 msg,
1451 sugg,
1452 Applicability::MaybeIncorrect,
1453 );
1454 for error in errors {
1455 if let FulfillmentErrorCode::Select(
1456 SelectionError::Unimplemented,
1457 ) = error.code
1458 && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
1459 pred,
1460 )) = error.obligation.predicate.kind().skip_binder()
1461 {
1462 self.infcx.err_ctxt().suggest_derive(
1463 &error.obligation,
1464 err,
1465 error.obligation.predicate.kind().rebind(pred),
1466 );
1467 }
1468 }
1469 }
1470 }
1471 }
1472 }
1473 _ => {}
1475 }
1476 } else {
1477 if move_span != span || is_loop_message {
1478 err.subdiagnostic(CaptureReasonLabel::MovedHere {
1479 move_span,
1480 is_partial,
1481 is_move_msg,
1482 is_loop_message,
1483 });
1484 }
1485 if !is_loop_message {
1488 move_spans.var_subdiag(err, None, |kind, var_span| match kind {
1489 hir::ClosureKind::Coroutine(_) => {
1490 CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
1491 }
1492 hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
1493 CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }
1494 }
1495 })
1496 }
1497 }
1498 }
1499}