about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2018-07-26 12:29:58 +0200
committerDavid Wood <david@davidtw.co>2018-07-27 13:00:56 +0200
commitf44807ae1ec15c983586077b53445bb45f083327 (patch)
tree2d31a269b839df0001a8b48baaf0bf9f29538c5e
parentb377e7bbfbf584de4c1a775fd41b957cbd2e057b (diff)
downloadrust-f44807ae1ec15c983586077b53445bb45f083327.tar.gz
rust-f44807ae1ec15c983586077b53445bb45f083327.zip
Improved mechanism for naming regions in non-annotated types.
-rw-r--r--src/librustc/util/ppaux.rs40
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs56
-rw-r--r--src/test/ui/issue-52533-1.nll.stderr17
-rw-r--r--src/test/ui/issue-52533-1.rs21
-rw-r--r--src/test/ui/issue-52533-1.stderr22
-rw-r--r--src/test/ui/nll/closure-requirements/escape-argument-callee.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr6
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr6
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr6
9 files changed, 127 insertions, 49 deletions
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index c67453d2b20..15b5edaa3d5 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -19,7 +19,7 @@ use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
 use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
 use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, TyAnon};
 use ty::{TyDynamic, TyInt, TyUint, TyInfer};
-use ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
+use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
 use util::nodemap::FxHashSet;
 
 use std::cell::Cell;
@@ -32,6 +32,12 @@ use syntax::ast::CRATE_NODE_ID;
 use syntax::symbol::{Symbol, InternedString};
 use hir;
 
