about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2018-07-23 16:26:33 +0200
committerDavid Wood <david@davidtw.co>2018-07-27 11:18:11 +0200
commitd4be95f0ffb46c752293c951eeebebdadd336180 (patch)
tree5ee1fb98247a8401d7958ee4bbfe92b58d8d87bd
parent53dda8e915e54bc65b41599738245d62dbe3e6df (diff)
downloadrust-d4be95f0ffb46c752293c951eeebebdadd336180.tar.gz
rust-d4be95f0ffb46c752293c951eeebebdadd336180.zip
Improved fully elaborated type generation to replace `'_#2r`-style regions.
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs5
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs47
2 files changed, 39 insertions, 13 deletions
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
index 7ba1e50cef3..cef6ab311a3 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
@@ -321,8 +321,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
                fr_is_local, outlived_fr_is_local, category);
 
-        match (fr_is_local, outlived_fr_is_local) {
-            (true, false) =>
+        match (category, fr_is_local, outlived_fr_is_local) {
+            (ConstraintCategory::Assignment, true, false) |
+            (ConstraintCategory::CallArgument, true, false) =>
                 self.report_escapes_closure_error(mir, infcx, mir_def_id, fr, outlived_fr,
                                                   category, span, errors_buffer),
             _ =>
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
index 05ac130f000..6c400278b70 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
@@ -146,6 +146,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index];
         if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument(
             infcx,
+            mir,
             mir_def_id,
             fr,
             arg_ty,
@@ -172,6 +173,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn give_name_if_we_can_match_hir_ty_from_argument(
         &self,
         infcx: &InferCtxt<'_, '_, 'tcx>,
+        mir: &Mir<'tcx>,
         mir_def_id: DefId,
         needle_fr: RegionVid,
         argument_ty: Ty<'tcx>,
@@ -188,8 +190,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // must highlight the variable.
             hir::TyKind::Infer => self.give_name_if_we_cannot_match_hir_ty(
                 infcx,
+                mir,
+                needle_fr,
                 argument_ty,
-                argument_hir_ty,
                 counter,
                 diag,
             ),
@@ -219,24 +222,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn give_name_if_we_cannot_match_hir_ty(
         &self,
         infcx: &InferCtxt<'_, '_, 'tcx>,
+        mir: &Mir<'tcx>,
+        needle_fr: RegionVid,
         argument_ty: Ty<'tcx>,
-        argument_hir_ty: &hir::Ty,
         counter: &mut usize,
         diag: &mut DiagnosticBuilder<'_>,
     ) -> Option<InternedString> {
         let mut type_name = infcx.extract_type_name(&argument_ty);
-
-        type_name.find("&").map(|index| {
+        let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?;
+        let mut first_region_name = None;
+
+        debug!("give_name_if_we_cannot_match_hir_ty: type_name={:?}", type_name);
+        while let Some(start_index) = type_name.find("&'_#") {
+            if let Some(end_index) = type_name[start_index..].find(' ') {
+                // Need to make the `end_index` relative to the full string.
+                let end_index = start_index + end_index;
+                // `start_index + 1` skips the `&`.
+                // `end_index` goes until the space after the region.
+                type_name.replace_range(start_index + 1..end_index, "");
+            }
+        }
+        debug!("give_name_if_we_cannot_match_hir_ty: type_name={:?}", type_name);
+
+        let mut index = 0;
+        while let Some(next_index) = type_name[index..].find("&") {
+            // At this point, next_index is the index of the `&` character (starting from
+            // the last `&` character).
+            debug!("give_name_if_we_cannot_match_hir_ty: start-of-loop index={:?} type_name={:?}",
+                   index, type_name);
             let region_name = self.synthesize_region_name(counter).as_str();
-            type_name.insert_str(index + 1, &format!("{} ", region_name));
+            if first_region_name.is_none() { first_region_name = Some(region_name); }
+
+            // Compute the index of the character after `&` in the original string.
+            index = next_index + index + 1;
+            type_name.insert_str(index, &format!("{}", region_name));
+        }
 
-            diag.span_label(
-                argument_hir_ty.span,
-                format!("has type `{}`", type_name),
-            );
+        let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index);
+        diag.span_label(span, format!("has type `{}`", type_name));
 
-            region_name.as_interned_str()
-        })
+        first_region_name.map(|s| s.as_interned_str())
     }
 
     /// Attempts to highlight the specific part of a type annotation