]> git.lizzy.rs Git - rust.git/commitdiff
extract a `best_blame_constraint` helper
authorNiko Matsakis <niko@alum.mit.edu>
Mon, 23 Jul 2018 18:27:49 +0000 (21:27 +0300)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 25 Jul 2018 03:38:21 +0000 (06:38 +0300)
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs

index a48ffe7a799ea83c4619954fc11455fe50c4a94f..054af74881957377d67babedc8bc714ca675de9b 100644 (file)
@@ -28,7 +28,7 @@
 /// Constraints that are considered interesting can be categorized to
 /// determine why they are interesting. Order of variants indicates
 /// sort order of the category, thereby influencing diagnostic output.
-#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
 enum ConstraintCategory {
     Cast,
     Assignment,
@@ -43,12 +43,14 @@ enum ConstraintCategory {
 impl fmt::Display for ConstraintCategory {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
-            ConstraintCategory::Assignment |
-            ConstraintCategory::AssignmentToUpvar => write!(f, "assignment"),
+            ConstraintCategory::Assignment | ConstraintCategory::AssignmentToUpvar => {
+                write!(f, "assignment")
+            }
             ConstraintCategory::Return => write!(f, "return"),
             ConstraintCategory::Cast => write!(f, "cast"),
-            ConstraintCategory::CallArgument |
-            ConstraintCategory::CallArgumentToUpvar => write!(f, "argument"),
+            ConstraintCategory::CallArgument | ConstraintCategory::CallArgumentToUpvar => {
+                write!(f, "argument")
+            }
             _ => write!(f, "free region"),
         }
     }
@@ -62,6 +64,43 @@ enum Trace {
 }
 
 impl<'tcx> RegionInferenceContext<'tcx> {
+    /// Tries to find the best constraint to blame for the fact that
+    /// `R: from_region`, where `R` is some region that meets
+    /// `target_test`. This works by following the constraint graph,
+    /// creating a constraint path that forces `R` to outlive
+    /// `from_region`, and then finding the best choices within that
+    /// path to blame.
+    fn best_blame_constraint(
+        &self,
+        mir: &Mir<'tcx>,
+        from_region: RegionVid,
+        target_test: impl Fn(RegionVid) -> bool,
+    ) -> (ConstraintCategory, Span) {
+        debug!("best_blame_constraint(from_region={:?})", from_region);
+
+        // Find all paths
+        let path = self
+            .find_constraint_paths_between_regions(from_region, target_test)
+            .unwrap();
+        debug!("best_blame_constraint: path={:#?}", path);
+
+        // Classify each of the constraints along the path.
+        let mut categorized_path: Vec<(ConstraintCategory, Span)> = path
+            .iter()
+            .map(|&index| self.classify_constraint(index, mir))
+            .collect();
+        debug!(
+            "best_blame_constraint: categorized_path={:?}",
+            categorized_path
+        );
+
+        // Find what appears to be the most interesting path to report to the user.
+        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
+        debug!("best_blame_constraint: sorted_path={:?}", categorized_path);
+
+        *categorized_path.first().unwrap()
+    }
+
     /// Walks the graph of constraints (where `'a: 'b` is considered
     /// an edge `'a -> 'b`) to find all paths from `from_region` to
     /// `to_region`. The paths are accumulated into the vector
@@ -89,7 +128,9 @@ fn find_constraint_paths_between_regions(
                 let mut p = r;
                 loop {
                     match context[p] {
-                        Trace::NotVisited => bug!("found unvisited region {:?} on path to {:?}", p, r),
+                        Trace::NotVisited => {
+                            bug!("found unvisited region {:?} on path to {:?}", p, r)
+                        }
                         Trace::FromConstraint(c) => {
                             result.push(c);
                             p = self.constraints[c].sup;
@@ -139,19 +180,24 @@ fn classify_constraint(
         &self,
         index: ConstraintIndex,
         mir: &Mir<'tcx>,
-        _infcx: &InferCtxt<'_, '_, 'tcx>,
     ) -> (ConstraintCategory, Span) {
         let constraint = self.constraints[index];
         debug!("classify_constraint: constraint={:?}", constraint);
         let span = constraint.locations.span(mir);
-        let location = constraint.locations.from_location().unwrap_or(Location::START);
+        let location = constraint
+            .locations
+            .from_location()
+            .unwrap_or(Location::START);
 
         if !self.constraint_is_interesting(index) {
             return (ConstraintCategory::Boring, span);
         }
 
         let data = &mir[location.block];
-        debug!("classify_constraint: location={:?} data={:?}", location, data);
+        debug!(
+            "classify_constraint: location={:?} data={:?}",
+            location, data
+        );
         let category = if location.statement_index == data.statements.len() {
             if let Some(ref terminator) = data.terminator {
                 debug!("classify_constraint: terminator.kind={:?}", terminator.kind);
@@ -174,8 +220,9 @@ fn classify_constraint(
                     } else {
                         match rvalue {
                             Rvalue::Cast(..) => ConstraintCategory::Cast,
-                            Rvalue::Use(..) |
-                            Rvalue::Aggregate(..) => ConstraintCategory::Assignment,
+                            Rvalue::Use(..) | Rvalue::Aggregate(..) => {
+                                ConstraintCategory::Assignment
+                            }
                             _ => ConstraintCategory::Other,
                         }
                     }
@@ -206,27 +253,12 @@ pub(super) fn report_error(
     ) {
         debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
 
-        // Find all paths
-        let path = self.find_constraint_paths_between_regions(fr, |r| r == outlived_fr).unwrap();
-        debug!("report_error: path={:#?}", path);
-
-        // Classify each of the constraints along the path.
-        let mut categorized_path: Vec<(ConstraintCategory, Span)> = path.iter()
-            .map(|&index| self.classify_constraint(index, mir, infcx))
-            .collect();
-        debug!("report_error: categorized_path={:?}", categorized_path);
-
-        // Find what appears to be the most interesting path to report to the user.
-        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
-        debug!("report_error: sorted_path={:?}", categorized_path);
-
-        // Get a span
-        let (category, span) = categorized_path.first().unwrap();
+        let (category, span) = self.best_blame_constraint(mir, fr, |r| r == outlived_fr);
 
         // Check if we can use one of the "nice region errors".
         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
             let tables = infcx.tcx.typeck_tables_of(mir_def_id);
-            let nice = NiceRegionError::new_from_span(infcx.tcx, *span, o, f, Some(tables));
+            let nice = NiceRegionError::new_from_span(infcx.tcx, span, o, f, Some(tables));
             if let Some(_error_reported) = nice.try_report() {
                 return;
             }
@@ -237,22 +269,36 @@ pub(super) fn report_error(
             self.universal_regions.is_local_free_region(fr),
             self.universal_regions.is_local_free_region(outlived_fr),
         ) {
-            (ConstraintCategory::Assignment, true, false) =>
-                &ConstraintCategory::AssignmentToUpvar,
-            (ConstraintCategory::CallArgument, true, false) =>
-                &ConstraintCategory::CallArgumentToUpvar,
+            (ConstraintCategory::Assignment, true, false) => ConstraintCategory::AssignmentToUpvar,
+            (ConstraintCategory::CallArgument, true, false) => {
+                ConstraintCategory::CallArgumentToUpvar
+            }
             (category, _, _) => category,
         };
 
         debug!("report_error: category={:?}", category);
         match category {
-            ConstraintCategory::AssignmentToUpvar |
-            ConstraintCategory::CallArgumentToUpvar =>
-                self.report_closure_error(
-                    mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer),
-            _ =>
-                self.report_general_error(
-                    mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer),
+            ConstraintCategory::AssignmentToUpvar | ConstraintCategory::CallArgumentToUpvar => self
+                .report_closure_error(
+                    mir,
+                    infcx,
+                    mir_def_id,
+                    fr,
+                    outlived_fr,
+                    category,
+                    span,
+                    errors_buffer,
+                ),
+            _ => self.report_general_error(
+                mir,
+                infcx,
+                mir_def_id,
+                fr,
+                outlived_fr,
+                category,
+                span,
+                errors_buffer,
+            ),
         }
     }
 
@@ -263,23 +309,31 @@ fn report_closure_error(
         mir_def_id: DefId,
         fr: RegionVid,
         outlived_fr: RegionVid,
-        category: &ConstraintCategory,
-        span: &Span,
+        category: ConstraintCategory,
+        span: Span,
         errors_buffer: &mut Vec<Diagnostic>,
     ) {
-        let fr_name_and_span  = self.get_var_name_and_span_for_region(
-            infcx.tcx, mir, fr);
-        let outlived_fr_name_and_span = self.get_var_name_and_span_for_region(
-            infcx.tcx, mir,outlived_fr);
+        let fr_name_and_span = self.get_var_name_and_span_for_region(infcx.tcx, mir, fr);
+        let outlived_fr_name_and_span =
+            self.get_var_name_and_span_for_region(infcx.tcx, mir, outlived_fr);
 
         if fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none() {
             return self.report_general_error(
-                mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer);
+                mir,
+                infcx,
+                mir_def_id,
+                fr,
+                outlived_fr,
+                category,
+                span,
+                errors_buffer,
+            );
         }
 
-        let mut diag = infcx.tcx.sess.struct_span_err(
-            *span, &format!("borrowed data escapes outside of closure"),
-        );
+        let mut diag = infcx
+            .tcx
+            .sess
+            .struct_span_err(span, &format!("borrowed data escapes outside of closure"));
 
         if let Some((outlived_fr_name, outlived_fr_span)) = outlived_fr_name_and_span {
             if let Some(name) = outlived_fr_name {
@@ -294,10 +348,13 @@ fn report_closure_error(
             if let Some(name) = fr_name {
                 diag.span_label(
                     fr_span,
-                    format!("`{}` is a reference that is only valid in the closure body", name),
+                    format!(
+                        "`{}` is a reference that is only valid in the closure body",
+                        name
+                    ),
                 );
 
-                diag.span_label(*span, format!("`{}` escapes the closure body here", name));
+                diag.span_label(span, format!("`{}` escapes the closure body here", name));
             }
         }
 
@@ -311,24 +368,27 @@ fn report_general_error(
         mir_def_id: DefId,
         fr: RegionVid,
         outlived_fr: RegionVid,
-        category: &ConstraintCategory,
-        span: &Span,
+        category: ConstraintCategory,
+        span: Span,
         errors_buffer: &mut Vec<Diagnostic>,
     ) {
         let mut diag = infcx.tcx.sess.struct_span_err(
-            *span, &format!("unsatisfied lifetime constraints"), // FIXME
+            span,
+            &format!("unsatisfied lifetime constraints"), // FIXME
         );
 
         let counter = &mut 1;
-        let fr_name = self.give_region_a_name(
-            infcx.tcx, mir, mir_def_id, fr, counter, &mut diag);
-        let outlived_fr_name = self.give_region_a_name(
-            infcx.tcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
-
-        diag.span_label(*span, format!(
-            "{} requires that `{}` must outlive `{}`",
-            category, fr_name, outlived_fr_name,
-        ));
+        let fr_name = self.give_region_a_name(infcx.tcx, mir, mir_def_id, fr, counter, &mut diag);
+        let outlived_fr_name =
+            self.give_region_a_name(infcx.tcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
+
+        diag.span_label(
+            span,
+            format!(
+                "{} requires that `{}` must outlive `{}`",
+                category, fr_name, outlived_fr_name,
+            ),
+        );
 
         diag.buffer(errors_buffer);
     }