]>
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 | 9 | use 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 | }; |
13 | use rustc_middle::ty::print::Print; | |
1b1a35ee | 14 | use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; |
c295e0f8 | 15 | use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; |
3c0e092e | 16 | use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span}; |
ba9703b0 | 17 | use rustc_target::abi::VariantIdx; |
ff7c6d11 | 18 | |
94b46f34 | 19 | use super::borrow_set::BorrowData; |
e74abb32 | 20 | use super::MirBorrowckCtxt; |
ff7c6d11 | 21 | |
60c5eb7d | 22 | mod find_use; |
60c5eb7d | 23 | mod outlives_suggestion; |
dfeec247 XL |
24 | mod region_name; |
25 | mod var_name; | |
60c5eb7d | 26 | |
94222f64 | 27 | mod bound_region_errors; |
60c5eb7d | 28 | mod conflict_errors; |
dfeec247 | 29 | mod explain_borrow; |
60c5eb7d XL |
30 | mod move_errors; |
31 | mod mutability_errors; | |
32 | mod region_errors; | |
60c5eb7d | 33 | |
94222f64 | 34 | crate use bound_region_errors::{ToUniverseInfo, UniverseInfo}; |
60c5eb7d | 35 | crate use mutability_errors::AccessKind; |
60c5eb7d | 36 | crate use outlives_suggestion::OutlivesSuggestionBuilder; |
dfeec247 XL |
37 | crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; |
38 | crate use region_name::{RegionName, RegionNameSource}; | |
f035d41b | 39 | use rustc_span::symbol::Ident; |
60c5eb7d | 40 | |
dc9dc135 | 41 | pub(super) struct IncludingDowncast(pub(super) bool); |
0bf4aa26 | 42 | |
dc9dc135 | 43 | impl<'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 | 489 | impl<'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 | 541 | pub(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 | 574 | pub(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 | 596 | impl 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 |
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> { | |
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 | 809 | impl<'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 | } |