]> git.lizzy.rs Git - rust.git/commitdiff
Address review comments
authorAman Arora <me@aman-arora.com>
Mon, 9 Nov 2020 05:15:45 +0000 (00:15 -0500)
committerAman Arora <me@aman-arora.com>
Wed, 11 Nov 2020 01:58:57 +0000 (20:58 -0500)
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_typeck/src/check/upvar.rs

index 76ca0c51ce1c3b59c24ffbe936fa0a28889ecdec..ee577213aba14cd7e29d466e35ceced6aa80959b 100644 (file)
@@ -415,9 +415,8 @@ pub struct TypeckResults<'tcx> {
     /// entire variable.
     pub closure_captures: ty::UpvarListMap,
 
-    /// Given the closure DefId this map provides a map of
-    /// root variables to minimum set of `Place`s (and how) that need to be tracked
-    /// to support all captures of that closure.
+    /// Tracks the minimum captures required for a closure;
+    /// see `MinCaptureInformationMap` for more details.
     pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
 
     /// Stores the type, expression, span and optional scope span of all types
index c41463d18448dbd1256c224ec7fcb05c435846b5..0c786be0478de5f4ca651a4c13f2b8b57e444365 100644 (file)
@@ -763,6 +763,31 @@ pub struct UpvarBorrow<'tcx> {
     pub region: ty::Region<'tcx>,
 }
 
+/// Given the closure DefId this map provides a map of root variables to minimum
+/// set of `CapturedPlace`s that need to be tracked to support all captures of that closure.
+pub type MinCaptureInformationMap<'tcx> = FxHashMap<DefId, RootVariableMinCaptureList<'tcx>>;
+
+/// Part of `MinCaptureInformationMap`; Maps a root variable to the list of `CapturedPlace`.
+/// Used to track the minimum set of `Place`s that need to be captured to support all
+/// Places captured by the closure starting at a given root variable.
+///
+/// This provides a convenient and quick way of checking if a variable being used within
+/// a closure is a capture of a local variable.
+pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureList<'tcx>>;
+
+/// Part of `MinCaptureInformationMap`; List of `CapturePlace`s.
+pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
+
+/// A `Place` and the corresponding `CaptureInfo`.
+#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct CapturedPlace<'tcx> {
+    pub place: HirPlace<'tcx>,
+    pub info: CaptureInfo<'tcx>,
+}
+
+/// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
+/// for a particular capture as well as identifying the part of the source code
+/// that triggered this capture to occur.
 #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
 pub struct CaptureInfo<'tcx> {
     /// Expr Id pointing to use that resulted in selecting the current capture kind
@@ -788,19 +813,9 @@ pub struct CaptureInfo<'tcx> {
     pub capture_kind: UpvarCapture<'tcx>,
 }
 
-#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
-pub struct CapturedPlace<'tcx> {
-    pub place: HirPlace<'tcx>,
-    pub info: CaptureInfo<'tcx>,
-}
-
 pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
 pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
 
-pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
-pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureList<'tcx>>;
-pub type MinCaptureInformationMap<'tcx> = FxHashMap<DefId, RootVariableMinCaptureList<'tcx>>;
-
 #[derive(Clone, Copy, PartialEq, Eq)]
 pub enum IntVarValue {
     IntType(ast::IntTy),
index 2dff7d0fbddfbd45d79e894f8e34dc5a29aa6855..90e021ae592a592257663aa758a1cd01d2cefeef 100644 (file)
@@ -46,9 +46,9 @@
 
 /// Describe the relationship between the paths of two places
 /// eg:
-/// - foo is ancestor of foo.bar.baz
-/// - foo.bar.baz is an descendant of foo.bar,
-/// - foo.bar and foo.baz are divergent
+/// - `foo` is ancestor of `foo.bar.baz`
+/// - `foo.bar.baz` is an descendant of `foo.bar`
+/// - `foo.bar` and `foo.baz` are divergent
 enum PlaceAncestryRelation {
     Ancestor,
     Descendant,
@@ -124,7 +124,8 @@ fn analyze_closure(
 
         let local_def_id = closure_def_id.expect_local();
 
-        let mut capture_information = FxIndexMap::<Place<'tcx>, ty::CaptureInfo<'tcx>>::default();
+        let mut capture_information: FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>> =
+            Default::default();
         if !self.tcx.features().capture_disjoint_fields {
             if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
                 for (&var_hir_id, _) in upvars.iter() {
@@ -186,7 +187,7 @@ fn analyze_closure(
         self.compute_min_captures(closure_def_id, delegate);
         self.log_closure_min_capture_info(closure_def_id, span);
 
-        self.set_closure_captures(closure_def_id);
+        self.min_captures_to_closure_captures_bridge(closure_def_id);
 
         // Now that we've analyzed the closure, we know how each
         // variable is borrowed, and we know what traits the closure
@@ -274,8 +275,7 @@ fn final_upvar_tys(&self, closure_id: hir::HirId) -> Vec<Ty<'tcx>> {
     ///
     /// 2. upvar_capture_map
     /// UpvarId(foo,c) -> MutBorrow, UpvarId(bar, c) -> ByValue
-
-    fn set_closure_captures(&self, closure_def_id: DefId) {
+    fn min_captures_to_closure_captures_bridge(&self, closure_def_id: DefId) {
         let mut closure_captures: FxIndexMap<hir::HirId, ty::UpvarId> = Default::default();
         let mut upvar_capture_map = ty::UpvarCaptureMap::default();
 
@@ -304,8 +304,7 @@ fn set_closure_captures(&self, closure_def_id: DefId) {
                         // so we create a fake capture info with no expression.
                         let fake_capture_info =
                             ty::CaptureInfo { expr_id: None, capture_kind: capture_kind.clone() };
-                        self.determine_capture_info(fake_capture_info, capture_info.clone())
-                            .capture_kind
+                        determine_capture_info(fake_capture_info, capture_info).capture_kind
                     } else {
                         capture_info.capture_kind
                     };
@@ -329,7 +328,7 @@ fn set_closure_captures(&self, closure_def_id: DefId) {
         }
     }
 
-    /// Analyses the information collected by InferBorrowKind to compute the min number of
+    /// Analyzes the information collected by `InferBorrowKind` to compute the min number of
     /// Places (and corresponding capture kind) that we need to keep track of to support all
     /// the required captured paths.
     ///
@@ -420,8 +419,8 @@ fn compute_min_captures(
                     // current place is ancestor of possible_descendant
                     PlaceAncestryRelation::Ancestor => {
                         descendant_found = true;
-                        updated_capture_info = self
-                            .determine_capture_info(updated_capture_info, possible_descendant.info);
+                        updated_capture_info =
+                            determine_capture_info(updated_capture_info, possible_descendant.info);
                         false
                     }
 
@@ -437,7 +436,7 @@ fn compute_min_captures(
                         PlaceAncestryRelation::Descendant => {
                             ancestor_found = true;
                             possible_ancestor.info =
-                                self.determine_capture_info(possible_ancestor.info, capture_info);
+                                determine_capture_info(possible_ancestor.info, capture_info);
 
                             // Only one ancestor of the current place will be in the list.
                             break;
@@ -500,60 +499,6 @@ fn should_log_capture_analysis(&self, closure_def_id: DefId) -> bool {
         self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis)
     }
 
-    /// Helper function to determine if we need to escalate CaptureKind from
-    /// CaptureInfo A to B and returns the escalated CaptureInfo.
-    /// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
-    ///
-    /// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
-    /// on the `CaptureInfo` containing an associated expression id.
-    ///
-    /// If both the CaptureKind and Expression are considered to be equivalent,
-    /// then `CaptureInfo` A is preferred.
-    fn determine_capture_info(
-        &self,
-        capture_info_a: ty::CaptureInfo<'tcx>,
-        capture_info_b: ty::CaptureInfo<'tcx>,
-    ) -> ty::CaptureInfo<'tcx> {
-        // If the capture kind is equivalent then, we don't need to escalate and can compare the
-        // expressions.
-        let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
-            (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => true,
-            (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
-                ref_a.kind == ref_b.kind
-            }
-            _ => false,
-        };
-
-        if eq_capture_kind {
-            match (capture_info_a.expr_id, capture_info_b.expr_id) {
-                (Some(_), _) | (None, None) => capture_info_a,
-                (None, Some(_)) => capture_info_b,
-            }
-        } else {
-            match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
-                (ty::UpvarCapture::ByValue(_), _) => capture_info_a,
-                (_, ty::UpvarCapture::ByValue(_)) => capture_info_b,
-                (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
-                    match (ref_a.kind, ref_b.kind) {
-                        // Take LHS:
-                        (ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow)
-                        | (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a,
-
-                        // Take RHS:
-                        (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow)
-                        | (ty::UniqueImmBorrow, ty::MutBorrow) => capture_info_b,
-
-                        (ty::ImmBorrow, ty::ImmBorrow)
-                        | (ty::UniqueImmBorrow, ty::UniqueImmBorrow)
-                        | (ty::MutBorrow, ty::MutBorrow) => {
-                            bug!("Expected unequal capture kinds");
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     fn log_closure_capture_info(
         &self,
         closure_def_id: rustc_hir::def_id::DefId,
@@ -617,8 +562,9 @@ struct InferBorrowKind<'a, 'tcx> {
     // variable access that caused us to do so.
     current_origin: Option<(Span, Symbol)>,
 
-    /// For each Place that we access, we track the minimal kind of
+    /// For each Place that is captured by the closure, we track the minimal kind of
     /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
+    ///
     /// Consider closure where s.str1 is captured via an ImmutableBorrow and
     /// s.str2 via a MutableBorrow
     ///
@@ -686,7 +632,7 @@ fn adjust_upvar_borrow_kind_for_consume(
         };
 
         let curr_info = self.capture_information[&place_with_id.place];
-        let updated_info = self.fcx.determine_capture_info(curr_info, capture_info);
+        let updated_info = determine_capture_info(curr_info, capture_info);
 
         self.capture_information[&place_with_id.place] = updated_info;
     }
@@ -804,7 +750,7 @@ fn adjust_upvar_borrow_kind(
                 expr_id: Some(diag_expr_id),
                 capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow),
             };
-            let updated_info = self.fcx.determine_capture_info(curr_capture_info, capture_info);
+            let updated_info = determine_capture_info(curr_capture_info, capture_info);
             self.capture_information[&place_with_id.place] = updated_info;
         };
     }
@@ -859,14 +805,14 @@ fn init_capture_info_for_place(
         if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
             assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
 
-            debug!("Capturing new place {:?}", place_with_id);
-
             let capture_kind =
                 self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span);
 
             let expr_id = Some(diag_expr_id);
             let capture_info = ty::CaptureInfo { expr_id, capture_kind };
 
+            debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info);
+
             self.capture_information.insert(place_with_id.place.clone(), capture_info);
         } else {
             debug!("Not upvar: {:?}", place_with_id);
@@ -964,6 +910,92 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
     tcx.hir().name(var_hir_id)
 }
 
+/// Helper function to determine if we need to escalate CaptureKind from
+/// CaptureInfo A to B and returns the escalated CaptureInfo.
+/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
+///
+/// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
+/// on the `CaptureInfo` containing an associated expression id.
+///
+/// If both the CaptureKind and Expression are considered to be equivalent,
+/// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
+/// expressions reported back to the user as part of diagnostics based on which appears earlier
+/// in the closure. This can be acheived simply by calling
+/// `determine_capture_info(existing_info, current_info)`. This works out because the
+/// expressions that occur earlier in the closure body than the current expression are processed before.
+/// Consider the following example
+/// ```rust
+/// let mut p: Point { x: 10, y: 10 };
+///
+/// let c = || {
+///     p.x     += 10;
+/// // ^ E1 ^
+///     // ...
+///     // More code
+///     // ...
+///     p.x += 10; // E2
+/// // ^ E2 ^
+/// }
+/// ```
+/// `CaptureKind` associated with both `E1` and `E2` will be ByRef(MutBorrow),
+/// and both have an expression associated, however for diagnostics we prfer reporting
+/// `E1` since it appears earlier in the closure body. When `E2` is being processed we
+/// would've already handled `E1`, and have an existing capture_information for it.
+/// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return
+/// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics.
+fn determine_capture_info(
+    capture_info_a: ty::CaptureInfo<'tcx>,
+    capture_info_b: ty::CaptureInfo<'tcx>,
+) -> ty::CaptureInfo<'tcx> {
+    // If the capture kind is equivalent then, we don't need to escalate and can compare the
+    // expressions.
+    let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
+        (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => {
+            // We don't need to worry about the spans being ignored here.
+            //
+            // The expr_id in capture_info corresponds to the span that is stored within
+            // ByValue(span) and therefore it gets handled with priortizing based on
+            // expressions below.
+            true
+        }
+        (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
+            ref_a.kind == ref_b.kind
+        }
+        (ty::UpvarCapture::ByValue(_), _) | (ty::UpvarCapture::ByRef(_), _) => false,
+    };
+
+    if eq_capture_kind {
+        match (capture_info_a.expr_id, capture_info_b.expr_id) {
+            (Some(_), _) | (None, None) => capture_info_a,
+            (None, Some(_)) => capture_info_b,
+        }
+    } else {
+        // We select the CaptureKind which ranks higher based the following priority order:
+        // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
+        match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
+            (ty::UpvarCapture::ByValue(_), _) => capture_info_a,
+            (_, ty::UpvarCapture::ByValue(_)) => capture_info_b,
+            (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
+                match (ref_a.kind, ref_b.kind) {
+                    // Take LHS:
+                    (ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow)
+                    | (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a,
+
+                    // Take RHS:
+                    (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow)
+                    | (ty::UniqueImmBorrow, ty::MutBorrow) => capture_info_b,
+
+                    (ty::ImmBorrow, ty::ImmBorrow)
+                    | (ty::UniqueImmBorrow, ty::UniqueImmBorrow)
+                    | (ty::MutBorrow, ty::MutBorrow) => {
+                        bug!("Expected unequal capture kinds");
+                    }
+                }
+            }
+        }
+    }
+}
+
 /// Determines the Ancestry relationship of Place A relative to Place B
 ///
 /// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B