]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/diagnostics/mod.rs
Rollup merge of #90023 - b-naber:postpone_const_eval_infer_vars, r=nikomatsakis
[rust.git] / compiler / rustc_borrowck / src / diagnostics / mod.rs
1 //! Borrow checker diagnostics.
2
3 use rustc_errors::DiagnosticBuilder;
4 use rustc_hir as hir;
5 use rustc_hir::def::Namespace;
6 use rustc_hir::def_id::DefId;
7 use rustc_hir::lang_items::LangItemGroup;
8 use rustc_hir::GeneratorKind;
9 use rustc_middle::mir::{
10     AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
11     Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
12 };
13 use rustc_middle::ty::print::Print;
14 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
15 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
16 use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
17 use rustc_target::abi::VariantIdx;
18
19 use super::borrow_set::BorrowData;
20 use super::MirBorrowckCtxt;
21
22 mod find_use;
23 mod outlives_suggestion;
24 mod region_name;
25 mod var_name;
26
27 mod bound_region_errors;
28 mod conflict_errors;
29 mod explain_borrow;
30 mod move_errors;
31 mod mutability_errors;
32 mod region_errors;
33
34 crate use bound_region_errors::{ToUniverseInfo, UniverseInfo};
35 crate use mutability_errors::AccessKind;
36 crate use outlives_suggestion::OutlivesSuggestionBuilder;
37 crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
38 crate use region_name::{RegionName, RegionNameSource};
39 use rustc_span::symbol::Ident;
40
41 pub(super) struct IncludingDowncast(pub(super) bool);
42
43 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
44     /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
45     /// is moved after being invoked.
46     ///
47     /// ```text
48     /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
49     ///       its environment
50     ///   --> $DIR/issue-42065.rs:16:29
51     ///    |
52     /// LL |         for (key, value) in dict {
53     ///    |                             ^^^^
54     /// ```
55     pub(super) fn add_moved_or_invoked_closure_note(
56         &self,
57         location: Location,
58         place: PlaceRef<'tcx>,
59         diag: &mut DiagnosticBuilder<'_>,
60     ) {
61         debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
62         let mut target = place.local_or_deref_local();
63         for stmt in &self.body[location.block].statements[location.statement_index..] {
64             debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
65             if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind {
66                 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
67                 match from {
68                     Operand::Copy(ref place) | Operand::Move(ref place)
69                         if target == place.local_or_deref_local() =>
70                     {
71                         target = into.local_or_deref_local()
72                     }
73                     _ => {}
74                 }
75             }
76         }
77
78         // Check if we are attempting to call a closure after it has been invoked.
79         let terminator = self.body[location.block].terminator();
80         debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
81         if let TerminatorKind::Call {
82             func: Operand::Constant(box Constant { literal, .. }),
83             args,
84             ..
85         } = &terminator.kind
86         {
87             if let ty::FnDef(id, _) = *literal.ty().kind() {
88                 debug!("add_moved_or_invoked_closure_note: id={:?}", id);
89                 if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() {
90                     let closure = match args.first() {
91                         Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place))
92                             if target == place.local_or_deref_local() =>
93                         {
94                             place.local_or_deref_local().unwrap()
95                         }
96                         _ => return,
97                     };
98
99                     debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
100                     if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
101                         let did = did.expect_local();
102                         let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
103
104                         if let Some((span, hir_place)) =
105                             self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
106                         {
107                             diag.span_note(
108                                 *span,
109                                 &format!(
110                                     "closure cannot be invoked more than once because it moves the \
111                                     variable `{}` out of its environment",
112                                     ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
113                                 ),
114                             );
115                             return;
116                         }
117                     }
118                 }
119             }
120         }
121
122         // Check if we are just moving a closure after it has been invoked.
123         if let Some(target) = target {
124             if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
125                 let did = did.expect_local();
126                 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
127
128                 if let Some((span, hir_place)) =
129                     self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
130                 {
131                     diag.span_note(
132                         *span,
133                         &format!(
134                             "closure cannot be moved more than once as it is not `Copy` due to \
135                              moving the variable `{}` out of its environment",
136                             ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
137                         ),
138                     );
139                 }
140             }
141         }
142     }
143
144     /// End-user visible description of `place` if one can be found.
145     /// If the place is a temporary for instance, `"value"` will be returned.
146     pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String {
147         match self.describe_place(place_ref) {
148             Some(mut descr) => {
149                 // Surround descr with `backticks`.
150                 descr.reserve(2);
151                 descr.insert(0, '`');
152                 descr.push('`');
153                 descr
154             }
155             None => "value".to_string(),
156         }
157     }
158
159     /// End-user visible description of `place` if one can be found.
160     /// If the place is a temporary for instance, None will be returned.
161     pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
162         self.describe_place_with_options(place_ref, IncludingDowncast(false))
163     }
164
165     /// End-user visible description of `place` if one can be found. If the
166     /// place is a temporary for instance, None will be returned.
167     /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
168     /// `Downcast` and `IncludingDowncast` is true
169     pub(super) fn describe_place_with_options(
170         &self,
171         place: PlaceRef<'tcx>,
172         including_downcast: IncludingDowncast,
173     ) -> Option<String> {
174         let mut buf = String::new();
175         match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
176             Ok(()) => Some(buf),
177             Err(()) => None,
178         }
179     }
180
181     /// Appends end-user visible description of `place` to `buf`.
182     fn append_place_to_string(
183         &self,
184         place: PlaceRef<'tcx>,
185         buf: &mut String,
186         mut autoderef: bool,
187         including_downcast: &IncludingDowncast,
188     ) -> Result<(), ()> {
189         match place {
190             PlaceRef { local, projection: [] } => {
191                 self.append_local_to_string(local, buf)?;
192             }
193             PlaceRef { local, projection: [ProjectionElem::Deref] }
194                 if self.body.local_decls[local].is_ref_for_guard() =>
195             {
196                 self.append_place_to_string(
197                     PlaceRef { local, projection: &[] },
198                     buf,
199                     autoderef,
200                     &including_downcast,
201                 )?;
202             }
203             PlaceRef { local, projection: [ProjectionElem::Deref] }
204                 if self.body.local_decls[local].is_ref_to_static() =>
205             {
206                 let local_info = &self.body.local_decls[local].local_info;
207                 if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
208                     buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
209                 } else {
210                     unreachable!();
211                 }
212             }
213             PlaceRef { local, projection: [proj_base @ .., elem] } => {
214                 match elem {
215                     ProjectionElem::Deref => {
216                         let upvar_field_projection = self.is_upvar_field_projection(place);
217                         if let Some(field) = upvar_field_projection {
218                             let var_index = field.index();
219                             let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
220                             if self.upvars[var_index].by_ref {
221                                 buf.push_str(&name);
222                             } else {
223                                 buf.push('*');
224                                 buf.push_str(&name);
225                             }
226                         } else {
227                             if autoderef {
228                                 // FIXME turn this recursion into iteration
229                                 self.append_place_to_string(
230                                     PlaceRef { local, projection: proj_base },
231                                     buf,
232                                     autoderef,
233                                     &including_downcast,
234                                 )?;
235                             } else {
236                                 buf.push('*');
237                                 self.append_place_to_string(
238                                     PlaceRef { local, projection: proj_base },
239                                     buf,
240                                     autoderef,
241                                     &including_downcast,
242                                 )?;
243                             }
244                         }
245                     }
246                     ProjectionElem::Downcast(..) => {
247                         self.append_place_to_string(
248                             PlaceRef { local, projection: proj_base },
249                             buf,
250                             autoderef,
251                             &including_downcast,
252                         )?;
253                         if including_downcast.0 {
254                             return Err(());
255                         }
256                     }
257                     ProjectionElem::Field(field, _ty) => {
258                         autoderef = true;
259
260                         // FIXME(project-rfc_2229#36): print capture precisely here.
261                         let upvar_field_projection = self.is_upvar_field_projection(place);
262                         if let Some(field) = upvar_field_projection {
263                             let var_index = field.index();
264                             let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
265                             buf.push_str(&name);
266                         } else {
267                             let field_name = self
268                                 .describe_field(PlaceRef { local, projection: proj_base }, *field);
269                             self.append_place_to_string(
270                                 PlaceRef { local, projection: proj_base },
271                                 buf,
272                                 autoderef,
273                                 &including_downcast,
274                             )?;
275                             buf.push('.');
276                             buf.push_str(&field_name);
277                         }
278                     }
279                     ProjectionElem::Index(index) => {
280                         autoderef = true;
281
282                         self.append_place_to_string(
283                             PlaceRef { local, projection: proj_base },
284                             buf,
285                             autoderef,
286                             &including_downcast,
287                         )?;
288                         buf.push('[');
289                         if self.append_local_to_string(*index, buf).is_err() {
290                             buf.push('_');
291                         }
292                         buf.push(']');
293                     }
294                     ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
295                         autoderef = true;
296                         // Since it isn't possible to borrow an element on a particular index and
297                         // then use another while the borrow is held, don't output indices details
298                         // to avoid confusing the end-user
299                         self.append_place_to_string(
300                             PlaceRef { local, projection: proj_base },
301                             buf,
302                             autoderef,
303                             &including_downcast,
304                         )?;
305                         buf.push_str("[..]");
306                     }
307                 };
308             }
309         }
310
311         Ok(())
312     }
313
314     /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
315     /// a name, or its name was generated by the compiler, then `Err` is returned
316     fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
317         let decl = &self.body.local_decls[local];
318         match self.local_names[local] {
319             Some(name) if !decl.from_compiler_desugaring() => {
320                 buf.push_str(&name.as_str());
321                 Ok(())
322             }
323             _ => Err(()),
324         }
325     }
326
327     /// End-user visible description of the `field`nth field of `base`
328     fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
329         // FIXME Place2 Make this work iteratively
330         match place {
331             PlaceRef { local, projection: [] } => {
332                 let local = &self.body.local_decls[local];
333                 self.describe_field_from_ty(&local.ty, field, None)
334             }
335             PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
336                 ProjectionElem::Deref => {
337                     self.describe_field(PlaceRef { local, projection: proj_base }, field)
338                 }
339                 ProjectionElem::Downcast(_, variant_index) => {
340                     let base_ty = place.ty(self.body, self.infcx.tcx).ty;
341                     self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
342                 }
343                 ProjectionElem::Field(_, field_type) => {
344                     self.describe_field_from_ty(&field_type, field, None)
345                 }
346                 ProjectionElem::Index(..)
347                 | ProjectionElem::ConstantIndex { .. }
348                 | ProjectionElem::Subslice { .. } => {
349                     self.describe_field(PlaceRef { local, projection: proj_base }, field)
350                 }
351             },
352         }
353     }
354
355     /// End-user visible description of the `field_index`nth field of `ty`
356     fn describe_field_from_ty(
357         &self,
358         ty: Ty<'_>,
359         field: Field,
360         variant_index: Option<VariantIdx>,
361     ) -> String {
362         if ty.is_box() {
363             // If the type is a box, the field is described from the boxed type
364             self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index)
365         } else {
366             match *ty.kind() {
367                 ty::Adt(def, _) => {
368                     let variant = if let Some(idx) = variant_index {
369                         assert!(def.is_enum());
370                         &def.variants[idx]
371                     } else {
372                         def.non_enum_variant()
373                     };
374                     variant.fields[field.index()].ident.to_string()
375                 }
376                 ty::Tuple(_) => field.index().to_string(),
377                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
378                     self.describe_field_from_ty(&ty, field, variant_index)
379                 }
380                 ty::Array(ty, _) | ty::Slice(ty) => {
381                     self.describe_field_from_ty(&ty, field, variant_index)
382                 }
383                 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
384                     // We won't be borrowck'ing here if the closure came from another crate,
385                     // so it's safe to call `expect_local`.
386                     //
387                     // We know the field exists so it's safe to call operator[] and `unwrap` here.
388                     let var_id = self
389                         .infcx
390                         .tcx
391                         .typeck(def_id.expect_local())
392                         .closure_min_captures_flattened(def_id)
393                         .nth(field.index())
394                         .unwrap()
395                         .get_root_variable();
396
397                     self.infcx.tcx.hir().name(var_id).to_string()
398                 }
399                 _ => {
400                     // Might need a revision when the fields in trait RFC is implemented
401                     // (https://github.com/rust-lang/rfcs/pull/1546)
402                     bug!("End-user description not implemented for field access on `{:?}`", ty);
403                 }
404             }
405         }
406     }
407
408     /// Add a note that a type does not implement `Copy`
409     pub(super) fn note_type_does_not_implement_copy(
410         &self,
411         err: &mut DiagnosticBuilder<'a>,
412         place_desc: &str,
413         ty: Ty<'tcx>,
414         span: Option<Span>,
415         move_prefix: &str,
416     ) {
417         let message = format!(
418             "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait",
419             move_prefix, place_desc, ty,
420         );
421         if let Some(span) = span {
422             err.span_label(span, message);
423         } else {
424             err.note(&message);
425         }
426     }
427
428     pub(super) fn borrowed_content_source(
429         &self,
430         deref_base: PlaceRef<'tcx>,
431     ) -> BorrowedContentSource<'tcx> {
432         let tcx = self.infcx.tcx;
433
434         // Look up the provided place and work out the move path index for it,
435         // we'll use this to check whether it was originally from an overloaded
436         // operator.
437         match self.move_data.rev_lookup.find(deref_base) {
438             LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
439                 debug!("borrowed_content_source: mpi={:?}", mpi);
440
441                 for i in &self.move_data.init_path_map[mpi] {
442                     let init = &self.move_data.inits[*i];
443                     debug!("borrowed_content_source: init={:?}", init);
444                     // We're only interested in statements that initialized a value, not the
445                     // initializations from arguments.
446                     let loc = match init.location {
447                         InitLocation::Statement(stmt) => stmt,
448                         _ => continue,
449                     };
450
451                     let bbd = &self.body[loc.block];
452                     let is_terminator = bbd.statements.len() == loc.statement_index;
453                     debug!(
454                         "borrowed_content_source: loc={:?} is_terminator={:?}",
455                         loc, is_terminator,
456                     );
457                     if !is_terminator {
458                         continue;
459                     } else if let Some(Terminator {
460                         kind: TerminatorKind::Call { ref func, from_hir_call: false, .. },
461                         ..
462                     }) = bbd.terminator
463                     {
464                         if let Some(source) =
465                             BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
466                         {
467                             return source;
468                         }
469                     }
470                 }
471             }
472             // Base is a `static` so won't be from an overloaded operator
473             _ => (),
474         };
475
476         // If we didn't find an overloaded deref or index, then assume it's a
477         // built in deref and check the type of the base.
478         let base_ty = deref_base.ty(self.body, tcx).ty;
479         if base_ty.is_unsafe_ptr() {
480             BorrowedContentSource::DerefRawPointer
481         } else if base_ty.is_mutable_ptr() {
482             BorrowedContentSource::DerefMutableRef
483         } else {
484             BorrowedContentSource::DerefSharedRef
485         }
486     }
487 }
488
489 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
490     /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
491     /// name where required.
492     pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
493         let mut s = String::new();
494         let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
495
496         // We need to add synthesized lifetimes where appropriate. We do
497         // this by hooking into the pretty printer and telling it to label the
498         // lifetimes without names with the value `'0`.
499         match ty.kind() {
500             ty::Ref(
501                 ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
502                 | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
503                 _,
504                 _,
505             ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter),
506             _ => {}
507         }
508
509         let _ = ty.print(printer);
510         s
511     }
512
513     /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
514     /// synthesized lifetime name where required.
515     pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
516         let mut s = String::new();
517         let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
518
519         let region = match ty.kind() {
520             ty::Ref(region, _, _) => {
521                 match region {
522                     ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
523                     | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
524                         printer.region_highlight_mode.highlighting_bound_region(*br, counter)
525                     }
526                     _ => {}
527                 }
528
529                 region
530             }
531             _ => bug!("ty for annotation of borrow region is not a reference"),
532         };
533
534         let _ = region.print(printer);
535         s
536     }
537 }
538
539 /// The span(s) associated to a use of a place.
540 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
541 pub(super) enum UseSpans<'tcx> {
542     /// The access is caused by capturing a variable for a closure.
543     ClosureUse {
544         /// This is true if the captured variable was from a generator.
545         generator_kind: Option<GeneratorKind>,
546         /// The span of the args of the closure, including the `move` keyword if
547         /// it's present.
548         args_span: Span,
549         /// The span of the use resulting in capture kind
550         /// Check `ty::CaptureInfo` for more details
551         capture_kind_span: Span,
552         /// The span of the use resulting in the captured path
553         /// Check `ty::CaptureInfo` for more details
554         path_span: Span,
555     },
556     /// The access is caused by using a variable as the receiver of a method
557     /// that takes 'self'
558     FnSelfUse {
559         /// The span of the variable being moved
560         var_span: Span,
561         /// The span of the method call on the variable
562         fn_call_span: Span,
563         /// The definition span of the method being called
564         fn_span: Span,
565         kind: FnSelfUseKind<'tcx>,
566     },
567     /// This access is caused by a `match` or `if let` pattern.
568     PatUse(Span),
569     /// This access has a single span associated to it: common case.
570     OtherUse(Span),
571 }
572
573 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
574 pub(super) enum FnSelfUseKind<'tcx> {
575     /// A normal method call of the form `receiver.foo(a, b, c)`
576     Normal {
577         self_arg: Ident,
578         implicit_into_iter: bool,
579         /// Whether the self type of the method call has an `.as_ref()` method.
580         /// Used for better diagnostics.
581         is_option_or_result: bool,
582     },
583     /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
584     FnOnceCall,
585     /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
586     Operator { self_arg: Ident },
587     DerefCoercion {
588         /// The `Span` of the `Target` associated type
589         /// in the `Deref` impl we are using.
590         deref_target: Span,
591         /// The type `T::Deref` we are dereferencing to
592         deref_target_ty: Ty<'tcx>,
593     },
594 }
595
596 impl UseSpans<'_> {
597     pub(super) fn args_or_use(self) -> Span {
598         match self {
599             UseSpans::ClosureUse { args_span: span, .. }
600             | UseSpans::PatUse(span)
601             | UseSpans::OtherUse(span) => span,
602             UseSpans::FnSelfUse {
603                 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
604             } => fn_call_span,
605             UseSpans::FnSelfUse { var_span, .. } => var_span,
606         }
607     }
608
609     /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span`
610     pub(super) fn var_or_use_path_span(self) -> Span {
611         match self {
612             UseSpans::ClosureUse { path_span: span, .. }
613             | UseSpans::PatUse(span)
614             | UseSpans::OtherUse(span) => span,
615             UseSpans::FnSelfUse {
616                 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
617             } => fn_call_span,
618             UseSpans::FnSelfUse { var_span, .. } => var_span,
619         }
620     }
621
622     /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span`
623     pub(super) fn var_or_use(self) -> Span {
624         match self {
625             UseSpans::ClosureUse { capture_kind_span: span, .. }
626             | UseSpans::PatUse(span)
627             | UseSpans::OtherUse(span) => span,
628             UseSpans::FnSelfUse {
629                 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
630             } => fn_call_span,
631             UseSpans::FnSelfUse { var_span, .. } => var_span,
632         }
633     }
634
635     pub(super) fn generator_kind(self) -> Option<GeneratorKind> {
636         match self {
637             UseSpans::ClosureUse { generator_kind, .. } => generator_kind,
638             _ => None,
639         }
640     }
641
642     // Add a span label to the arguments of the closure, if it exists.
643     pub(super) fn args_span_label(
644         self,
645         err: &mut DiagnosticBuilder<'_>,
646         message: impl Into<String>,
647     ) {
648         if let UseSpans::ClosureUse { args_span, .. } = self {
649             err.span_label(args_span, message);
650         }
651     }
652
653     // Add a span label to the use of the captured variable, if it exists.
654     // only adds label to the `path_span`
655     pub(super) fn var_span_label_path_only(
656         self,
657         err: &mut DiagnosticBuilder<'_>,
658         message: impl Into<String>,
659     ) {
660         if let UseSpans::ClosureUse { path_span, .. } = self {
661             err.span_label(path_span, message);
662         }
663     }
664
665     // Add a span label to the use of the captured variable, if it exists.
666     pub(super) fn var_span_label(
667         self,
668         err: &mut DiagnosticBuilder<'_>,
669         message: impl Into<String>,
670         kind_desc: impl Into<String>,
671     ) {
672         if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
673             if capture_kind_span == path_span {
674                 err.span_label(capture_kind_span, message);
675             } else {
676                 let capture_kind_label =
677                     format!("capture is {} because of use here", kind_desc.into());
678                 let path_label = message;
679                 err.span_label(capture_kind_span, capture_kind_label);
680                 err.span_label(path_span, path_label);
681             }
682         }
683     }
684
685     /// Returns `false` if this place is not used in a closure.
686     pub(super) fn for_closure(&self) -> bool {
687         match *self {
688             UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(),
689             _ => false,
690         }
691     }
692
693     /// Returns `false` if this place is not used in a generator.
694     pub(super) fn for_generator(&self) -> bool {
695         match *self {
696             UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(),
697             _ => false,
698         }
699     }
700
701     /// Describe the span associated with a use of a place.
702     pub(super) fn describe(&self) -> String {
703         match *self {
704             UseSpans::ClosureUse { generator_kind, .. } => {
705                 if generator_kind.is_some() {
706                     " in generator".to_string()
707                 } else {
708                     " in closure".to_string()
709                 }
710             }
711             _ => String::new(),
712         }
713     }
714
715     pub(super) fn or_else<F>(self, if_other: F) -> Self
716     where
717         F: FnOnce() -> Self,
718     {
719         match self {
720             closure @ UseSpans::ClosureUse { .. } => closure,
721             UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
722             fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
723         }
724     }
725 }
726
727 pub(super) enum BorrowedContentSource<'tcx> {
728     DerefRawPointer,
729     DerefMutableRef,
730     DerefSharedRef,
731     OverloadedDeref(Ty<'tcx>),
732     OverloadedIndex(Ty<'tcx>),
733 }
734
735 impl BorrowedContentSource<'tcx> {
736     pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
737         match *self {
738             BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
739             BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
740             BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
741             BorrowedContentSource::OverloadedDeref(ty) => ty
742                 .ty_adt_def()
743                 .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
744                     name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
745                     _ => None,
746                 })
747                 .unwrap_or_else(|| format!("dereference of `{}`", ty)),
748             BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
749         }
750     }
751
752     pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
753         match *self {
754             BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
755             BorrowedContentSource::DerefSharedRef => Some("shared reference"),
756             BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
757             // Overloaded deref and index operators should be evaluated into a
758             // temporary. So we don't need a description here.
759             BorrowedContentSource::OverloadedDeref(_)
760             | BorrowedContentSource::OverloadedIndex(_) => None,
761         }
762     }
763
764     pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
765         match *self {
766             BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(),
767             BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(),
768             BorrowedContentSource::DerefMutableRef => {
769                 bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
770             }
771             BorrowedContentSource::OverloadedDeref(ty) => ty
772                 .ty_adt_def()
773                 .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
774                     name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
775                     _ => None,
776                 })
777                 .unwrap_or_else(|| format!("dereference of `{}`", ty)),
778             BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
779         }
780     }
781
782     fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
783         match *func.kind() {
784             ty::FnDef(def_id, substs) => {
785                 let trait_id = tcx.trait_of_item(def_id)?;
786
787                 let lang_items = tcx.lang_items();
788                 if Some(trait_id) == lang_items.deref_trait()
789                     || Some(trait_id) == lang_items.deref_mut_trait()
790                 {
791                     Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0)))
792                 } else if Some(trait_id) == lang_items.index_trait()
793                     || Some(trait_id) == lang_items.index_mut_trait()
794                 {
795                     Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0)))
796                 } else {
797                     None
798                 }
799             }
800             _ => None,
801         }
802     }
803 }
804
805 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
806     /// Finds the spans associated to a move or copy of move_place at location.
807     pub(super) fn move_spans(
808         &self,
809         moved_place: PlaceRef<'tcx>, // Could also be an upvar.
810         location: Location,
811     ) -> UseSpans<'tcx> {
812         use self::UseSpans::*;
813
814         let stmt = match self.body[location.block].statements.get(location.statement_index) {
815             Some(stmt) => stmt,
816             None => return OtherUse(self.body.source_info(location).span),
817         };
818
819         debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
820         if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind {
821             match kind {
822                 box AggregateKind::Closure(def_id, _)
823                 | box AggregateKind::Generator(def_id, _, _) => {
824                     debug!("move_spans: def_id={:?} places={:?}", def_id, places);
825                     if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
826                         self.closure_span(*def_id, moved_place, places)
827                     {
828                         return ClosureUse {
829                             generator_kind,
830                             args_span,
831                             capture_kind_span,
832                             path_span,
833                         };
834                     }
835                 }
836                 _ => {}
837             }
838         }
839
840         // StatementKind::FakeRead only contains a def_id if they are introduced as a result
841         // of pattern matching within a closure.
842         if let StatementKind::FakeRead(box (cause, ref place)) = stmt.kind {
843             match cause {
844                 FakeReadCause::ForMatchedPlace(Some(closure_def_id))
845                 | FakeReadCause::ForLet(Some(closure_def_id)) => {
846                     debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
847                     let places = &[Operand::Move(*place)];
848                     if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
849                         self.closure_span(closure_def_id, moved_place, places)
850                     {
851                         return ClosureUse {
852                             generator_kind,
853                             args_span,
854                             capture_kind_span,
855                             path_span,
856                         };
857                     }
858                 }
859                 _ => {}
860             }
861         }
862
863         let normal_ret =
864             if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
865                 PatUse(stmt.source_info.span)
866             } else {
867                 OtherUse(stmt.source_info.span)
868             };
869
870         // We are trying to find MIR of the form:
871         // ```
872         // _temp = _moved_val;
873         // ...
874         // FnSelfCall(_temp, ...)
875         // ```
876         //
877         // where `_moved_val` is the place we generated the move error for,
878         // `_temp` is some other local, and `FnSelfCall` is a function
879         // that has a `self` parameter.
880
881         let target_temp = match stmt.kind {
882             StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
883                 temp.as_local().unwrap()
884             }
885             _ => return normal_ret,
886         };
887
888         debug!("move_spans: target_temp = {:?}", target_temp);
889
890         if let Some(Terminator {
891             kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
892         }) = &self.body[location.block].terminator
893         {
894             let (method_did, method_substs) = if let Some(info) =
895                 rustc_const_eval::util::find_self_call(
896                     self.infcx.tcx,
897                     &self.body,
898                     target_temp,
899                     location.block,
900                 ) {
901                 info
902             } else {
903                 return normal_ret;
904             };
905
906             let tcx = self.infcx.tcx;
907             let parent = tcx.parent(method_did);
908             let is_fn_once = parent == tcx.lang_items().fn_once_trait();
909             let is_operator = !from_hir_call
910                 && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
911             let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
912             let fn_call_span = *fn_span;
913
914             let self_arg = tcx.fn_arg_names(method_did)[0];
915
916             debug!(
917                 "terminator = {:?} from_hir_call={:?}",
918                 self.body[location.block].terminator, from_hir_call
919             );
920
921             // Check for a 'special' use of 'self' -
922             // an FnOnce call, an operator (e.g. `<<`), or a
923             // deref coercion.
924             let kind = if is_fn_once {
925                 Some(FnSelfUseKind::FnOnceCall)
926             } else if is_operator {
927                 Some(FnSelfUseKind::Operator { self_arg })
928             } else if is_deref {
929                 let deref_target =
930                     tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
931                         Instance::resolve(tcx, self.param_env, deref_target, method_substs)
932                             .transpose()
933                     });
934                 if let Some(Ok(instance)) = deref_target {
935                     let deref_target_ty = instance.ty(tcx, self.param_env);
936                     Some(FnSelfUseKind::DerefCoercion {
937                         deref_target: tcx.def_span(instance.def_id()),
938                         deref_target_ty,
939                     })
940                 } else {
941                     None
942                 }
943             } else {
944                 None
945             };
946
947             let kind = kind.unwrap_or_else(|| {
948                 // This isn't a 'special' use of `self`
949                 debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
950                 let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
951                     && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
952                 let parent_self_ty = parent
953                     .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
954                     .and_then(|did| match tcx.type_of(did).kind() {
955                         ty::Adt(def, ..) => Some(def.did),
956                         _ => None,
957                     });
958                 let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
959                     matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
960                 });
961                 FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
962             });
963
964             return FnSelfUse {
965                 var_span: stmt.source_info.span,
966                 fn_call_span,
967                 fn_span: self
968                     .infcx
969                     .tcx
970                     .sess
971                     .source_map()
972                     .guess_head_span(self.infcx.tcx.def_span(method_did)),
973                 kind,
974             };
975         }
976         normal_ret
977     }
978
979     /// Finds the span of arguments of a closure (within `maybe_closure_span`)
980     /// and its usage of the local assigned at `location`.
981     /// This is done by searching in statements succeeding `location`
982     /// and originating from `maybe_closure_span`.
983     pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
984         use self::UseSpans::*;
985         debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
986
987         let target = match self.body[location.block].statements.get(location.statement_index) {
988             Some(&Statement { kind: StatementKind::Assign(box (ref place, _)), .. }) => {
989                 if let Some(local) = place.as_local() {
990                     local
991                 } else {
992                     return OtherUse(use_span);
993                 }
994             }
995             _ => return OtherUse(use_span),
996         };
997
998         if self.body.local_kind(target) != LocalKind::Temp {
999             // operands are always temporaries.
1000             return OtherUse(use_span);
1001         }
1002
1003         for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
1004             if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) =
1005                 stmt.kind
1006             {
1007                 let (def_id, is_generator) = match kind {
1008                     box AggregateKind::Closure(def_id, _) => (def_id, false),
1009                     box AggregateKind::Generator(def_id, _, _) => (def_id, true),
1010                     _ => continue,
1011                 };
1012
1013                 debug!(
1014                     "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
1015                     def_id, is_generator, places
1016                 );
1017                 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
1018                     self.closure_span(*def_id, Place::from(target).as_ref(), places)
1019                 {
1020                     return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
1021                 } else {
1022                     return OtherUse(use_span);
1023                 }
1024             }
1025
1026             if use_span != stmt.source_info.span {
1027                 break;
1028             }
1029         }
1030
1031         OtherUse(use_span)
1032     }
1033
1034     /// Finds the spans of a captured place within a closure or generator.
1035     /// The first span is the location of the use resulting in the capture kind of the capture
1036     /// The second span is the location the use resulting in the captured path of the capture
1037     fn closure_span(
1038         &self,
1039         def_id: DefId,
1040         target_place: PlaceRef<'tcx>,
1041         places: &[Operand<'tcx>],
1042     ) -> Option<(Span, Option<GeneratorKind>, Span, Span)> {
1043         debug!(
1044             "closure_span: def_id={:?} target_place={:?} places={:?}",
1045             def_id, target_place, places
1046         );
1047         let local_did = def_id.as_local()?;
1048         let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did);
1049         let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
1050         debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
1051         if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
1052             for (captured_place, place) in self
1053                 .infcx
1054                 .tcx
1055                 .typeck(def_id.expect_local())
1056                 .closure_min_captures_flattened(def_id)
1057                 .zip(places)
1058             {
1059                 match place {
1060                     Operand::Copy(place) | Operand::Move(place)
1061                         if target_place == place.as_ref() =>
1062                     {
1063                         debug!("closure_span: found captured local {:?}", place);
1064                         let body = self.infcx.tcx.hir().body(*body_id);
1065                         let generator_kind = body.generator_kind();
1066
1067                         return Some((
1068                             *args_span,
1069                             generator_kind,
1070                             captured_place.get_capture_kind_span(self.infcx.tcx),
1071                             captured_place.get_path_span(self.infcx.tcx),
1072                         ));
1073                     }
1074                     _ => {}
1075                 }
1076             }
1077         }
1078         None
1079     }
1080
1081     /// Helper to retrieve span(s) of given borrow from the current MIR
1082     /// representation
1083     pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
1084         let span = self.body.source_info(borrow.reserve_location).span;
1085         self.borrow_spans(span, borrow.reserve_location)
1086     }
1087 }