]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/diagnostics/mod.rs
New upstream version 1.58.1+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / diagnostics / mod.rs
CommitLineData
60c5eb7d
XL
1//! Borrow checker diagnostics.
2
dc9dc135 3use rustc_errors::DiagnosticBuilder;
dfeec247
XL
4use rustc_hir as hir;
5use rustc_hir::def::Namespace;
6use rustc_hir::def_id::DefId;
f035d41b 7use rustc_hir::lang_items::LangItemGroup;
dfeec247 8use rustc_hir::GeneratorKind;
ba9703b0 9use rustc_middle::mir::{
cdc7bbd5
XL
10 AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
11 Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
ba9703b0
XL
12};
13use rustc_middle::ty::print::Print;
1b1a35ee 14use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
c295e0f8 15use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
3c0e092e 16use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
ba9703b0 17use rustc_target::abi::VariantIdx;
ff7c6d11 18
94b46f34 19use super::borrow_set::BorrowData;
e74abb32 20use super::MirBorrowckCtxt;
ff7c6d11 21
60c5eb7d 22mod find_use;
60c5eb7d 23mod outlives_suggestion;
dfeec247
XL
24mod region_name;
25mod var_name;
60c5eb7d 26
94222f64 27mod bound_region_errors;
60c5eb7d 28mod conflict_errors;
dfeec247 29mod explain_borrow;
60c5eb7d
XL
30mod move_errors;
31mod mutability_errors;
32mod region_errors;
60c5eb7d 33
94222f64 34crate use bound_region_errors::{ToUniverseInfo, UniverseInfo};
60c5eb7d 35crate use mutability_errors::AccessKind;
60c5eb7d 36crate use outlives_suggestion::OutlivesSuggestionBuilder;
dfeec247
XL
37crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
38crate use region_name::{RegionName, RegionNameSource};
f035d41b 39use rustc_span::symbol::Ident;
60c5eb7d 40
dc9dc135 41pub(super) struct IncludingDowncast(pub(super) bool);
0bf4aa26 42
dc9dc135 43impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
0731742a
XL
44 /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
45 /// is moved after being invoked.
0bf4aa26
XL
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 /// ```
0731742a 55 pub(super) fn add_moved_or_invoked_closure_note(
0bf4aa26
XL
56 &self,
57 location: Location,
74b04a01 58 place: PlaceRef<'tcx>,
0bf4aa26
XL
59 diag: &mut DiagnosticBuilder<'_>,
60 ) {
0731742a 61 debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
dc9dc135
XL
62 let mut target = place.local_or_deref_local();
63 for stmt in &self.body[location.block].statements[location.statement_index..] {
0731742a 64 debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
dfeec247 65 if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind {
0731742a 66 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
0bf4aa26 67 match from {
dfeec247
XL
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 _ => {}
0bf4aa26
XL
74 }
75 }
76 }
77
0731742a 78 // Check if we are attempting to call a closure after it has been invoked.
dc9dc135 79 let terminator = self.body[location.block].terminator();
0731742a 80 debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
0bf4aa26 81 if let TerminatorKind::Call {
6a06907d 82 func: Operand::Constant(box Constant { literal, .. }),
0bf4aa26
XL
83 args,
84 ..
dfeec247
XL
85 } = &terminator.kind
86 {
6a06907d 87 if let ty::FnDef(id, _) = *literal.ty().kind() {
1b1a35ee
XL
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 };
0bf4aa26 98
1b1a35ee
XL
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);
0bf4aa26 103
5869c6ff 104 if let Some((span, hir_place)) =
1b1a35ee
XL
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",
5869c6ff 112 ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
1b1a35ee
XL
113 ),
114 );
115 return;
116 }
0bf4aa26
XL
117 }
118 }
119 }
120 }
0731742a
XL
121
122 // Check if we are just moving a closure after it has been invoked.
123 if let Some(target) = target {
1b1a35ee 124 if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
f9f354fc 125 let did = did.expect_local();
3dfed10e 126 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
0731742a 127
5869c6ff 128 if let Some((span, hir_place)) =
3dfed10e 129 self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
0731742a
XL
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",
5869c6ff 136 ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
0731742a
XL
137 ),
138 );
139 }
140 }
141 }
0bf4aa26
XL
142 }
143
ba9703b0
XL
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);
1b1a35ee
XL
151 descr.insert(0, '`');
152 descr.push('`');
ba9703b0
XL
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.
74b04a01 161 pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
416331ca 162 self.describe_place_with_options(place_ref, IncludingDowncast(false))
8faf50e0
XL
163 }
164
0bf4aa26
XL
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
8faf50e0
XL
169 pub(super) fn describe_place_with_options(
170 &self,
74b04a01 171 place: PlaceRef<'tcx>,
8faf50e0
XL
172 including_downcast: IncludingDowncast,
173 ) -> Option<String> {
ff7c6d11 174 let mut buf = String::new();
8faf50e0 175 match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
ff7c6d11
XL
176 Ok(()) => Some(buf),
177 Err(()) => None,
178 }
179 }
180
0bf4aa26 181 /// Appends end-user visible description of `place` to `buf`.
ff7c6d11
XL
182 fn append_place_to_string(
183 &self,
74b04a01 184 place: PlaceRef<'tcx>,
ff7c6d11
XL
185 buf: &mut String,
186 mut autoderef: bool,
8faf50e0 187 including_downcast: &IncludingDowncast,
ff7c6d11 188 ) -> Result<(), ()> {
416331ca 189 match place {
dfeec247 190 PlaceRef { local, projection: [] } => {
74b04a01 191 self.append_local_to_string(local, buf)?;
ff7c6d11 192 }
dfeec247 193 PlaceRef { local, projection: [ProjectionElem::Deref] }
74b04a01 194 if self.body.local_decls[local].is_ref_for_guard() =>
dfeec247 195 {
60c5eb7d 196 self.append_place_to_string(
74b04a01 197 PlaceRef { local, projection: &[] },
60c5eb7d
XL
198 buf,
199 autoderef,
200 &including_downcast,
201 )?;
dfeec247
XL
202 }
203 PlaceRef { local, projection: [ProjectionElem::Deref] }
74b04a01 204 if self.body.local_decls[local].is_ref_to_static() =>
dfeec247 205 {
74b04a01 206 let local_info = &self.body.local_decls[local].local_info;
f9f354fc 207 if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
60c5eb7d
XL
208 buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
209 } else {
210 unreachable!();
211 }
dfeec247
XL
212 }
213 PlaceRef { local, projection: [proj_base @ .., elem] } => {
e1599b0c 214 match elem {
ff7c6d11 215 ProjectionElem::Deref => {
dfeec247 216 let upvar_field_projection = self.is_upvar_field_projection(place);
8faf50e0 217 if let Some(field) = upvar_field_projection {
ff7c6d11 218 let var_index = field.index();
17df50a5 219 let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
48663c56 220 if self.upvars[var_index].by_ref {
ff7c6d11
XL
221 buf.push_str(&name);
222 } else {
1b1a35ee
XL
223 buf.push('*');
224 buf.push_str(&name);
ff7c6d11
XL
225 }
226 } else {
227 if autoderef {
416331ca 228 // FIXME turn this recursion into iteration
8faf50e0 229 self.append_place_to_string(
dfeec247 230 PlaceRef { local, projection: proj_base },
8faf50e0
XL
231 buf,
232 autoderef,
233 &including_downcast,
234 )?;
ff7c6d11 235 } else {
1b1a35ee 236 buf.push('*');
dfeec247
XL
237 self.append_place_to_string(
238 PlaceRef { local, projection: proj_base },
239 buf,
240 autoderef,
241 &including_downcast,
242 )?;
ff7c6d11
XL
243 }
244 }
245 }
246 ProjectionElem::Downcast(..) => {
8faf50e0 247 self.append_place_to_string(
dfeec247 248 PlaceRef { local, projection: proj_base },
8faf50e0
XL
249 buf,
250 autoderef,
251 &including_downcast,
252 )?;
253 if including_downcast.0 {
254 return Err(());
255 }
ff7c6d11
XL
256 }
257 ProjectionElem::Field(field, _ty) => {
258 autoderef = true;
259
5869c6ff 260 // FIXME(project-rfc_2229#36): print capture precisely here.
dfeec247 261 let upvar_field_projection = self.is_upvar_field_projection(place);
8faf50e0 262 if let Some(field) = upvar_field_projection {
ff7c6d11 263 let var_index = field.index();
17df50a5 264 let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
ff7c6d11
XL
265 buf.push_str(&name);
266 } else {
dfeec247
XL
267 let field_name = self
268 .describe_field(PlaceRef { local, projection: proj_base }, *field);
8faf50e0 269 self.append_place_to_string(
dfeec247 270 PlaceRef { local, projection: proj_base },
8faf50e0
XL
271 buf,
272 autoderef,
273 &including_downcast,
274 )?;
1b1a35ee
XL
275 buf.push('.');
276 buf.push_str(&field_name);
ff7c6d11
XL
277 }
278 }
279 ProjectionElem::Index(index) => {
280 autoderef = true;
281
8faf50e0 282 self.append_place_to_string(
dfeec247 283 PlaceRef { local, projection: proj_base },
8faf50e0
XL
284 buf,
285 autoderef,
286 &including_downcast,
287 )?;
1b1a35ee 288 buf.push('[');
e1599b0c 289 if self.append_local_to_string(*index, buf).is_err() {
1b1a35ee 290 buf.push('_');
ff7c6d11 291 }
1b1a35ee 292 buf.push(']');
ff7c6d11
XL
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
8faf50e0 299 self.append_place_to_string(
dfeec247 300 PlaceRef { local, projection: proj_base },
8faf50e0
XL
301 buf,
302 autoderef,
303 &including_downcast,
304 )?;
1b1a35ee 305 buf.push_str("[..]");
ff7c6d11
XL
306 }
307 };
308 }
309 }
310
311 Ok(())
312 }
313
0bf4aa26 314 /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
dc9dc135 315 /// a name, or its name was generated by the compiler, then `Err` is returned
60c5eb7d
XL
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() => {
e1599b0c 320 buf.push_str(&name.as_str());
ff7c6d11
XL
321 Ok(())
322 }
dc9dc135 323 _ => Err(()),
ff7c6d11
XL
324 }
325 }
326
0bf4aa26 327 /// End-user visible description of the `field`nth field of `base`
74b04a01 328 fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
416331ca
XL
329 // FIXME Place2 Make this work iteratively
330 match place {
dfeec247 331 PlaceRef { local, projection: [] } => {
74b04a01 332 let local = &self.body.local_decls[local];
532ac7d7 333 self.describe_field_from_ty(&local.ty, field, None)
ff7c6d11 334 }
dfeec247 335 PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
e1599b0c 336 ProjectionElem::Deref => {
dfeec247 337 self.describe_field(PlaceRef { local, projection: proj_base }, field)
e1599b0c 338 }
532ac7d7 339 ProjectionElem::Downcast(_, variant_index) => {
5869c6ff 340 let base_ty = place.ty(self.body, self.infcx.tcx).ty;
e1599b0c 341 self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
532ac7d7 342 }
ff7c6d11 343 ProjectionElem::Field(_, field_type) => {
532ac7d7 344 self.describe_field_from_ty(&field_type, field, None)
ff7c6d11 345 }
0531ce1d
XL
346 ProjectionElem::Index(..)
347 | ProjectionElem::ConstantIndex { .. }
348 | ProjectionElem::Subslice { .. } => {
dfeec247 349 self.describe_field(PlaceRef { local, projection: proj_base }, field)
ff7c6d11
XL
350 }
351 },
352 }
353 }
354
0bf4aa26 355 /// End-user visible description of the `field_index`nth field of `ty`
532ac7d7
XL
356 fn describe_field_from_ty(
357 &self,
48663c56 358 ty: Ty<'_>,
532ac7d7 359 field: Field,
dfeec247 360 variant_index: Option<VariantIdx>,
532ac7d7 361 ) -> String {
ff7c6d11
XL
362 if ty.is_box() {
363 // If the type is a box, the field is described from the boxed type
532ac7d7 364 self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index)
ff7c6d11 365 } else {
1b1a35ee 366 match *ty.kind() {
532ac7d7
XL
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 };
dfeec247
XL
374 variant.fields[field.index()].ident.to_string()
375 }
b7449926
XL
376 ty::Tuple(_) => field.index().to_string(),
377 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
532ac7d7 378 self.describe_field_from_ty(&ty, field, variant_index)
ff7c6d11 379 }
dfeec247
XL
380 ty::Array(ty, _) | ty::Slice(ty) => {
381 self.describe_field_from_ty(&ty, field, variant_index)
382 }
b7449926 383 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
fc512014
XL
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.
6a06907d
XL
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();
ff7c6d11 396
dc9dc135 397 self.infcx.tcx.hir().name(var_id).to_string()
ff7c6d11
XL
398 }
399 _ => {
400 // Might need a revision when the fields in trait RFC is implemented
401 // (https://github.com/rust-lang/rfcs/pull/1546)
dfeec247 402 bug!("End-user description not implemented for field access on `{:?}`", ty);
ff7c6d11
XL
403 }
404 }
405 }
406 }
407
dc9dc135
XL
408 /// Add a note that a type does not implement `Copy`
409 pub(super) fn note_type_does_not_implement_copy(
0bf4aa26 410 &self,
dc9dc135
XL
411 err: &mut DiagnosticBuilder<'a>,
412 place_desc: &str,
413 ty: Ty<'tcx>,
414 span: Option<Span>,
1b1a35ee 415 move_prefix: &str,
dc9dc135
XL
416 ) {
417 let message = format!(
1b1a35ee
XL
418 "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait",
419 move_prefix, place_desc, ty,
0bf4aa26 420 );
dc9dc135
XL
421 if let Some(span) = span {
422 err.span_label(span, message);
423 } else {
424 err.note(&message);
0bf4aa26
XL
425 }
426 }
416331ca
XL
427
428 pub(super) fn borrowed_content_source(
429 &self,
74b04a01 430 deref_base: PlaceRef<'tcx>,
416331ca
XL
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={:?}",
dfeec247 455 loc, is_terminator,
416331ca
XL
456 );
457 if !is_terminator {
458 continue;
459 } else if let Some(Terminator {
dfeec247 460 kind: TerminatorKind::Call { ref func, from_hir_call: false, .. },
416331ca 461 ..
dfeec247
XL
462 }) = bbd.terminator
463 {
464 if let Some(source) =
f9f354fc 465 BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
dfeec247 466 {
416331ca
XL
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.
5869c6ff 478 let base_ty = deref_base.ty(self.body, tcx).ty;
416331ca
XL
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 }
532ac7d7 487}
0bf4aa26 488
dc9dc135 489impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
0bf4aa26
XL
490 /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
491 /// name where required.
dc9dc135 492 pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
532ac7d7
XL
493 let mut s = String::new();
494 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
495
0bf4aa26
XL
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`.
1b1a35ee 499 match ty.kind() {
ba9703b0 500 ty::Ref(
cdc7bbd5 501 ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
ba9703b0 502 | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
0bf4aa26
XL
503 _,
504 _,
532ac7d7
XL
505 ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter),
506 _ => {}
0bf4aa26 507 }
532ac7d7
XL
508
509 let _ = ty.print(printer);
510 s
0bf4aa26
XL
511 }
512
9fa01778 513 /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
0bf4aa26 514 /// synthesized lifetime name where required.
dc9dc135 515 pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
532ac7d7
XL
516 let mut s = String::new();
517 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
518
1b1a35ee 519 let region = match ty.kind() {
532ac7d7
XL
520 ty::Ref(region, _, _) => {
521 match region {
cdc7bbd5 522 ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
532ac7d7
XL
523 | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
524 printer.region_highlight_mode.highlighting_bound_region(*br, counter)
525 }
526 _ => {}
0bf4aa26 527 }
532ac7d7
XL
528
529 region
530 }
0bf4aa26 531 _ => bug!("ty for annotation of borrow region is not a reference"),
532ac7d7
XL
532 };
533
534 let _ = region.print(printer);
535 s
0bf4aa26 536 }
b7449926
XL
537}
538
f035d41b 539/// The span(s) associated to a use of a place.
b7449926 540#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1b1a35ee 541pub(super) enum UseSpans<'tcx> {
f035d41b 542 /// The access is caused by capturing a variable for a closure.
b7449926 543 ClosureUse {
f035d41b 544 /// This is true if the captured variable was from a generator.
e74abb32 545 generator_kind: Option<GeneratorKind>,
f035d41b
XL
546 /// The span of the args of the closure, including the `move` keyword if
547 /// it's present.
b7449926 548 args_span: Span,
17df50a5
XL
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,
f035d41b
XL
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
b7449926 560 var_span: Span,
f035d41b
XL
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,
1b1a35ee 565 kind: FnSelfUseKind<'tcx>,
b7449926 566 },
f035d41b
XL
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.
b7449926
XL
570 OtherUse(Span),
571}
572
f035d41b 573#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1b1a35ee 574pub(super) enum FnSelfUseKind<'tcx> {
f035d41b 575 /// A normal method call of the form `receiver.foo(a, b, c)`
cdc7bbd5
XL
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 },
f035d41b
XL
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 },
1b1a35ee
XL
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 },
f035d41b
XL
594}
595
1b1a35ee 596impl UseSpans<'_> {
b7449926
XL
597 pub(super) fn args_or_use(self) -> Span {
598 match self {
f035d41b
XL
599 UseSpans::ClosureUse { args_span: span, .. }
600 | UseSpans::PatUse(span)
f035d41b 601 | UseSpans::OtherUse(span) => span,
1b1a35ee
XL
602 UseSpans::FnSelfUse {
603 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
604 } => fn_call_span,
605 UseSpans::FnSelfUse { var_span, .. } => var_span,
b7449926
XL
606 }
607 }
608
17df50a5
XL
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`
b7449926
XL
623 pub(super) fn var_or_use(self) -> Span {
624 match self {
17df50a5 625 UseSpans::ClosureUse { capture_kind_span: span, .. }
f035d41b 626 | UseSpans::PatUse(span)
f035d41b 627 | UseSpans::OtherUse(span) => span,
1b1a35ee
XL
628 UseSpans::FnSelfUse {
629 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
630 } => fn_call_span,
631 UseSpans::FnSelfUse { var_span, .. } => var_span,
b7449926
XL
632 }
633 }
634
e74abb32
XL
635 pub(super) fn generator_kind(self) -> Option<GeneratorKind> {
636 match self {
637 UseSpans::ClosureUse { generator_kind, .. } => generator_kind,
638 _ => None,
639 }
640 }
641
b7449926 642 // Add a span label to the arguments of the closure, if it exists.
9fa01778
XL
643 pub(super) fn args_span_label(
644 self,
645 err: &mut DiagnosticBuilder<'_>,
646 message: impl Into<String>,
647 ) {
b7449926
XL
648 if let UseSpans::ClosureUse { args_span, .. } = self {
649 err.span_label(args_span, message);
650 }
651 }
652
17df50a5
XL
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
b7449926 665 // Add a span label to the use of the captured variable, if it exists.
9fa01778
XL
666 pub(super) fn var_span_label(
667 self,
668 err: &mut DiagnosticBuilder<'_>,
669 message: impl Into<String>,
17df50a5 670 kind_desc: impl Into<String>,
9fa01778 671 ) {
17df50a5
XL
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 }
b7449926
XL
682 }
683 }
684
9fa01778 685 /// Returns `false` if this place is not used in a closure.
dc9dc135 686 pub(super) fn for_closure(&self) -> bool {
0bf4aa26 687 match *self {
e74abb32 688 UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(),
0bf4aa26
XL
689 _ => false,
690 }
691 }
692
9fa01778 693 /// Returns `false` if this place is not used in a generator.
dc9dc135 694 pub(super) fn for_generator(&self) -> bool {
0bf4aa26 695 match *self {
e74abb32 696 UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(),
0bf4aa26
XL
697 _ => false,
698 }
699 }
700
701 /// Describe the span associated with a use of a place.
dc9dc135 702 pub(super) fn describe(&self) -> String {
0bf4aa26 703 match *self {
dfeec247
XL
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 }
1b1a35ee 711 _ => String::new(),
b7449926
XL
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,
f035d41b
XL
721 UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
722 fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
b7449926
XL
723 }
724 }
725}
726
416331ca
XL
727pub(super) enum BorrowedContentSource<'tcx> {
728 DerefRawPointer,
729 DerefMutableRef,
730 DerefSharedRef,
731 OverloadedDeref(Ty<'tcx>),
732 OverloadedIndex(Ty<'tcx>),
733}
734
735impl BorrowedContentSource<'tcx> {
ba9703b0 736 pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
416331ca 737 match *self {
74b04a01
XL
738 BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
739 BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
740 BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
1b1a35ee 741 BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
ba9703b0 742 ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
74b04a01 743 "an `Rc`".to_string()
ba9703b0
XL
744 }
745 ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
74b04a01 746 "an `Arc`".to_string()
416331ca 747 }
ba9703b0
XL
748 _ => format!("dereference of `{}`", ty),
749 },
416331ca
XL
750 BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
751 }
752 }
753
754 pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
755 match *self {
756 BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
757 BorrowedContentSource::DerefSharedRef => Some("shared reference"),
758 BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
759 // Overloaded deref and index operators should be evaluated into a
760 // temporary. So we don't need a description here.
761 BorrowedContentSource::OverloadedDeref(_)
dfeec247 762 | BorrowedContentSource::OverloadedIndex(_) => None,
416331ca
XL
763 }
764 }
765
ba9703b0 766 pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
416331ca 767 match *self {
74b04a01
XL
768 BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(),
769 BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(),
416331ca 770 BorrowedContentSource::DerefMutableRef => {
dfeec247
XL
771 bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
772 }
1b1a35ee 773 BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
ba9703b0 774 ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
74b04a01 775 "an `Rc`".to_string()
ba9703b0
XL
776 }
777 ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
74b04a01 778 "an `Arc`".to_string()
416331ca 779 }
ba9703b0
XL
780 _ => format!("a dereference of `{}`", ty),
781 },
416331ca
XL
782 BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
783 }
784 }
785
786 fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
1b1a35ee 787 match *func.kind() {
416331ca
XL
788 ty::FnDef(def_id, substs) => {
789 let trait_id = tcx.trait_of_item(def_id)?;
790
791 let lang_items = tcx.lang_items();
792 if Some(trait_id) == lang_items.deref_trait()
793 || Some(trait_id) == lang_items.deref_mut_trait()
794 {
795 Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0)))
796 } else if Some(trait_id) == lang_items.index_trait()
797 || Some(trait_id) == lang_items.index_mut_trait()
798 {
799 Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0)))
800 } else {
801 None
802 }
803 }
804 _ => None,
805 }
806 }
807}
808
dc9dc135 809impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
b7449926
XL
810 /// Finds the spans associated to a move or copy of move_place at location.
811 pub(super) fn move_spans(
812 &self,
74b04a01 813 moved_place: PlaceRef<'tcx>, // Could also be an upvar.
b7449926 814 location: Location,
1b1a35ee 815 ) -> UseSpans<'tcx> {
b7449926 816 use self::UseSpans::*;
b7449926 817
dc9dc135 818 let stmt = match self.body[location.block].statements.get(location.statement_index) {
b7449926 819 Some(stmt) => stmt,
dc9dc135 820 None => return OtherUse(self.body.source_info(location).span),
b7449926
XL
821 };
822
0bf4aa26 823 debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
dfeec247 824 if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind {
f035d41b 825 match kind {
e74abb32 826 box AggregateKind::Closure(def_id, _)
f035d41b
XL
827 | box AggregateKind::Generator(def_id, _, _) => {
828 debug!("move_spans: def_id={:?} places={:?}", def_id, places);
17df50a5 829 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
f035d41b
XL
830 self.closure_span(*def_id, moved_place, places)
831 {
17df50a5
XL
832 return ClosureUse {
833 generator_kind,
834 args_span,
835 capture_kind_span,
836 path_span,
837 };
f035d41b
XL
838 }
839 }
840 _ => {}
841 }
842 }
843
cdc7bbd5
XL
844 // StatementKind::FakeRead only contains a def_id if they are introduced as a result
845 // of pattern matching within a closure.
846 if let StatementKind::FakeRead(box (cause, ref place)) = stmt.kind {
847 match cause {
848 FakeReadCause::ForMatchedPlace(Some(closure_def_id))
849 | FakeReadCause::ForLet(Some(closure_def_id)) => {
850 debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
851 let places = &[Operand::Move(*place)];
17df50a5 852 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
cdc7bbd5
XL
853 self.closure_span(closure_def_id, moved_place, places)
854 {
17df50a5
XL
855 return ClosureUse {
856 generator_kind,
857 args_span,
858 capture_kind_span,
859 path_span,
860 };
cdc7bbd5
XL
861 }
862 }
863 _ => {}
864 }
865 }
866
f035d41b
XL
867 let normal_ret =
868 if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
869 PatUse(stmt.source_info.span)
870 } else {
871 OtherUse(stmt.source_info.span)
0bf4aa26
XL
872 };
873
f035d41b
XL
874 // We are trying to find MIR of the form:
875 // ```
876 // _temp = _moved_val;
877 // ...
878 // FnSelfCall(_temp, ...)
879 // ```
880 //
881 // where `_moved_val` is the place we generated the move error for,
882 // `_temp` is some other local, and `FnSelfCall` is a function
883 // that has a `self` parameter.
884
885 let target_temp = match stmt.kind {
886 StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
887 temp.as_local().unwrap()
b7449926 888 }
f035d41b
XL
889 _ => return normal_ret,
890 };
b7449926 891
f035d41b
XL
892 debug!("move_spans: target_temp = {:?}", target_temp);
893
894 if let Some(Terminator {
1b1a35ee 895 kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
f035d41b
XL
896 }) = &self.body[location.block].terminator
897 {
1b1a35ee 898 let (method_did, method_substs) = if let Some(info) =
c295e0f8
XL
899 rustc_const_eval::util::find_self_call(
900 self.infcx.tcx,
901 &self.body,
902 target_temp,
903 location.block,
904 ) {
1b1a35ee
XL
905 info
906 } else {
907 return normal_ret;
908 };
f035d41b
XL
909
910 let tcx = self.infcx.tcx;
1b1a35ee
XL
911 let parent = tcx.parent(method_did);
912 let is_fn_once = parent == tcx.lang_items().fn_once_trait();
913 let is_operator = !from_hir_call
914 && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
915 let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
916 let fn_call_span = *fn_span;
917
918 let self_arg = tcx.fn_arg_names(method_did)[0];
919
920 debug!(
921 "terminator = {:?} from_hir_call={:?}",
922 self.body[location.block].terminator, from_hir_call
923 );
924
925 // Check for a 'special' use of 'self' -
926 // an FnOnce call, an operator (e.g. `<<`), or a
927 // deref coercion.
928 let kind = if is_fn_once {
929 Some(FnSelfUseKind::FnOnceCall)
930 } else if is_operator {
931 Some(FnSelfUseKind::Operator { self_arg })
932 } else if is_deref {
933 let deref_target =
934 tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
935 Instance::resolve(tcx, self.param_env, deref_target, method_substs)
936 .transpose()
937 });
938 if let Some(Ok(instance)) = deref_target {
939 let deref_target_ty = instance.ty(tcx, self.param_env);
940 Some(FnSelfUseKind::DerefCoercion {
941 deref_target: tcx.def_span(instance.def_id()),
942 deref_target_ty,
943 })
944 } else {
945 None
f035d41b 946 }
1b1a35ee
XL
947 } else {
948 None
949 };
950
951 let kind = kind.unwrap_or_else(|| {
952 // This isn't a 'special' use of `self`
953 debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
3c0e092e
XL
954 let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
955 && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
cdc7bbd5
XL
956 let parent_self_ty = parent
957 .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
958 .and_then(|did| match tcx.type_of(did).kind() {
959 ty::Adt(def, ..) => Some(def.did),
960 _ => None,
961 });
962 let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
c295e0f8
XL
963 tcx.is_diagnostic_item(sym::Option, def_id)
964 || tcx.is_diagnostic_item(sym::Result, def_id)
cdc7bbd5
XL
965 });
966 FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
1b1a35ee
XL
967 });
968
969 return FnSelfUse {
970 var_span: stmt.source_info.span,
971 fn_call_span,
972 fn_span: self
973 .infcx
974 .tcx
975 .sess
976 .source_map()
977 .guess_head_span(self.infcx.tcx.def_span(method_did)),
978 kind,
979 };
f035d41b 980 }
3dfed10e 981 normal_ret
b7449926
XL
982 }
983
984 /// Finds the span of arguments of a closure (within `maybe_closure_span`)
985 /// and its usage of the local assigned at `location`.
986 /// This is done by searching in statements succeeding `location`
987 /// and originating from `maybe_closure_span`.
1b1a35ee 988 pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
b7449926 989 use self::UseSpans::*;
0bf4aa26 990 debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
b7449926 991
dfeec247
XL
992 let target = match self.body[location.block].statements.get(location.statement_index) {
993 Some(&Statement { kind: StatementKind::Assign(box (ref place, _)), .. }) => {
e74abb32
XL
994 if let Some(local) = place.as_local() {
995 local
996 } else {
997 return OtherUse(use_span);
998 }
999 }
b7449926
XL
1000 _ => return OtherUse(use_span),
1001 };
1002
dc9dc135 1003 if self.body.local_kind(target) != LocalKind::Temp {
b7449926
XL
1004 // operands are always temporaries.
1005 return OtherUse(use_span);
1006 }
1007
dc9dc135 1008 for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
dfeec247
XL
1009 if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) =
1010 stmt.kind
1011 {
0bf4aa26
XL
1012 let (def_id, is_generator) = match kind {
1013 box AggregateKind::Closure(def_id, _) => (def_id, false),
1014 box AggregateKind::Generator(def_id, _, _) => (def_id, true),
1015 _ => continue,
1016 };
b7449926 1017
0bf4aa26
XL
1018 debug!(
1019 "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
1020 def_id, is_generator, places
1021 );
17df50a5 1022 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
dfeec247
XL
1023 self.closure_span(*def_id, Place::from(target).as_ref(), places)
1024 {
17df50a5 1025 return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
0bf4aa26
XL
1026 } else {
1027 return OtherUse(use_span);
b7449926
XL
1028 }
1029 }
1030
1031 if use_span != stmt.source_info.span {
1032 break;
1033 }
1034 }
1035
1036 OtherUse(use_span)
1037 }
1038
17df50a5
XL
1039 /// Finds the spans of a captured place within a closure or generator.
1040 /// The first span is the location of the use resulting in the capture kind of the capture
1041 /// The second span is the location the use resulting in the captured path of the capture
0bf4aa26
XL
1042 fn closure_span(
1043 &self,
1044 def_id: DefId,
74b04a01 1045 target_place: PlaceRef<'tcx>,
5869c6ff 1046 places: &[Operand<'tcx>],
17df50a5 1047 ) -> Option<(Span, Option<GeneratorKind>, Span, Span)> {
0bf4aa26
XL
1048 debug!(
1049 "closure_span: def_id={:?} target_place={:?} places={:?}",
1050 def_id, target_place, places
1051 );
1b1a35ee
XL
1052 let local_did = def_id.as_local()?;
1053 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did);
e74abb32 1054 let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
532ac7d7 1055 debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
dfeec247 1056 if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
17df50a5
XL
1057 for (captured_place, place) in self
1058 .infcx
1059 .tcx
1060 .typeck(def_id.expect_local())
1061 .closure_min_captures_flattened(def_id)
1062 .zip(places)
1063 {
48663c56 1064 match place {
dfeec247
XL
1065 Operand::Copy(place) | Operand::Move(place)
1066 if target_place == place.as_ref() =>
1067 {
48663c56 1068 debug!("closure_span: found captured local {:?}", place);
e74abb32
XL
1069 let body = self.infcx.tcx.hir().body(*body_id);
1070 let generator_kind = body.generator_kind();
1b1a35ee 1071
17df50a5
XL
1072 return Some((
1073 *args_span,
1074 generator_kind,
1075 captured_place.get_capture_kind_span(self.infcx.tcx),
1076 captured_place.get_path_span(self.infcx.tcx),
1077 ));
dfeec247 1078 }
48663c56
XL
1079 _ => {}
1080 }
1081 }
0bf4aa26 1082 }
48663c56 1083 None
0bf4aa26
XL
1084 }
1085
b7449926
XL
1086 /// Helper to retrieve span(s) of given borrow from the current MIR
1087 /// representation
1b1a35ee 1088 pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
dc9dc135 1089 let span = self.body.source_info(borrow.reserve_location).span;
b7449926
XL
1090 self.borrow_spans(span, borrow.reserve_location)
1091 }
ff7c6d11 1092}