]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/check/upvar.rs
Auto merge of #80843 - Mark-Simulacrum:fmt-bump, r=petrochenkov
[rust.git] / compiler / rustc_typeck / src / check / upvar.rs
1 //! ### Inferring borrow kinds for upvars
2 //!
3 //! Whenever there is a closure expression, we need to determine how each
4 //! upvar is used. We do this by initially assigning each upvar an
5 //! immutable "borrow kind" (see `ty::BorrowKind` for details) and then
6 //! "escalating" the kind as needed. The borrow kind proceeds according to
7 //! the following lattice:
8 //!
9 //!     ty::ImmBorrow -> ty::UniqueImmBorrow -> ty::MutBorrow
10 //!
11 //! So, for example, if we see an assignment `x = 5` to an upvar `x`, we
12 //! will promote its borrow kind to mutable borrow. If we see an `&mut x`
13 //! we'll do the same. Naturally, this applies not just to the upvar, but
14 //! to everything owned by `x`, so the result is the same for something
15 //! like `x.f = 5` and so on (presuming `x` is not a borrowed pointer to a
16 //! struct). These adjustments are performed in
17 //! `adjust_upvar_borrow_kind()` (you can trace backwards through the code
18 //! from there).
19 //!
20 //! The fact that we are inferring borrow kinds as we go results in a
21 //! semi-hacky interaction with mem-categorization. In particular,
22 //! mem-categorization will query the current borrow kind as it
23 //! categorizes, and we'll return the *current* value, but this may get
24 //! adjusted later. Therefore, in this module, we generally ignore the
25 //! borrow kind (and derived mutabilities) that are returned from
26 //! mem-categorization, since they may be inaccurate. (Another option
27 //! would be to use a unification scheme, where instead of returning a
28 //! concrete borrow kind like `ty::ImmBorrow`, we return a
29 //! `ty::InferBorrow(upvar_id)` or something like that, but this would
30 //! then mean that all later passes would have to check for these figments
31 //! and report an error, and it just seems like more mess in the end.)
32
33 use super::writeback::Resolver;
34 use super::FnCtxt;
35
36 use crate::expr_use_visitor as euv;
37 use rustc_data_structures::fx::FxIndexMap;
38 use rustc_hir as hir;
39 use rustc_hir::def_id::DefId;
40 use rustc_hir::def_id::LocalDefId;
41 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
42 use rustc_infer::infer::UpvarRegion;
43 use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, ProjectionKind};
44 use rustc_middle::ty::fold::TypeFoldable;
45 use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults, UpvarSubsts};
46 use rustc_session::lint;
47 use rustc_span::sym;
48 use rustc_span::{MultiSpan, Span, Symbol};
49
50 /// Describe the relationship between the paths of two places
51 /// eg:
52 /// - `foo` is ancestor of `foo.bar.baz`
53 /// - `foo.bar.baz` is an descendant of `foo.bar`
54 /// - `foo.bar` and `foo.baz` are divergent
55 enum PlaceAncestryRelation {
56     Ancestor,
57     Descendant,
58     Divergent,
59 }
60
61 /// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo`
62 /// during capture analysis. Information in this map feeds into the minimum capture
63 /// analysis pass.
64 type InferredCaptureInformation<'tcx> = FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>;
65
66 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
67     pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) {
68         InferBorrowKindVisitor { fcx: self }.visit_body(body);
69
70         // it's our job to process these.
71         assert!(self.deferred_call_resolutions.borrow().is_empty());
72     }
73 }
74
75 struct InferBorrowKindVisitor<'a, 'tcx> {
76     fcx: &'a FnCtxt<'a, 'tcx>,
77 }
78
79 impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
80     type Map = intravisit::ErasedMap<'tcx>;
81
82     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
83         NestedVisitorMap::None
84     }
85
86     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
87         if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind {
88             let body = self.fcx.tcx.hir().body(body_id);
89             self.visit_body(body);
90             self.fcx.analyze_closure(expr.hir_id, expr.span, body, cc);
91         }
92
93         intravisit::walk_expr(self, expr);
94     }
95 }
96
97 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
98     /// Analysis starting point.
99     fn analyze_closure(
100         &self,
101         closure_hir_id: hir::HirId,
102         span: Span,
103         body: &'tcx hir::Body<'tcx>,
104         capture_clause: hir::CaptureBy,
105     ) {
106         debug!("analyze_closure(id={:?}, body.id={:?})", closure_hir_id, body.id());
107
108         // Extract the type of the closure.
109         let ty = self.node_ty(closure_hir_id);
110         let (closure_def_id, substs) = match *ty.kind() {
111             ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)),
112             ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)),
113             ty::Error(_) => {
114                 // #51714: skip analysis when we have already encountered type errors
115                 return;
116             }
117             _ => {
118                 span_bug!(
119                     span,
120                     "type of closure expr {:?} is not a closure {:?}",
121                     closure_hir_id,
122                     ty
123                 );
124             }
125         };
126
127         let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs {
128             self.closure_kind(closure_substs).is_none().then_some(closure_substs)
129         } else {
130             None
131         };
132
133         let local_def_id = closure_def_id.expect_local();
134
135         let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id());
136         assert_eq!(body_owner_def_id.to_def_id(), closure_def_id);
137         let mut delegate = InferBorrowKind {
138             fcx: self,
139             closure_def_id,
140             closure_span: span,
141             capture_clause,
142             current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
143             current_origin: None,
144             capture_information: Default::default(),
145         };
146         euv::ExprUseVisitor::new(
147             &mut delegate,
148             &self.infcx,
149             body_owner_def_id,
150             self.param_env,
151             &self.typeck_results.borrow(),
152         )
153         .consume_body(body);
154
155         debug!(
156             "For closure={:?}, capture_information={:#?}",
157             closure_def_id, delegate.capture_information
158         );
159         self.log_capture_analysis_first_pass(closure_def_id, &delegate.capture_information, span);
160
161         self.compute_min_captures(closure_def_id, delegate.capture_information);
162
163         let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
164         if should_do_migration_analysis(self.tcx, closure_hir_id) {
165             self.perform_2229_migration_anaysis(closure_def_id, capture_clause, span, body);
166         }
167
168         // We now fake capture information for all variables that are mentioned within the closure
169         // We do this after handling migrations so that min_captures computes before
170         if !self.tcx.features().capture_disjoint_fields {
171             let mut capture_information: InferredCaptureInformation<'tcx> = Default::default();
172
173             if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
174                 for var_hir_id in upvars.keys() {
175                     let place = self.place_for_root_variable(local_def_id, *var_hir_id);
176
177                     debug!("seed place {:?}", place);
178
179                     let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id);
180                     let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span);
181                     let fake_info = ty::CaptureInfo {
182                         capture_kind_expr_id: None,
183                         path_expr_id: None,
184                         capture_kind,
185                     };
186
187                     capture_information.insert(place, fake_info);
188                 }
189             }
190
191             // This will update the min captures based on this new fake information.
192             self.compute_min_captures(closure_def_id, capture_information);
193         }
194
195         if let Some(closure_substs) = infer_kind {
196             // Unify the (as yet unbound) type variable in the closure
197             // substs with the kind we inferred.
198             let inferred_kind = delegate.current_closure_kind;
199             let closure_kind_ty = closure_substs.as_closure().kind_ty();
200             self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty);
201
202             // If we have an origin, store it.
203             if let Some(origin) = delegate.current_origin.clone() {
204                 let origin = if self.tcx.features().capture_disjoint_fields {
205                     origin
206                 } else {
207                     // FIXME(project-rfc-2229#31): Once the changes to support reborrowing are
208                     //                             made, make sure we are selecting and restricting
209                     //                             the origin correctly.
210                     (origin.0, Place { projections: vec![], ..origin.1 })
211                 };
212
213                 self.typeck_results
214                     .borrow_mut()
215                     .closure_kind_origins_mut()
216                     .insert(closure_hir_id, origin);
217             }
218         }
219
220         self.log_closure_min_capture_info(closure_def_id, span);
221
222         self.min_captures_to_closure_captures_bridge(closure_def_id);
223
224         // Now that we've analyzed the closure, we know how each
225         // variable is borrowed, and we know what traits the closure
226         // implements (Fn vs FnMut etc). We now have some updates to do
227         // with that information.
228         //
229         // Note that no closure type C may have an upvar of type C
230         // (though it may reference itself via a trait object). This
231         // results from the desugaring of closures to a struct like
232         // `Foo<..., UV0...UVn>`. If one of those upvars referenced
233         // C, then the type would have infinite size (and the
234         // inference algorithm will reject it).
235
236         // Equate the type variables for the upvars with the actual types.
237         let final_upvar_tys = self.final_upvar_tys(closure_def_id);
238         debug!(
239             "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}",
240             closure_hir_id, substs, final_upvar_tys
241         );
242
243         // Build a tuple (U0..Un) of the final upvar types U0..Un
244         // and unify the upvar tupe type in the closure with it:
245         let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter());
246         self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
247
248         // If we are also inferred the closure kind here,
249         // process any deferred resolutions.
250         let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
251         for deferred_call_resolution in deferred_call_resolutions {
252             deferred_call_resolution.resolve(self);
253         }
254     }
255
256     // Returns a list of `Ty`s for each upvar.
257     fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> {
258         // Presently an unboxed closure type cannot "escape" out of a
259         // function, so we will only encounter ones that originated in the
260         // local crate or were inlined into it along with some function.
261         // This may change if abstract return types of some sort are
262         // implemented.
263         let tcx = self.tcx;
264
265         self.typeck_results
266             .borrow()
267             .closure_min_captures_flattened(closure_id)
268             .map(|captured_place| {
269                 let upvar_ty = captured_place.place.ty();
270                 let capture = captured_place.info.capture_kind;
271
272                 debug!(
273                     "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}",
274                     captured_place.place, upvar_ty, capture, captured_place.mutability,
275                 );
276
277                 match capture {
278                     ty::UpvarCapture::ByValue(_) => upvar_ty,
279                     ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref(
280                         borrow.region,
281                         ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() },
282                     ),
283                 }
284             })
285             .collect()
286     }
287
288     /// Bridge for closure analysis
289     /// ----------------------------
290     ///
291     /// For closure with DefId `c`, the bridge converts structures required for supporting RFC 2229,
292     /// to structures currently used in the compiler for handling closure captures.
293     ///
294     /// For example the following structure will be converted:
295     ///
296     /// closure_min_captures
297     /// foo -> [ {foo.x, ImmBorrow}, {foo.y, MutBorrow} ]
298     /// bar -> [ {bar.z, ByValue}, {bar.q, MutBorrow} ]
299     ///
300     /// to
301     ///
302     /// 1. closure_captures
303     /// foo -> UpvarId(foo, c), bar -> UpvarId(bar, c)
304     ///
305     /// 2. upvar_capture_map
306     /// UpvarId(foo,c) -> MutBorrow, UpvarId(bar, c) -> ByValue
307     fn min_captures_to_closure_captures_bridge(&self, closure_def_id: DefId) {
308         let mut closure_captures: FxIndexMap<hir::HirId, ty::UpvarId> = Default::default();
309         let mut upvar_capture_map = ty::UpvarCaptureMap::default();
310
311         if let Some(min_captures) =
312             self.typeck_results.borrow().closure_min_captures.get(&closure_def_id)
313         {
314             for (var_hir_id, min_list) in min_captures.iter() {
315                 for captured_place in min_list {
316                     let place = &captured_place.place;
317                     let capture_info = captured_place.info;
318
319                     let upvar_id = match place.base {
320                         PlaceBase::Upvar(upvar_id) => upvar_id,
321                         base => bug!("Expected upvar, found={:?}", base),
322                     };
323
324                     assert_eq!(upvar_id.var_path.hir_id, *var_hir_id);
325                     assert_eq!(upvar_id.closure_expr_id, closure_def_id.expect_local());
326
327                     closure_captures.insert(*var_hir_id, upvar_id);
328
329                     let new_capture_kind =
330                         if let Some(capture_kind) = upvar_capture_map.get(&upvar_id) {
331                             // upvar_capture_map only stores the UpvarCapture (CaptureKind),
332                             // so we create a fake capture info with no expression.
333                             let fake_capture_info = ty::CaptureInfo {
334                                 capture_kind_expr_id: None,
335                                 path_expr_id: None,
336                                 capture_kind: *capture_kind,
337                             };
338                             determine_capture_info(fake_capture_info, capture_info).capture_kind
339                         } else {
340                             capture_info.capture_kind
341                         };
342                     upvar_capture_map.insert(upvar_id, new_capture_kind);
343                 }
344             }
345         }
346         debug!("For closure_def_id={:?}, closure_captures={:#?}", closure_def_id, closure_captures);
347         debug!(
348             "For closure_def_id={:?}, upvar_capture_map={:#?}",
349             closure_def_id, upvar_capture_map
350         );
351
352         if !closure_captures.is_empty() {
353             self.typeck_results
354                 .borrow_mut()
355                 .closure_captures
356                 .insert(closure_def_id, closure_captures);
357
358             self.typeck_results.borrow_mut().upvar_capture_map.extend(upvar_capture_map);
359         }
360     }
361
362     /// Analyzes the information collected by `InferBorrowKind` to compute the min number of
363     /// Places (and corresponding capture kind) that we need to keep track of to support all
364     /// the required captured paths.
365     ///
366     ///
367     /// Note: If this function is called multiple times for the same closure, it will update
368     ///       the existing min_capture map that is stored in TypeckResults.
369     ///
370     /// Eg:
371     /// ```rust,no_run
372     /// struct Point { x: i32, y: i32 }
373     ///
374     /// let s: String;  // hir_id_s
375     /// let mut p: Point; // his_id_p
376     /// let c = || {
377     ///        println!("{}", s);  // L1
378     ///        p.x += 10;  // L2
379     ///        println!("{}" , p.y) // L3
380     ///        println!("{}", p) // L4
381     ///        drop(s);   // L5
382     /// };
383     /// ```
384     /// and let hir_id_L1..5 be the expressions pointing to use of a captured variable on
385     /// the lines L1..5 respectively.
386     ///
387     /// InferBorrowKind results in a structure like this:
388     ///
389     /// ```
390     /// {
391     ///       Place(base: hir_id_s, projections: [], ....) -> {
392     ///                                                            capture_kind_expr: hir_id_L5,
393     ///                                                            path_expr_id: hir_id_L5,
394     ///                                                            capture_kind: ByValue
395     ///                                                       },
396     ///       Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> {
397     ///                                                                     capture_kind_expr: hir_id_L2,
398     ///                                                                     path_expr_id: hir_id_L2,
399     ///                                                                     capture_kind: ByValue
400     ///                                                                 },
401     ///       Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> {
402     ///                                                                     capture_kind_expr: hir_id_L3,
403     ///                                                                     path_expr_id: hir_id_L3,
404     ///                                                                     capture_kind: ByValue
405     ///                                                                 },
406     ///       Place(base: hir_id_p, projections: [], ...) -> {
407     ///                                                          capture_kind_expr: hir_id_L4,
408     ///                                                          path_expr_id: hir_id_L4,
409     ///                                                          capture_kind: ByValue
410     ///                                                      },
411     /// ```
412     ///
413     /// After the min capture analysis, we get:
414     /// ```
415     /// {
416     ///       hir_id_s -> [
417     ///            Place(base: hir_id_s, projections: [], ....) -> {
418     ///                                                                capture_kind_expr: hir_id_L5,
419     ///                                                                path_expr_id: hir_id_L5,
420     ///                                                                capture_kind: ByValue
421     ///                                                            },
422     ///       ],
423     ///       hir_id_p -> [
424     ///            Place(base: hir_id_p, projections: [], ...) -> {
425     ///                                                               capture_kind_expr: hir_id_L2,
426     ///                                                               path_expr_id: hir_id_L4,
427     ///                                                               capture_kind: ByValue
428     ///                                                           },
429     ///       ],
430     /// ```
431     fn compute_min_captures(
432         &self,
433         closure_def_id: DefId,
434         capture_information: InferredCaptureInformation<'tcx>,
435     ) {
436         if capture_information.is_empty() {
437             return;
438         }
439
440         let mut typeck_results = self.typeck_results.borrow_mut();
441
442         let mut root_var_min_capture_list =
443             typeck_results.closure_min_captures.remove(&closure_def_id).unwrap_or_default();
444
445         for (place, capture_info) in capture_information.into_iter() {
446             let var_hir_id = match place.base {
447                 PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
448                 base => bug!("Expected upvar, found={:?}", base),
449             };
450
451             let place = restrict_capture_precision(place, capture_info.capture_kind);
452
453             let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
454                 None => {
455                     let mutability = self.determine_capture_mutability(&typeck_results, &place);
456                     let min_cap_list =
457                         vec![ty::CapturedPlace { place, info: capture_info, mutability }];
458                     root_var_min_capture_list.insert(var_hir_id, min_cap_list);
459                     continue;
460                 }
461                 Some(min_cap_list) => min_cap_list,
462             };
463
464             // Go through each entry in the current list of min_captures
465             // - if ancestor is found, update it's capture kind to account for current place's
466             // capture information.
467             //
468             // - if descendant is found, remove it from the list, and update the current place's
469             // capture information to account for the descendants's capture kind.
470             //
471             // We can never be in a case where the list contains both an ancestor and a descendant
472             // Also there can only be ancestor but in case of descendants there might be
473             // multiple.
474
475             let mut descendant_found = false;
476             let mut updated_capture_info = capture_info;
477             min_cap_list.retain(|possible_descendant| {
478                 match determine_place_ancestry_relation(&place, &possible_descendant.place) {
479                     // current place is ancestor of possible_descendant
480                     PlaceAncestryRelation::Ancestor => {
481                         descendant_found = true;
482                         let backup_path_expr_id = updated_capture_info.path_expr_id;
483
484                         updated_capture_info =
485                             determine_capture_info(updated_capture_info, possible_descendant.info);
486
487                         // we need to keep the ancestor's `path_expr_id`
488                         updated_capture_info.path_expr_id = backup_path_expr_id;
489                         false
490                     }
491
492                     _ => true,
493                 }
494             });
495
496             let mut ancestor_found = false;
497             if !descendant_found {
498                 for possible_ancestor in min_cap_list.iter_mut() {
499                     match determine_place_ancestry_relation(&place, &possible_ancestor.place) {
500                         // current place is descendant of possible_ancestor
501                         PlaceAncestryRelation::Descendant => {
502                             ancestor_found = true;
503                             let backup_path_expr_id = possible_ancestor.info.path_expr_id;
504                             possible_ancestor.info =
505                                 determine_capture_info(possible_ancestor.info, capture_info);
506
507                             // we need to keep the ancestor's `path_expr_id`
508                             possible_ancestor.info.path_expr_id = backup_path_expr_id;
509
510                             // Only one ancestor of the current place will be in the list.
511                             break;
512                         }
513                         _ => {}
514                     }
515                 }
516             }
517
518             // Only need to insert when we don't have an ancestor in the existing min capture list
519             if !ancestor_found {
520                 let mutability = self.determine_capture_mutability(&typeck_results, &place);
521                 let captured_place =
522                     ty::CapturedPlace { place, info: updated_capture_info, mutability };
523                 min_cap_list.push(captured_place);
524             }
525         }
526
527         debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list);
528         typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list);
529     }
530
531     /// Perform the migration analysis for RFC 2229, and emit lint
532     /// `disjoint_capture_drop_reorder` if needed.
533     fn perform_2229_migration_anaysis(
534         &self,
535         closure_def_id: DefId,
536         capture_clause: hir::CaptureBy,
537         span: Span,
538         body: &'tcx hir::Body<'tcx>,
539     ) {
540         let need_migrations = self.compute_2229_migrations_first_pass(
541             closure_def_id,
542             span,
543             capture_clause,
544             body,
545             self.typeck_results.borrow().closure_min_captures.get(&closure_def_id),
546         );
547
548         if !need_migrations.is_empty() {
549             let need_migrations_hir_id = need_migrations.iter().map(|m| m.0).collect::<Vec<_>>();
550
551             let migrations_text = migration_suggestion_for_2229(self.tcx, &need_migrations_hir_id);
552
553             let local_def_id = closure_def_id.expect_local();
554             let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
555             self.tcx.struct_span_lint_hir(
556                 lint::builtin::DISJOINT_CAPTURE_DROP_REORDER,
557                 closure_hir_id,
558                 span,
559                 |lint| {
560                     let mut diagnostics_builder = lint.build(
561                         "drop order affected for closure because of `capture_disjoint_fields`",
562                     );
563                     diagnostics_builder.note(&migrations_text);
564                     diagnostics_builder.emit();
565                 },
566             );
567         }
568     }
569
570     /// Figures out the list of root variables (and their types) that aren't completely
571     /// captured by the closure when `capture_disjoint_fields` is enabled and drop order of
572     /// some path starting at that root variable **might** be affected.
573     ///
574     /// The output list would include a root variable if:
575     /// - It would have been moved into the closure when `capture_disjoint_fields` wasn't
576     ///   enabled, **and**
577     /// - It wasn't completely captured by the closure, **and**
578     /// - The type of the root variable needs Drop.
579     fn compute_2229_migrations_first_pass(
580         &self,
581         closure_def_id: DefId,
582         closure_span: Span,
583         closure_clause: hir::CaptureBy,
584         body: &'tcx hir::Body<'tcx>,
585         min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
586     ) -> Vec<(hir::HirId, Ty<'tcx>)> {
587         fn resolve_ty<T: TypeFoldable<'tcx>>(
588             fcx: &FnCtxt<'_, 'tcx>,
589             span: Span,
590             body: &'tcx hir::Body<'tcx>,
591             ty: T,
592         ) -> T {
593             let mut resolver = Resolver::new(fcx, &span, body);
594             ty.fold_with(&mut resolver)
595         }
596
597         let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
598             upvars
599         } else {
600             return vec![];
601         };
602
603         let mut need_migrations = Vec::new();
604
605         for (&var_hir_id, _) in upvars.iter() {
606             let ty = resolve_ty(self, closure_span, body, self.node_ty(var_hir_id));
607
608             if !ty.needs_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
609                 continue;
610             }
611
612             let root_var_min_capture_list = if let Some(root_var_min_capture_list) =
613                 min_captures.and_then(|m| m.get(&var_hir_id))
614             {
615                 root_var_min_capture_list
616             } else {
617                 // The upvar is mentioned within the closure but no path starting from it is
618                 // used.
619
620                 match closure_clause {
621                     // Only migrate if closure is a move closure
622                     hir::CaptureBy::Value => need_migrations.push((var_hir_id, ty)),
623
624                     hir::CaptureBy::Ref => {}
625                 }
626
627                 continue;
628             };
629
630             let is_moved = root_var_min_capture_list
631                 .iter()
632                 .any(|capture| matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue(_)));
633
634             let is_not_completely_captured =
635                 root_var_min_capture_list.iter().any(|capture| capture.place.projections.len() > 0);
636
637             if is_moved && is_not_completely_captured {
638                 need_migrations.push((var_hir_id, ty));
639             }
640         }
641
642         need_migrations
643     }
644
645     fn init_capture_kind(
646         &self,
647         capture_clause: hir::CaptureBy,
648         upvar_id: ty::UpvarId,
649         closure_span: Span,
650     ) -> ty::UpvarCapture<'tcx> {
651         match capture_clause {
652             hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None),
653             hir::CaptureBy::Ref => {
654                 let origin = UpvarRegion(upvar_id, closure_span);
655                 let upvar_region = self.next_region_var(origin);
656                 let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
657                 ty::UpvarCapture::ByRef(upvar_borrow)
658             }
659         }
660     }
661
662     fn place_for_root_variable(
663         &self,
664         closure_def_id: LocalDefId,
665         var_hir_id: hir::HirId,
666     ) -> Place<'tcx> {
667         let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id);
668
669         Place {
670             base_ty: self.node_ty(var_hir_id),
671             base: PlaceBase::Upvar(upvar_id),
672             projections: Default::default(),
673         }
674     }
675
676     fn should_log_capture_analysis(&self, closure_def_id: DefId) -> bool {
677         self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis)
678     }
679
680     fn log_capture_analysis_first_pass(
681         &self,
682         closure_def_id: rustc_hir::def_id::DefId,
683         capture_information: &FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>,
684         closure_span: Span,
685     ) {
686         if self.should_log_capture_analysis(closure_def_id) {
687             let mut diag =
688                 self.tcx.sess.struct_span_err(closure_span, "First Pass analysis includes:");
689             for (place, capture_info) in capture_information {
690                 let capture_str = construct_capture_info_string(self.tcx, place, capture_info);
691                 let output_str = format!("Capturing {}", capture_str);
692
693                 let span =
694                     capture_info.path_expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
695                 diag.span_note(span, &output_str);
696             }
697             diag.emit();
698         }
699     }
700
701     fn log_closure_min_capture_info(&self, closure_def_id: DefId, closure_span: Span) {
702         if self.should_log_capture_analysis(closure_def_id) {
703             if let Some(min_captures) =
704                 self.typeck_results.borrow().closure_min_captures.get(&closure_def_id)
705             {
706                 let mut diag =
707                     self.tcx.sess.struct_span_err(closure_span, "Min Capture analysis includes:");
708
709                 for (_, min_captures_for_var) in min_captures {
710                     for capture in min_captures_for_var {
711                         let place = &capture.place;
712                         let capture_info = &capture.info;
713
714                         let capture_str =
715                             construct_capture_info_string(self.tcx, place, capture_info);
716                         let output_str = format!("Min Capture {}", capture_str);
717
718                         if capture.info.path_expr_id != capture.info.capture_kind_expr_id {
719                             let path_span = capture_info
720                                 .path_expr_id
721                                 .map_or(closure_span, |e| self.tcx.hir().span(e));
722                             let capture_kind_span = capture_info
723                                 .capture_kind_expr_id
724                                 .map_or(closure_span, |e| self.tcx.hir().span(e));
725
726                             let mut multi_span: MultiSpan =
727                                 MultiSpan::from_spans(vec![path_span, capture_kind_span]);
728
729                             let capture_kind_label =
730                                 construct_capture_kind_reason_string(self.tcx, place, capture_info);
731                             let path_label = construct_path_string(self.tcx, place);
732
733                             multi_span.push_span_label(path_span, path_label);
734                             multi_span.push_span_label(capture_kind_span, capture_kind_label);
735
736                             diag.span_note(multi_span, &output_str);
737                         } else {
738                             let span = capture_info
739                                 .path_expr_id
740                                 .map_or(closure_span, |e| self.tcx.hir().span(e));
741
742                             diag.span_note(span, &output_str);
743                         };
744                     }
745                 }
746                 diag.emit();
747             }
748         }
749     }
750
751     /// A captured place is mutable if
752     /// 1. Projections don't include a Deref of an immut-borrow, **and**
753     /// 2. PlaceBase is mut or projections include a Deref of a mut-borrow.
754     fn determine_capture_mutability(
755         &self,
756         typeck_results: &'a TypeckResults<'tcx>,
757         place: &Place<'tcx>,
758     ) -> hir::Mutability {
759         let var_hir_id = match place.base {
760             PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
761             _ => unreachable!(),
762         };
763
764         let bm = *typeck_results.pat_binding_modes().get(var_hir_id).expect("missing binding mode");
765
766         let mut is_mutbl = match bm {
767             ty::BindByValue(mutability) => mutability,
768             ty::BindByReference(_) => hir::Mutability::Not,
769         };
770
771         for pointer_ty in place.deref_tys() {
772             match pointer_ty.kind() {
773                 // We don't capture derefs of raw ptrs
774                 ty::RawPtr(_) => unreachable!(),
775
776                 // Derefencing a mut-ref allows us to mut the Place if we don't deref
777                 // an immut-ref after on top of this.
778                 ty::Ref(.., hir::Mutability::Mut) => is_mutbl = hir::Mutability::Mut,
779
780                 // The place isn't mutable once we dereference a immutable reference.
781                 ty::Ref(.., hir::Mutability::Not) => return hir::Mutability::Not,
782
783                 // Dereferencing a box doesn't change mutability
784                 ty::Adt(def, ..) if def.is_box() => {}
785
786                 unexpected_ty => bug!("deref of unexpected pointer type {:?}", unexpected_ty),
787             }
788         }
789
790         is_mutbl
791     }
792 }
793
794 struct InferBorrowKind<'a, 'tcx> {
795     fcx: &'a FnCtxt<'a, 'tcx>,
796
797     // The def-id of the closure whose kind and upvar accesses are being inferred.
798     closure_def_id: DefId,
799
800     closure_span: Span,
801
802     capture_clause: hir::CaptureBy,
803
804     // The kind that we have inferred that the current closure
805     // requires. Note that we *always* infer a minimal kind, even if
806     // we don't always *use* that in the final result (i.e., sometimes
807     // we've taken the closure kind from the expectations instead, and
808     // for generators we don't even implement the closure traits
809     // really).
810     current_closure_kind: ty::ClosureKind,
811
812     // If we modified `current_closure_kind`, this field contains a `Some()` with the
813     // variable access that caused us to do so.
814     current_origin: Option<(Span, Place<'tcx>)>,
815
816     /// For each Place that is captured by the closure, we track the minimal kind of
817     /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
818     ///
819     /// Consider closure where s.str1 is captured via an ImmutableBorrow and
820     /// s.str2 via a MutableBorrow
821     ///
822     /// ```rust,no_run
823     /// struct SomeStruct { str1: String, str2: String }
824     ///
825     /// // Assume that the HirId for the variable definition is `V1`
826     /// let mut s = SomeStruct { str1: format!("s1"), str2: format!("s2") }
827     ///
828     /// let fix_s = |new_s2| {
829     ///     // Assume that the HirId for the expression `s.str1` is `E1`
830     ///     println!("Updating SomeStruct with str1=", s.str1);
831     ///     // Assume that the HirId for the expression `*s.str2` is `E2`
832     ///     s.str2 = new_s2;
833     /// };
834     /// ```
835     ///
836     /// For closure `fix_s`, (at a high level) the map contains
837     ///
838     /// ```
839     /// Place { V1, [ProjectionKind::Field(Index=0, Variant=0)] } : CaptureKind { E1, ImmutableBorrow }
840     /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
841     /// ```
842     capture_information: InferredCaptureInformation<'tcx>,
843 }
844
845 impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
846     fn adjust_upvar_borrow_kind_for_consume(
847         &mut self,
848         place_with_id: &PlaceWithHirId<'tcx>,
849         diag_expr_id: hir::HirId,
850         mode: euv::ConsumeMode,
851     ) {
852         debug!(
853             "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})",
854             place_with_id, diag_expr_id, mode
855         );
856
857         // we only care about moves
858         match mode {
859             euv::Copy => {
860                 return;
861             }
862             euv::Move => {}
863         }
864
865         let tcx = self.fcx.tcx;
866         let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
867             upvar_id
868         } else {
869             return;
870         };
871
872         debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id);
873
874         let usage_span = tcx.hir().span(diag_expr_id);
875
876         // To move out of an upvar, this must be a FnOnce closure
877         self.adjust_closure_kind(
878             upvar_id.closure_expr_id,
879             ty::ClosureKind::FnOnce,
880             usage_span,
881             place_with_id.place.clone(),
882         );
883
884         let capture_info = ty::CaptureInfo {
885             capture_kind_expr_id: Some(diag_expr_id),
886             path_expr_id: Some(diag_expr_id),
887             capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)),
888         };
889
890         let curr_info = self.capture_information[&place_with_id.place];
891         let updated_info = determine_capture_info(curr_info, capture_info);
892
893         self.capture_information[&place_with_id.place] = updated_info;
894     }
895
896     /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
897     /// to). If the place is based on a by-ref upvar, this implies that
898     /// the upvar must be borrowed using an `&mut` borrow.
899     fn adjust_upvar_borrow_kind_for_mut(
900         &mut self,
901         place_with_id: &PlaceWithHirId<'tcx>,
902         diag_expr_id: hir::HirId,
903     ) {
904         debug!(
905             "adjust_upvar_borrow_kind_for_mut(place_with_id={:?}, diag_expr_id={:?})",
906             place_with_id, diag_expr_id
907         );
908
909         if let PlaceBase::Upvar(_) = place_with_id.place.base {
910             let mut borrow_kind = ty::MutBorrow;
911             for pointer_ty in place_with_id.place.deref_tys() {
912                 match pointer_ty.kind() {
913                     // Raw pointers don't inherit mutability.
914                     ty::RawPtr(_) => return,
915                     // assignment to deref of an `&mut`
916                     // borrowed pointer implies that the
917                     // pointer itself must be unique, but not
918                     // necessarily *mutable*
919                     ty::Ref(.., hir::Mutability::Mut) => borrow_kind = ty::UniqueImmBorrow,
920                     _ => (),
921                 }
922             }
923             self.adjust_upvar_deref(place_with_id, diag_expr_id, borrow_kind);
924         }
925     }
926
927     fn adjust_upvar_borrow_kind_for_unique(
928         &mut self,
929         place_with_id: &PlaceWithHirId<'tcx>,
930         diag_expr_id: hir::HirId,
931     ) {
932         debug!(
933             "adjust_upvar_borrow_kind_for_unique(place_with_id={:?}, diag_expr_id={:?})",
934             place_with_id, diag_expr_id
935         );
936
937         if let PlaceBase::Upvar(_) = place_with_id.place.base {
938             if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
939                 // Raw pointers don't inherit mutability.
940                 return;
941             }
942             // for a borrowed pointer to be unique, its base must be unique
943             self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::UniqueImmBorrow);
944         }
945     }
946
947     fn adjust_upvar_deref(
948         &mut self,
949         place_with_id: &PlaceWithHirId<'tcx>,
950         diag_expr_id: hir::HirId,
951         borrow_kind: ty::BorrowKind,
952     ) {
953         assert!(match borrow_kind {
954             ty::MutBorrow => true,
955             ty::UniqueImmBorrow => true,
956
957             // imm borrows never require adjusting any kinds, so we don't wind up here
958             ty::ImmBorrow => false,
959         });
960
961         let tcx = self.fcx.tcx;
962
963         // if this is an implicit deref of an
964         // upvar, then we need to modify the
965         // borrow_kind of the upvar to make sure it
966         // is inferred to mutable if necessary
967         self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind);
968
969         if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
970             self.adjust_closure_kind(
971                 upvar_id.closure_expr_id,
972                 ty::ClosureKind::FnMut,
973                 tcx.hir().span(diag_expr_id),
974                 place_with_id.place.clone(),
975             );
976         }
977     }
978
979     /// We infer the borrow_kind with which to borrow upvars in a stack closure.
980     /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`,
981     /// moving from left to right as needed (but never right to left).
982     /// Here the argument `mutbl` is the borrow_kind that is required by
983     /// some particular use.
984     fn adjust_upvar_borrow_kind(
985         &mut self,
986         place_with_id: &PlaceWithHirId<'tcx>,
987         diag_expr_id: hir::HirId,
988         kind: ty::BorrowKind,
989     ) {
990         let curr_capture_info = self.capture_information[&place_with_id.place];
991
992         debug!(
993             "adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})",
994             place_with_id, diag_expr_id, curr_capture_info, kind
995         );
996
997         if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind {
998             // It's already captured by value, we don't need to do anything here
999             return;
1000         } else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind {
1001             // Use the same region as the current capture information
1002             // Doesn't matter since only one of the UpvarBorrow will be used.
1003             let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region };
1004
1005             let capture_info = ty::CaptureInfo {
1006                 capture_kind_expr_id: Some(diag_expr_id),
1007                 path_expr_id: Some(diag_expr_id),
1008                 capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow),
1009             };
1010             let updated_info = determine_capture_info(curr_capture_info, capture_info);
1011             self.capture_information[&place_with_id.place] = updated_info;
1012         };
1013     }
1014
1015     fn adjust_closure_kind(
1016         &mut self,
1017         closure_id: LocalDefId,
1018         new_kind: ty::ClosureKind,
1019         upvar_span: Span,
1020         place: Place<'tcx>,
1021     ) {
1022         debug!(
1023             "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, place={:?})",
1024             closure_id, new_kind, upvar_span, place
1025         );
1026
1027         // Is this the closure whose kind is currently being inferred?
1028         if closure_id.to_def_id() != self.closure_def_id {
1029             debug!("adjust_closure_kind: not current closure");
1030             return;
1031         }
1032
1033         // closures start out as `Fn`.
1034         let existing_kind = self.current_closure_kind;
1035
1036         debug!(
1037             "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}",
1038             closure_id, existing_kind, new_kind
1039         );
1040
1041         match (existing_kind, new_kind) {
1042             (ty::ClosureKind::Fn, ty::ClosureKind::Fn)
1043             | (ty::ClosureKind::FnMut, ty::ClosureKind::Fn | ty::ClosureKind::FnMut)
1044             | (ty::ClosureKind::FnOnce, _) => {
1045                 // no change needed
1046             }
1047
1048             (ty::ClosureKind::Fn, ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce)
1049             | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
1050                 // new kind is stronger than the old kind
1051                 self.current_closure_kind = new_kind;
1052                 self.current_origin = Some((upvar_span, place));
1053             }
1054         }
1055     }
1056
1057     fn init_capture_info_for_place(
1058         &mut self,
1059         place_with_id: &PlaceWithHirId<'tcx>,
1060         diag_expr_id: hir::HirId,
1061     ) {
1062         if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
1063             assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
1064
1065             let capture_kind =
1066                 self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span);
1067
1068             let expr_id = Some(diag_expr_id);
1069             let capture_info = ty::CaptureInfo {
1070                 capture_kind_expr_id: expr_id,
1071                 path_expr_id: expr_id,
1072                 capture_kind,
1073             };
1074
1075             debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info);
1076
1077             self.capture_information.insert(place_with_id.place.clone(), capture_info);
1078         } else {
1079             debug!("Not upvar: {:?}", place_with_id);
1080         }
1081     }
1082 }
1083
1084 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1085     fn consume(
1086         &mut self,
1087         place_with_id: &PlaceWithHirId<'tcx>,
1088         diag_expr_id: hir::HirId,
1089         mode: euv::ConsumeMode,
1090     ) {
1091         debug!(
1092             "consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})",
1093             place_with_id, diag_expr_id, mode
1094         );
1095         if !self.capture_information.contains_key(&place_with_id.place) {
1096             self.init_capture_info_for_place(place_with_id, diag_expr_id);
1097         }
1098
1099         self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id, mode);
1100     }
1101
1102     fn borrow(
1103         &mut self,
1104         place_with_id: &PlaceWithHirId<'tcx>,
1105         diag_expr_id: hir::HirId,
1106         bk: ty::BorrowKind,
1107     ) {
1108         debug!(
1109             "borrow(place_with_id={:?}, diag_expr_id={:?}, bk={:?})",
1110             place_with_id, diag_expr_id, bk
1111         );
1112
1113         if !self.capture_information.contains_key(&place_with_id.place) {
1114             self.init_capture_info_for_place(place_with_id, diag_expr_id);
1115         }
1116
1117         match bk {
1118             ty::ImmBorrow => {}
1119             ty::UniqueImmBorrow => {
1120                 self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id);
1121             }
1122             ty::MutBorrow => {
1123                 self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id);
1124             }
1125         }
1126     }
1127
1128     fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
1129         debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id);
1130
1131         if !self.capture_information.contains_key(&assignee_place.place) {
1132             self.init_capture_info_for_place(assignee_place, diag_expr_id);
1133         }
1134
1135         self.adjust_upvar_borrow_kind_for_mut(assignee_place, diag_expr_id);
1136     }
1137 }
1138
1139 /// Truncate projections so that following rules are obeyed by the captured `place`:
1140 ///
1141 /// - No Derefs in move closure, this will result in value behind a reference getting moved.
1142 /// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
1143 ///   them completely.
1144 /// - No Index projections are captured, since arrays are captured completely.
1145 fn restrict_capture_precision<'tcx>(
1146     mut place: Place<'tcx>,
1147     capture_kind: ty::UpvarCapture<'tcx>,
1148 ) -> Place<'tcx> {
1149     if place.projections.is_empty() {
1150         // Nothing to do here
1151         return place;
1152     }
1153
1154     if place.base_ty.is_unsafe_ptr() {
1155         place.projections.truncate(0);
1156         return place;
1157     }
1158
1159     let mut truncated_length = usize::MAX;
1160     let mut first_deref_projection = usize::MAX;
1161
1162     for (i, proj) in place.projections.iter().enumerate() {
1163         if proj.ty.is_unsafe_ptr() {
1164             // Don't apply any projections on top of an unsafe ptr
1165             truncated_length = truncated_length.min(i + 1);
1166             break;
1167         }
1168         match proj.kind {
1169             ProjectionKind::Index => {
1170                 // Arrays are completely captured, so we drop Index projections
1171                 truncated_length = truncated_length.min(i);
1172                 break;
1173             }
1174             ProjectionKind::Deref => {
1175                 // We only drop Derefs in case of move closures
1176                 // There might be an index projection or raw ptr ahead, so we don't stop here.
1177                 first_deref_projection = first_deref_projection.min(i);
1178             }
1179             ProjectionKind::Field(..) => {} // ignore
1180             ProjectionKind::Subslice => {}  // We never capture this
1181         }
1182     }
1183
1184     let length = place
1185         .projections
1186         .len()
1187         .min(truncated_length)
1188         // In case of capture `ByValue` we want to not capture derefs
1189         .min(match capture_kind {
1190             ty::UpvarCapture::ByValue(..) => first_deref_projection,
1191             ty::UpvarCapture::ByRef(..) => usize::MAX,
1192         });
1193
1194     place.projections.truncate(length);
1195
1196     place
1197 }
1198
1199 fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
1200     let variable_name = match place.base {
1201         PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(),
1202         _ => bug!("Capture_information should only contain upvars"),
1203     };
1204
1205     let mut projections_str = String::new();
1206     for (i, item) in place.projections.iter().enumerate() {
1207         let proj = match item.kind {
1208             ProjectionKind::Field(a, b) => format!("({:?}, {:?})", a, b),
1209             ProjectionKind::Deref => String::from("Deref"),
1210             ProjectionKind::Index => String::from("Index"),
1211             ProjectionKind::Subslice => String::from("Subslice"),
1212         };
1213         if i != 0 {
1214             projections_str.push_str(",");
1215         }
1216         projections_str.push_str(proj.as_str());
1217     }
1218
1219     format!("{}[{}]", variable_name, projections_str)
1220 }
1221
1222 fn construct_capture_kind_reason_string(
1223     tcx: TyCtxt<'_>,
1224     place: &Place<'tcx>,
1225     capture_info: &ty::CaptureInfo<'tcx>,
1226 ) -> String {
1227     let place_str = construct_place_string(tcx, &place);
1228
1229     let capture_kind_str = match capture_info.capture_kind {
1230         ty::UpvarCapture::ByValue(_) => "ByValue".into(),
1231         ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
1232     };
1233
1234     format!("{} captured as {} here", place_str, capture_kind_str)
1235 }
1236
1237 fn construct_path_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
1238     let place_str = construct_place_string(tcx, &place);
1239
1240     format!("{} used here", place_str)
1241 }
1242
1243 fn construct_capture_info_string(
1244     tcx: TyCtxt<'_>,
1245     place: &Place<'tcx>,
1246     capture_info: &ty::CaptureInfo<'tcx>,
1247 ) -> String {
1248     let place_str = construct_place_string(tcx, &place);
1249
1250     let capture_kind_str = match capture_info.capture_kind {
1251         ty::UpvarCapture::ByValue(_) => "ByValue".into(),
1252         ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
1253     };
1254     format!("{} -> {}", place_str, capture_kind_str)
1255 }
1256
1257 fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
1258     tcx.hir().name(var_hir_id)
1259 }
1260
1261 fn should_do_migration_analysis(tcx: TyCtxt<'_>, closure_id: hir::HirId) -> bool {
1262     let (level, _) =
1263         tcx.lint_level_at_node(lint::builtin::DISJOINT_CAPTURE_DROP_REORDER, closure_id);
1264
1265     !matches!(level, lint::Level::Allow)
1266 }
1267
1268 fn migration_suggestion_for_2229(tcx: TyCtxt<'_>, need_migrations: &Vec<hir::HirId>) -> String {
1269     let need_migrations_strings =
1270         need_migrations.iter().map(|v| format!("{}", var_name(tcx, *v))).collect::<Vec<_>>();
1271     let migrations_list_concat = need_migrations_strings.join(", ");
1272
1273     format!("drop(&({}));", migrations_list_concat)
1274 }
1275
1276 /// Helper function to determine if we need to escalate CaptureKind from
1277 /// CaptureInfo A to B and returns the escalated CaptureInfo.
1278 /// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
1279 ///
1280 /// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
1281 /// on the `CaptureInfo` containing an associated `capture_kind_expr_id`.
1282 ///
1283 /// It is the caller's duty to figure out which path_expr_id to use.
1284 ///
1285 /// If both the CaptureKind and Expression are considered to be equivalent,
1286 /// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
1287 /// expressions reported back to the user as part of diagnostics based on which appears earlier
1288 /// in the closure. This can be acheived simply by calling
1289 /// `determine_capture_info(existing_info, current_info)`. This works out because the
1290 /// expressions that occur earlier in the closure body than the current expression are processed before.
1291 /// Consider the following example
1292 /// ```rust,no_run
1293 /// struct Point { x: i32, y: i32 }
1294 /// let mut p: Point { x: 10, y: 10 };
1295 ///
1296 /// let c = || {
1297 ///     p.x     += 10;
1298 /// // ^ E1 ^
1299 ///     // ...
1300 ///     // More code
1301 ///     // ...
1302 ///     p.x += 10; // E2
1303 /// // ^ E2 ^
1304 /// };
1305 /// ```
1306 /// `CaptureKind` associated with both `E1` and `E2` will be ByRef(MutBorrow),
1307 /// and both have an expression associated, however for diagnostics we prefer reporting
1308 /// `E1` since it appears earlier in the closure body. When `E2` is being processed we
1309 /// would've already handled `E1`, and have an existing capture_information for it.
1310 /// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return
1311 /// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics.
1312 fn determine_capture_info(
1313     capture_info_a: ty::CaptureInfo<'tcx>,
1314     capture_info_b: ty::CaptureInfo<'tcx>,
1315 ) -> ty::CaptureInfo<'tcx> {
1316     // If the capture kind is equivalent then, we don't need to escalate and can compare the
1317     // expressions.
1318     let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
1319         (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => {
1320             // We don't need to worry about the spans being ignored here.
1321             //
1322             // The expr_id in capture_info corresponds to the span that is stored within
1323             // ByValue(span) and therefore it gets handled with priortizing based on
1324             // expressions below.
1325             true
1326         }
1327         (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
1328             ref_a.kind == ref_b.kind
1329         }
1330         (ty::UpvarCapture::ByValue(_), _) | (ty::UpvarCapture::ByRef(_), _) => false,
1331     };
1332
1333     if eq_capture_kind {
1334         match (capture_info_a.capture_kind_expr_id, capture_info_b.capture_kind_expr_id) {
1335             (Some(_), _) | (None, None) => capture_info_a,
1336             (None, Some(_)) => capture_info_b,
1337         }
1338     } else {
1339         // We select the CaptureKind which ranks higher based the following priority order:
1340         // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
1341         match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
1342             (ty::UpvarCapture::ByValue(_), _) => capture_info_a,
1343             (_, ty::UpvarCapture::ByValue(_)) => capture_info_b,
1344             (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
1345                 match (ref_a.kind, ref_b.kind) {
1346                     // Take LHS:
1347                     (ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow)
1348                     | (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a,
1349
1350                     // Take RHS:
1351                     (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow)
1352                     | (ty::UniqueImmBorrow, ty::MutBorrow) => capture_info_b,
1353
1354                     (ty::ImmBorrow, ty::ImmBorrow)
1355                     | (ty::UniqueImmBorrow, ty::UniqueImmBorrow)
1356                     | (ty::MutBorrow, ty::MutBorrow) => {
1357                         bug!("Expected unequal capture kinds");
1358                     }
1359                 }
1360             }
1361         }
1362     }
1363 }
1364
1365 /// Determines the Ancestry relationship of Place A relative to Place B
1366 ///
1367 /// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B
1368 /// `PlaceAncestryRelation::Descendant` implies Place A is descendant of Place B
1369 /// `PlaceAncestryRelation::Divergent` implies neither of them is the ancestor of the other.
1370 fn determine_place_ancestry_relation(
1371     place_a: &Place<'tcx>,
1372     place_b: &Place<'tcx>,
1373 ) -> PlaceAncestryRelation {
1374     // If Place A and Place B, don't start off from the same root variable, they are divergent.
1375     if place_a.base != place_b.base {
1376         return PlaceAncestryRelation::Divergent;
1377     }
1378
1379     // Assume of length of projections_a = n
1380     let projections_a = &place_a.projections;
1381
1382     // Assume of length of projections_b = m
1383     let projections_b = &place_b.projections;
1384
1385     let mut same_initial_projections = true;
1386
1387     for (proj_a, proj_b) in projections_a.iter().zip(projections_b.iter()) {
1388         if proj_a != proj_b {
1389             same_initial_projections = false;
1390             break;
1391         }
1392     }
1393
1394     if same_initial_projections {
1395         // First min(n, m) projections are the same
1396         // Select Ancestor/Descendant
1397         if projections_b.len() >= projections_a.len() {
1398             PlaceAncestryRelation::Ancestor
1399         } else {
1400             PlaceAncestryRelation::Descendant
1401         }
1402     } else {
1403         PlaceAncestryRelation::Divergent
1404     }
1405 }