+thread_local! {
+    /// Mechanism for highlighting of specific regions for display in NLL region inference errors.
+    /// Contains region to highlight and counter for number to use when highlighting.
+    static HIGHLIGHT_REGION: Cell<Option<(RegionVid, usize)>> = Cell::new(None)
+}
+
 macro_rules! gen_display_debug_body {
     ( $with:path ) => {
         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -562,6 +568,19 @@ pub fn parameterized<F: fmt::Write>(f: &mut F,
     PrintContext::new().parameterized(f, substs, did, projections)
 }
 
+fn get_highlight_region() -> Option<(RegionVid, usize)> {
+    HIGHLIGHT_REGION.with(|hr| hr.get())
+}
+
+pub fn with_highlight_region<R>(r: RegionVid, counter: usize, op: impl FnOnce() -> R) -> R {
+    HIGHLIGHT_REGION.with(|hr| {
+        assert_eq!(hr.get(), None);
+        hr.set(Some((r, counter)));
+        let r = op();
+        hr.set(None);
+        r
+    })
+}
 
 impl<'a, T: Print> Print for &'a T {
     fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
@@ -733,7 +752,7 @@ define_print! {
 define_print! {
     () ty::RegionKind, (self, f, cx) {
         display {
-            if cx.is_verbose {
+            if cx.is_verbose || get_highlight_region().is_some() {
                 return self.print_debug(f, cx);
             }
 
@@ -905,6 +924,15 @@ impl fmt::Debug for ty::FloatVid {
 
 impl fmt::Debug for ty::RegionVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if let Some((region, counter)) = get_highlight_region() {
+            debug!("RegionVid.fmt: region={:?} self={:?} counter={:?}", region, self, counter);
+            return if *self == region {
+                write!(f, "'{:?}", counter)
+            } else {
+                write!(f, "'_")
+            }
+        }
+
         write!(f, "'_#{}r", self.index())
     }
 }
@@ -1022,9 +1050,11 @@ define_print! {
                 TyRef(r, ty, mutbl) => {
                     write!(f, "&")?;
                     let s = r.print_to_string(cx);
-                    write!(f, "{}", s)?;
-                    if !s.is_empty() {
-                        write!(f, " ")?;
+                    if s != "'_" {
+                        write!(f, "{}", s)?;
+                        if !s.is_empty() {
+                            write!(f, " ")?;
+                        }
                     }
                     ty::TypeAndMut { ty, mutbl }.print(f, cx)
                 }
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 f3b437c38d8..8505d8e1ef3 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
@@ -16,6 +16,7 @@ use rustc::infer::InferCtxt;
 use rustc::mir::Mir;
 use rustc::ty::subst::{Substs, UnpackedKind};
 use rustc::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc::util::ppaux::with_highlight_region;
 use rustc_errors::DiagnosticBuilder;
 use syntax::ast::Name;
 use syntax::symbol::keywords;
@@ -228,40 +229,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         counter: &mut usize,
         diag: &mut DiagnosticBuilder<'_>,
     ) -> Option<InternedString> {
-        let mut type_name = infcx.extract_type_name(&argument_ty);
-        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 + 1` goes to (including) the space after the region.
-                type_name.replace_range(start_index + 1..end_index + 1, "");
-            }
-        }
-        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();
-            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));
-        }
-
-        let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index);
-        diag.span_label(span, format!("has type `{}`", type_name));
-
-        first_region_name.map(|s| s.as_interned_str())
+        let type_name = with_highlight_region(needle_fr, *counter, || {
+            infcx.extract_type_name(&argument_ty)
+        });
+
+        debug!("give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
+               type_name, needle_fr);
+        let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
+            // Only add a label if we can confirm that a region was labelled.
+            let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?;
+            let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index);
+            diag.span_label(span, format!("has type `{}`", type_name));
+
+            // This counter value will already have been used, so this function will increment it
+            // so the next value will be used next and return the region name that would have been
+            // used.
+            Some(self.synthesize_region_name(counter))
+        } else {
+            None
+        };
+
+        assigned_region_name
     }
 
     /// Attempts to highlight the specific part of a type annotation
diff --git a/src/test/ui/issue-52533-1.nll.stderr b/src/test/ui/issue-52533-1.nll.stderr
new file mode 100644
index 00000000000..87fda1dd99c
--- /dev/null
+++ b/src/test/ui/issue-52533-1.nll.stderr
@@ -0,0 +1,17 @@
+warning: not reporting region error due to nll
+  --> $DIR/issue-52533-1.rs:19:18
+   |
+LL |     gimme(|x, y| y)
+   |                  ^
+
+error: unsatisfied lifetime constraints
+  --> $DIR/issue-52533-1.rs:19:18
+   |
+LL |     gimme(|x, y| y)
+   |            -  -  ^ closure was supposed to return data with lifetime `'1` but it is returning data with lifetime `'2`
+   |            |  |
+   |            |  has type `&Foo<'_, '1, u32>`
+   |            has type `&Foo<'_, '2, u32>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issue-52533-1.rs b/src/test/ui/issue-52533-1.rs
new file mode 100644
index 00000000000..22af5a86702
--- /dev/null
+++ b/src/test/ui/issue-52533-1.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(warnings)]
+
+struct Foo<'a, 'b, T: 'a + 'b> { x: &'a T, y: &'b T }
+
+fn gimme(_: impl for<'a, 'b, 'c> FnOnce(&'a Foo<'a, 'b, u32>,
+                                        &'a Foo<'a, 'c, u32>) -> &'a Foo<'a, 'b, u32>) { }
+
+fn main() {
+    gimme(|x, y| y)
+    //~^ ERROR mismatched types [E0308]
+}
diff --git a/src/test/ui/issue-52533-1.stderr b/src/test/ui/issue-52533-1.stderr
new file mode 100644
index 00000000000..38deb7d66de
--- /dev/null
+++ b/src/test/ui/issue-52533-1.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-52533-1.rs:19:18
+   |
+LL |     gimme(|x, y| y)
+   |                  ^ lifetime mismatch
+   |
+   = note: expected type `&Foo<'_, '_, u32>`
+              found type `&Foo<'_, '_, u32>`
+note: the anonymous lifetime #4 defined on the body at 19:11...
+  --> $DIR/issue-52533-1.rs:19:11
+   |
+LL |     gimme(|x, y| y)
+   |           ^^^^^^^^
+note: ...does not necessarily outlive the anonymous lifetime #3 defined on the body at 19:11
+  --> $DIR/issue-52533-1.rs:19:11
+   |
+LL |     gimme(|x, y| y)
+   |           ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
index c7fdbe1685c..99da2141ce9 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -11,7 +11,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    |                                       -  -  ^^^^^^ free region requires that `'1` must outlive `'2`
    |                                       |  |
    |                                       |  has type `&'1 i32`
-   |                                       has type `&'2 mut &'3 i32`
+   |                                       has type `&mut &'2 i32`
 
 note: No external requirements
   --> $DIR/escape-argument-callee.rs:36:38
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
index 6882b08f330..b4508824901 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -8,12 +8,12 @@ error: unsatisfied lifetime constraints
   --> $DIR/propagate-approximated-fail-no-postdom.rs:57:13
    |
 LL |         |_outlives1, _outlives2, _outlives3, x, y| {
-   |          ----------              ---------- has type `std::cell::Cell<&'3 &'4 u32>`
+   |          ----------              ---------- has type `std::cell::Cell<&'2 &u32>`
    |          |
-   |          has type `std::cell::Cell<&'1 &'2 u32>`
+   |          has type `std::cell::Cell<&&'1 u32>`
 ...
 LL |             demand_y(x, y, p) //~ ERROR
-   |             ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'3`
+   |             ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
 
 note: No external requirements
   --> $DIR/propagate-approximated-fail-no-postdom.rs:53:9
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index 771d1df2df0..40ebda4419b 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -8,12 +8,12 @@ error: unsatisfied lifetime constraints
   --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9
    |
 LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-   |                                                ---------  - has type `&'1 std::cell::Cell<&'2 u32>`
+   |                                                ---------  - has type `&std::cell::Cell<&'1 u32>`
    |                                                |
-   |                                                has type `&'3 std::cell::Cell<&'4 &'5 u32>`
+   |                                                has type `&std::cell::Cell<&'2 &u32>`
 LL |         // Only works if 'x: 'y:
 LL |         demand_y(x, y, x.get())
-   |         ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'3`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
 
 note: No external requirements
   --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
index 1ac52e5e560..37ea6103976 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -8,12 +8,12 @@ error: unsatisfied lifetime constraints
   --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:9
    |
 LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-   |                                                ----------  ---------- has type `&'4 std::cell::Cell<&'5 &'6 u32>`
+   |                                                ----------  ---------- has type `&std::cell::Cell<&'2 &u32>`
    |                                                |
-   |                                                has type `&'1 std::cell::Cell<&'2 &'3 u32>`
+   |                                                has type `&std::cell::Cell<&'1 &u32>`
 LL |         // Only works if 'x: 'y:
 LL |         demand_y(x, y, x.get())
-   |         ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'4`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
 
 note: No external requirements
   --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:49:47