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