From 5ddda3f19551ce299af426756661f8dcdf3ccde6 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Mon, 4 Jun 2018 08:53:34 -0400
Subject: [PATCH 01/15] rename `ToLocations` to `NormalizeLocation`

---
 src/librustc_mir/borrow_check/nll/type_check/mod.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 611050a406020..b1ccee340bc6b 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -1614,7 +1614,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn normalize<T>(&mut self, value: T, location: impl ToLocations) -> T
+    fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
     where
         T: type_op::normalize::Normalizable<'gcx, 'tcx> + Copy,
     {
@@ -1701,17 +1701,17 @@ impl AtLocation for Location {
     }
 }
 
-trait ToLocations: fmt::Debug + Copy {
+trait NormalizeLocation: fmt::Debug + Copy {
     fn to_locations(self) -> Locations;
 }
 
-impl ToLocations for Locations {
+impl NormalizeLocation for Locations {
     fn to_locations(self) -> Locations {
         self
     }
 }
 
-impl ToLocations for Location {
+impl NormalizeLocation for Location {
     fn to_locations(self) -> Locations {
         self.at_self()
     }

From dbeda5ee29ddfd9195f540860020afd1a628bde2 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Mon, 4 Jun 2018 09:29:36 -0400
Subject: [PATCH 02/15] remove the `at_location` from Locations

We are not currently using it for anything; even polonius just uses
the `from_location`.
---
 .../borrow_check/nll/constraint_generation.rs |  1 -
 .../borrow_check/nll/constraint_set.rs        | 12 ++--
 .../borrow_check/nll/region_infer/dump_mir.rs |  4 +-
 .../borrow_check/nll/region_infer/graphviz.rs |  2 +-
 .../borrow_check/nll/region_infer/mod.rs      | 22 +++----
 .../nll/type_check/constraint_conversion.rs   |  4 +-
 .../borrow_check/nll/type_check/mod.rs        | 61 ++-----------------
 7 files changed, 20 insertions(+), 86 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 72db9f8da9872..6e9574e2d5b73 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -315,7 +315,6 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
                                 span,
                                 ref_region.to_region_vid(),
                                 borrow_region.to_region_vid(),
-                                location.successor_within_block(),
                             );
 
                             if let Some(all_facts) = self.all_facts {
diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs
index 4c6e445293d54..ac3ab961d0a15 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_set.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::mir::Location;
 use rustc::ty::RegionVid;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 
@@ -24,8 +23,8 @@ crate struct ConstraintSet {
 impl ConstraintSet {
     pub fn push(&mut self, constraint: OutlivesConstraint) {
         debug!(
-            "add_outlives({:?}: {:?} @ {:?}",
-            constraint.sup, constraint.sub, constraint.point
+            "add_outlives({:?}: {:?})",
+            constraint.sup, constraint.sub
         );
         if constraint.sup == constraint.sub {
             // 'a: 'a is pretty uninteresting
@@ -86,9 +85,6 @@ pub struct OutlivesConstraint {
     /// Region that must be outlived.
     pub sub: RegionVid,
 
-    /// At this location.
-    pub point: Location,
-
     /// Later on, we thread the constraints onto a linked list
     /// grouped by their `sub` field. So if you had:
     ///
@@ -107,8 +103,8 @@ impl fmt::Debug for OutlivesConstraint {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         write!(
             formatter,
-            "({:?}: {:?} @ {:?}) due to {:?}",
-            self.sup, self.sub, self.point, self.span
+            "({:?}: {:?}) due to {:?}",
+            self.sup, self.sub, self.span
         )
     }
 }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
index 6c796ea4c73ab..c68bb15552fc7 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
@@ -82,15 +82,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             let OutlivesConstraint {
                 sup,
                 sub,
-                point,
                 span,
                 next: _,
             } = constraint;
             with_msg(&format!(
-                "{:?}: {:?} @ {:?} due to {:?}",
+                "{:?}: {:?} due to {:?}",
                 sup,
                 sub,
-                point,
                 span
             ))?;
         }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
index 106dd003ceab9..15896413af991 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
@@ -44,7 +44,7 @@ impl<'this, 'tcx> dot::Labeller<'this> for RegionInferenceContext<'tcx> {
         dot::LabelText::LabelStr(format!("{:?}", n).into_cow())
     }
     fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
-        dot::LabelText::LabelStr(format!("{:?}", e.point).into_cow())
+        dot::LabelText::LabelStr(format!("{:?}", e.span).into_cow())
     }
 }
 
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index a576dc5f7f47b..fd8a62b4deb33 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -359,14 +359,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         span: Span,
         sup: RegionVid,
         sub: RegionVid,
-        point: Location,
     ) {
         assert!(self.inferred_values.is_none(), "values already inferred");
         self.constraints.push(OutlivesConstraint {
             span,
             sup,
             sub,
-            point,
             next: None,
         })
     }
@@ -503,7 +501,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         for type_test in &self.type_tests {
             debug!("check_type_test: {:?}", type_test);
 
-            if self.eval_region_test(mir, type_test.point, type_test.lower_bound, &type_test.test) {
+            if self.eval_region_test(mir, type_test.lower_bound, &type_test.test) {
                 continue;
             }
 
@@ -765,31 +763,30 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn eval_region_test(
         &self,
         mir: &Mir<'tcx>,
-        point: Location,
         lower_bound: RegionVid,
         test: &RegionTest,
     ) -> bool {
         debug!(
-            "eval_region_test(point={:?}, lower_bound={:?}, test={:?})",
-            point, lower_bound, test
+            "eval_region_test(lower_bound={:?}, test={:?})",
+            lower_bound, test
         );
 
         match test {
             RegionTest::IsOutlivedByAllRegionsIn(regions) => regions
                 .iter()
-                .all(|&r| self.eval_outlives(mir, r, lower_bound, point)),
+                .all(|&r| self.eval_outlives(mir, r, lower_bound)),
 
             RegionTest::IsOutlivedByAnyRegionIn(regions) => regions
                 .iter()
-                .any(|&r| self.eval_outlives(mir, r, lower_bound, point)),
+                .any(|&r| self.eval_outlives(mir, r, lower_bound)),
 
             RegionTest::Any(tests) => tests
                 .iter()
-                .any(|test| self.eval_region_test(mir, point, lower_bound, test)),
+                .any(|test| self.eval_region_test(mir, lower_bound, test)),
 
             RegionTest::All(tests) => tests
                 .iter()
-                .all(|test| self.eval_region_test(mir, point, lower_bound, test)),
+                .all(|test| self.eval_region_test(mir, lower_bound, test)),
         }
     }
 
@@ -799,11 +796,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         _mir: &Mir<'tcx>,
         sup_region: RegionVid,
         sub_region: RegionVid,
-        point: Location,
     ) -> bool {
         debug!(
-            "eval_outlives({:?}: {:?} @ {:?})",
-            sup_region, sub_region, point
+            "eval_outlives({:?}: {:?})",
+            sup_region, sub_region
         );
 
         let inferred_values = self
diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
index 3100df3e8f629..2ee74dc6095fa 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
@@ -146,7 +146,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     ) -> TypeTest<'tcx> {
         let lower_bound = self.to_region_vid(region);
 
-        let point = self.locations.at_location().unwrap_or(Location::START);
+        let point = self.locations.from_location().unwrap_or(Location::START);
 
         let test = self.verify_bound_to_region_test(&bound);
 
@@ -197,13 +197,11 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
 
     fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
         let span = self.span();
-        let point = self.locations.at_location().unwrap_or(Location::START);
 
         self.outlives_constraints.push(OutlivesConstraint {
             span,
             sub,
             sup,
-            point,
             next: None,
         });
     }
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index b1ccee340bc6b..da12ce89f9d68 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -671,11 +671,6 @@ pub enum Locations {
         /// This is intended for error reporting and diagnosis; the
         /// constraints may *take effect* at a distinct spot.
         from_location: Location,
-
-        /// The constraints must be met at this location. In terms of the
-        /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
-        /// is the `P` value.
-        at_location: Location,
     },
 }
 
@@ -686,13 +681,6 @@ impl Locations {
             Locations::Pair { from_location, .. } => Some(*from_location),
         }
     }
-
-    pub fn at_location(&self) -> Option<Location> {
-        match self {
-            Locations::All => None,
-            Locations::Pair { at_location, .. } => Some(*at_location),
-        }
-    }
 }
 
 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
@@ -799,9 +787,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             StatementKind::Assign(ref place, ref rv) => {
                 let place_ty = place.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = rv.ty(mir, tcx);
-                if let Err(terr) =
-                    self.sub_types(rv_ty, place_ty, location.at_successor_within_block())
-                {
+                if let Err(terr) = self.sub_types(rv_ty, place_ty, location.at_self()) {
                     span_mirbug!(
                         self,
                         stmt,
@@ -897,15 +883,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             TerminatorKind::DropAndReplace {
                 ref location,
                 ref value,
-                target,
-                unwind,
+                target: _,
+                unwind: _,
             } => {
                 let place_ty = location.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = value.ty(mir, tcx);
 
                 let locations = Locations::Pair {
                     from_location: term_location,
-                    at_location: target.start_location(),
                 };
                 if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
                     span_mirbug!(
@@ -917,26 +902,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         terr
                     );
                 }
-
-                // Subtle: this assignment occurs at the start of
-                // *both* blocks, so we need to ensure that it holds
-                // at both locations.
-                if let Some(unwind) = unwind {
-                    let locations = Locations::Pair {
-                        from_location: term_location,
-                        at_location: unwind.start_location(),
-                    };
-                    if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
-                        span_mirbug!(
-                            self,
-                            term,
-                            "bad DropAndReplace ({:?} = {:?}): {:?}",
-                            place_ty,
-                            rv_ty,
-                            terr
-                        );
-                    }
-                }
             }
             TerminatorKind::SwitchInt {
                 ref discr,
@@ -1052,11 +1017,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     ) {
         let tcx = self.tcx();
         match *destination {
-            Some((ref dest, target_block)) => {
+            Some((ref dest, _target_block)) => {
                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
                 let locations = Locations::Pair {
                     from_location: term_location,
-                    at_location: target_block.start_location(),
                 };
                 if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) {
                     span_mirbug!(
@@ -1674,29 +1638,12 @@ trait AtLocation {
     /// indicated by `self`. This is typically used when processing
     /// "inputs" to the given location.
     fn at_self(self) -> Locations;
-
-    /// Creates a `Locations` where `self` is the from-location and
-    /// its successor within the block is the at-location. This means
-    /// that any required region relationships must hold only upon
-    /// **exiting** the statement/terminator indicated by `self`. This
-    /// is for example used when you have a `place = rv` statement: it
-    /// indicates that the `typeof(rv) <: typeof(place)` as of the
-    /// **next** statement.
-    fn at_successor_within_block(self) -> Locations;
 }
 
 impl AtLocation for Location {
     fn at_self(self) -> Locations {
         Locations::Pair {
             from_location: self,
-            at_location: self,
-        }
-    }
-
-    fn at_successor_within_block(self) -> Locations {
-        Locations::Pair {
-            from_location: self,
-            at_location: self.successor_within_block(),
         }
     }
 }

From 609bb27514fe71f08040aef1eb8a7acd098e9185 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Mon, 4 Jun 2018 11:19:43 -0400
Subject: [PATCH 03/15] categorize `Locations` as interesting or boring

---
 .../borrow_check/nll/type_check/liveness.rs   |  2 +-
 .../borrow_check/nll/type_check/mod.rs        | 90 ++++++++++---------
 2 files changed, 48 insertions(+), 44 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
index f27de92c6215a..d84dcc5678279 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
@@ -199,7 +199,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
         });
 
         if let Some(data) = &drop_data.region_constraint_data {
-            self.cx.push_region_constraints(location.at_self(), data);
+            self.cx.push_region_constraints(location.boring(), data);
         }
 
         drop_data.dropck_result.report_overflows(
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index da12ce89f9d68..404e04ef4ccef 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -288,7 +288,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                         tcx.predicates_of(def_id).instantiate(tcx, substs);
                     type_checker.normalize_and_prove_instantiated_predicates(
                         instantiated_predicates,
-                        location,
+                        location.boring(),
                     );
                 }
 
@@ -313,10 +313,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
 
         debug!("sanitize_constant: expected_ty={:?}", expected_ty);
 
-        if let Err(terr) = self
-            .cx
-            .eq_types(expected_ty, constant.ty, location.at_self())
-        {
+        if let Err(terr) = self.cx.eq_types(expected_ty, constant.ty, location.boring()) {
             span_mirbug!(
                 self,
                 constant,
@@ -346,7 +343,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                 let sty = self.sanitize_type(place, sty);
                 let ty = self.tcx().type_of(def_id);
                 let ty = self.cx.normalize(ty, location);
-                if let Err(terr) = self.cx.eq_types(ty, sty, location.at_self()) {
+                if let Err(terr) = self.cx.eq_types(ty, sty, location.boring()) {
                     span_mirbug!(
                         self,
                         place,
@@ -390,7 +387,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
             // fully apply: in effect, the rule is that if a value of some type could implement
             // Copy, then it must.
-            self.cx.prove_trait_ref(trait_ref, location);
+            self.cx.prove_trait_ref(trait_ref, location.interesting());
         }
         place_ty
     }
@@ -489,7 +486,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             ProjectionElem::Field(field, fty) => {
                 let fty = self.sanitize_type(place, fty);
                 match self.field_ty(place, base, field, location) {
-                    Ok(ty) => if let Err(terr) = self.cx.eq_types(ty, fty, location.at_self()) {
+                    Ok(ty) => if let Err(terr) = self.cx.eq_types(ty, fty, location.boring()) {
                         span_mirbug!(
                             self,
                             place,
@@ -787,7 +784,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             StatementKind::Assign(ref place, ref rv) => {
                 let place_ty = place.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = rv.ty(mir, tcx);
-                if let Err(terr) = self.sub_types(rv_ty, place_ty, location.at_self()) {
+                if let Err(terr) = self.sub_types(rv_ty, place_ty, location.interesting()) {
                     span_mirbug!(
                         self,
                         stmt,
@@ -802,7 +799,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     def_id: tcx.lang_items().sized_trait().unwrap(),
                     substs: tcx.mk_substs_trait(place_ty, &[]),
                 };
-                self.prove_trait_ref(trait_ref, location);
+                self.prove_trait_ref(trait_ref, location.interesting());
             }
             StatementKind::SetDiscriminant {
                 ref place,
@@ -909,7 +906,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 ..
             } => {
                 let discr_ty = discr.ty(mir, tcx);
-                if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.at_self()) {
+                if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.boring()) {
                     span_mirbug!(
                         self,
                         term,
@@ -949,7 +946,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
                 self.prove_predicates(
                     sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)),
-                    term_location,
+                    term_location.boring(),
                 );
 
                 // The ordinary liveness rules will ensure that all
@@ -991,7 +988,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 match mir.yield_ty {
                     None => span_mirbug!(self, term, "yield in non-generator"),
                     Some(ty) => {
-                        if let Err(terr) = self.sub_types(value_ty, ty, term_location.at_self()) {
+                        if let Err(terr) = self.sub_types(value_ty, ty, term_location.interesting()) {
                             span_mirbug!(
                                 self,
                                 term,
@@ -1056,7 +1053,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
         for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
             let op_arg_ty = op_arg.ty(mir, self.tcx());
-            if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.at_self()) {
+            if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.interesting()) {
                 span_mirbug!(
                     self,
                     term,
@@ -1284,7 +1281,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     substs: tcx.mk_substs_trait(operand_ty, &[]),
                 };
 
-                self.prove_trait_ref(trait_ref, location);
+                self.prove_trait_ref(trait_ref, location.interesting());
             },
 
             Rvalue::NullaryOp(_, ty) => {
@@ -1293,7 +1290,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     substs: tcx.mk_substs_trait(ty, &[]),
                 };
 
-                self.prove_trait_ref(trait_ref, location);
+                self.prove_trait_ref(trait_ref, location.interesting());
             }
 
             Rvalue::Cast(cast_kind, op, ty) => match cast_kind {
@@ -1309,7 +1306,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
                     let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
 
-                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
+                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) {
                         span_mirbug!(
                             self,
                             rvalue,
@@ -1330,7 +1327,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     };
                     let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig);
 
-                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
+                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) {
                         span_mirbug!(
                             self,
                             rvalue,
@@ -1354,7 +1351,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
                     let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
 
-                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
+                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) {
                         span_mirbug!(
                             self,
                             rvalue,
@@ -1373,7 +1370,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty.into()]),
                     };
 
-                    self.prove_trait_ref(trait_ref, location);
+                    self.prove_trait_ref(trait_ref, location.interesting());
                 }
 
                 CastKind::Misc => {}
@@ -1422,7 +1419,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 }
             };
             let operand_ty = operand.ty(mir, tcx);
-            if let Err(terr) = self.sub_types(operand_ty, field_ty, location.at_self()) {
+
+            if let Err(terr) = self.sub_types(operand_ty, field_ty, location.boring()) {
                 span_mirbug!(
                     self,
                     rvalue,
@@ -1483,8 +1481,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         *substs,
                     );
 
+                    // Hmm, are these constraints *really* boring?
                     self.push_region_constraints(
-                        location.at_self(),
+                        location.boring(),
                         &closure_constraints,
                     );
                 }
@@ -1499,53 +1498,53 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
         };
 
-        self.normalize_and_prove_instantiated_predicates(instantiated_predicates, location);
+        self.normalize_and_prove_instantiated_predicates(instantiated_predicates, location.boring());
     }
 
-    fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) {
+    fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations) {
         self.prove_predicates(
             Some(ty::Predicate::Trait(
                 trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
             )),
-            location,
+            locations,
         );
     }
 
     fn normalize_and_prove_instantiated_predicates(
         &mut self,
         instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
-        location: Location,
+        locations: Locations,
     ) {
         for predicate in instantiated_predicates.predicates {
-            let predicate = self.normalize(predicate, location);
-            self.prove_predicate(predicate, location);
+            let predicate = self.normalize(predicate, locations);
+            self.prove_predicate(predicate, locations);
         }
     }
 
     fn prove_predicates(
         &mut self,
         predicates: impl IntoIterator<Item = ty::Predicate<'tcx>>,
-        location: Location,
+        locations: Locations,
     ) {
         for predicate in predicates {
             debug!(
-                "prove_predicates(predicate={:?}, location={:?})",
-                predicate, location,
+                "prove_predicates(predicate={:?}, locations={:?})",
+                predicate, locations,
             );
 
-            self.prove_predicate(predicate, location);
+            self.prove_predicate(predicate, locations);
         }
     }
 
-    fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, location: Location) {
+    fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, locations: Locations) {
         debug!(
             "prove_predicate(predicate={:?}, location={:?})",
-            predicate, location,
+            predicate, locations,
         );
 
         let param_env = self.param_env;
         self.fully_perform_op(
-            location.at_self(),
+            locations,
             param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
         ).unwrap_or_else(|NoSolution| {
             span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
@@ -1632,20 +1631,25 @@ impl MirPass for TypeckMir {
 }
 
 trait AtLocation {
-    /// Creates a `Locations` where `self` is both the from-location
-    /// and the at-location. This means that any required region
-    /// relationships must hold upon entering the statement/terminator
-    /// indicated by `self`. This is typically used when processing
-    /// "inputs" to the given location.
-    fn at_self(self) -> Locations;
+    /// Indicates a "boring" constraint that the user probably
+    /// woudln't want to see highlights.
+    fn boring(self) -> Locations;
+
+    /// Indicates an "interesting" edge, which is of significance only
+    /// for diagnostics.
+    fn interesting(self) -> Locations;
 }
 
 impl AtLocation for Location {
-    fn at_self(self) -> Locations {
+    fn boring(self) -> Locations {
         Locations::Pair {
             from_location: self,
         }
     }
+
+    fn interesting(self) -> Locations {
+        self.boring()
+    }
 }
 
 trait NormalizeLocation: fmt::Debug + Copy {
@@ -1660,6 +1664,6 @@ impl NormalizeLocation for Locations {
 
 impl NormalizeLocation for Location {
     fn to_locations(self) -> Locations {
-        self.at_self()
+        self.boring()
     }
 }

From 0b620186fdac2a8a671d445ac25ef33d1df44153 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Mon, 4 Jun 2018 12:25:12 -0400
Subject: [PATCH 04/15] propagate boring vs interesting causal info for
 constraints/tests

---
 .../borrow_check/nll/constraint_generation.rs |  6 +-
 .../borrow_check/nll/constraint_set.rs        | 10 +--
 .../borrow_check/nll/region_infer/dump_mir.rs |  4 +-
 .../borrow_check/nll/region_infer/graphviz.rs |  2 +-
 .../borrow_check/nll/region_infer/mod.rs      | 33 +++++-----
 .../nll/type_check/constraint_conversion.rs   | 26 ++------
 .../borrow_check/nll/type_check/mod.rs        | 61 +++++++++++--------
 7 files changed, 70 insertions(+), 72 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 6e9574e2d5b73..68aa9aeabf811 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -10,9 +10,10 @@
 
 use borrow_check::borrow_set::BorrowSet;
 use borrow_check::location::LocationTable;
+use borrow_check::nll::ToRegionVid;
 use borrow_check::nll::facts::AllFacts;
 use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
-use borrow_check::nll::ToRegionVid;
+use borrow_check::nll::type_check::AtLocation;
 use rustc::hir;
 use rustc::infer::InferCtxt;
 use rustc::mir::visit::TyContext;
@@ -310,9 +311,8 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
                     match base_ty.sty {
                         ty::TyRef(ref_region, _, mutbl) => {
-                            let span = self.mir.source_info(location).span;
                             self.regioncx.add_outlives(
-                                span,
+                                location.boring(),
                                 ref_region.to_region_vid(),
                                 borrow_region.to_region_vid(),
                             );
diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs
index ac3ab961d0a15..3bdf78ff3db54 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_set.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs
@@ -10,9 +10,9 @@
 
 use rustc::ty::RegionVid;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use borrow_check::nll::type_check::Locations;
 
 use std::fmt;
-use syntax_pos::Span;
 use std::ops::Deref;
 
 #[derive(Clone, Default)]
@@ -23,8 +23,8 @@ crate struct ConstraintSet {
 impl ConstraintSet {
     pub fn push(&mut self, constraint: OutlivesConstraint) {
         debug!(
-            "add_outlives({:?}: {:?})",
-            constraint.sup, constraint.sub
+            "add_outlives({:?}: {:?} @ {:?})",
+            constraint.sup, constraint.sub, constraint.locations
         );
         if constraint.sup == constraint.sub {
             // 'a: 'a is pretty uninteresting
@@ -96,7 +96,7 @@ pub struct OutlivesConstraint {
     pub next: Option<ConstraintIndex>,
 
     /// Where did this constraint arise?
-    pub span: Span,
+    pub locations: Locations,
 }
 
 impl fmt::Debug for OutlivesConstraint {
@@ -104,7 +104,7 @@ impl fmt::Debug for OutlivesConstraint {
         write!(
             formatter,
             "({:?}: {:?}) due to {:?}",
-            self.sup, self.sub, self.span
+            self.sup, self.sub, self.locations
         )
     }
 }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
index c68bb15552fc7..88d9f46e340d3 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
@@ -82,14 +82,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             let OutlivesConstraint {
                 sup,
                 sub,
-                span,
+                locations,
                 next: _,
             } = constraint;
             with_msg(&format!(
                 "{:?}: {:?} due to {:?}",
                 sup,
                 sub,
-                span
+                locations,
             ))?;
         }
 
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
index 15896413af991..0116fbcfc8860 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
@@ -44,7 +44,7 @@ impl<'this, 'tcx> dot::Labeller<'this> for RegionInferenceContext<'tcx> {
         dot::LabelText::LabelStr(format!("{:?}", n).into_cow())
     }
     fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
-        dot::LabelText::LabelStr(format!("{:?}", e.span).into_cow())
+        dot::LabelText::LabelStr(format!("{:?}", e.locations).into_cow())
     }
 }
 
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index fd8a62b4deb33..ace701eeb789c 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -11,6 +11,7 @@
 use super::universal_regions::UniversalRegions;
 use borrow_check::nll::region_infer::values::ToElementIndex;
 use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintSet, OutlivesConstraint};
+use borrow_check::nll::type_check::Locations;
 use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
@@ -154,11 +155,8 @@ pub struct TypeTest<'tcx> {
     /// The region `'x` that the type must outlive.
     pub lower_bound: RegionVid,
 
-    /// The point where the outlives relation must hold.
-    pub point: Location,
-
-    /// Where did this constraint arise?
-    pub span: Span,
+    /// Where did this constraint arise and why?
+    pub locations: Locations,
 
     /// A test which, if met by the region `'x`, proves that this type
     /// constraint is satisfied.
@@ -356,13 +354,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
     pub(super) fn add_outlives(
         &mut self,
-        span: Span,
+        locations: Locations,
         sup: RegionVid,
         sub: RegionVid,
     ) {
         assert!(self.inferred_values.is_none(), "values already inferred");
         self.constraints.push(OutlivesConstraint {
-            span,
+            locations,
             sup,
             sub,
             next: None,
@@ -408,7 +406,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut());
 
-        self.check_universal_regions(infcx, mir_def_id, outlives_requirements.as_mut());
+        self.check_universal_regions(infcx, mir, mir_def_id, outlives_requirements.as_mut());
 
         let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
 
@@ -506,7 +504,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
 
             if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
-                if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) {
+                if self.try_promote_type_test(infcx, mir, type_test, propagated_outlives_requirements) {
                     continue;
                 }
             }
@@ -515,9 +513,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             let lower_bound_region = self.to_error_region(type_test.lower_bound);
             if let Some(lower_bound_region) = lower_bound_region {
                 let region_scope_tree = &tcx.region_scope_tree(mir_def_id);
+                let type_test_span = type_test.locations.span(mir);
                 infcx.report_generic_bound_failure(
                     region_scope_tree,
-                    type_test.span,
+                    type_test_span,
                     None,
                     type_test.generic_kind,
                     lower_bound_region,
@@ -532,8 +531,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 // to report it; we could probably handle it by
                 // iterating over the universal regions and reporting
                 // an error that multiple bounds are required.
+                let type_test_span = type_test.locations.span(mir);
                 tcx.sess.span_err(
-                    type_test.span,
+                    type_test_span,
                     &format!("`{}` does not live long enough", type_test.generic_kind,),
                 );
             }
@@ -566,6 +566,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn try_promote_type_test<'gcx>(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        mir: &Mir<'tcx>,
         type_test: &TypeTest<'tcx>,
         propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
     ) -> bool {
@@ -574,8 +575,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let TypeTest {
             generic_kind,
             lower_bound,
-            point: _,
-            span,
+            locations,
             test: _,
         } = type_test;
 
@@ -599,7 +599,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         propagated_outlives_requirements.push(ClosureOutlivesRequirement {
             subject,
             outlived_free_region: lower_bound_plus,
-            blame_span: *span,
+            blame_span: locations.span(mir),
         });
         true
     }
@@ -865,6 +865,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn check_universal_regions<'gcx>(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        mir: &Mir<'tcx>,
         mir_def_id: DefId,
         mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
     ) {
@@ -881,6 +882,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         for (fr, _) in universal_definitions {
             self.check_universal_region(
                 infcx,
+                mir,
                 mir_def_id,
                 fr,
                 &mut propagated_outlives_requirements,
@@ -899,6 +901,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn check_universal_region<'gcx>(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        mir: &Mir<'tcx>,
         mir_def_id: DefId,
         longer_fr: RegionVid,
         propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
@@ -921,7 +924,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             );
 
             let blame_index = self.blame_constraint(longer_fr, shorter_fr);
-            let blame_span = self.constraints[blame_index].span;
+            let blame_span = self.constraints[blame_index].locations.span(mir);
 
             if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
                 // Shrink `fr` until we find a non-local region (if we do).
diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
index 2ee74dc6095fa..27bd50427772d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
@@ -19,14 +19,12 @@ use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
 use rustc::infer::region_constraints::{GenericKind, VerifyBound};
 use rustc::infer::{self, SubregionOrigin};
-use rustc::mir::{Location, Mir};
 use rustc::ty::subst::UnpackedKind;
 use rustc::ty::{self, TyCtxt};
-use syntax::codemap::Span;
+use syntax_pos::DUMMY_SP;
 
 crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    mir: &'a Mir<'tcx>,
     universal_regions: &'a UniversalRegions<'tcx>,
     location_table: &'a LocationTable,
     region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
@@ -41,7 +39,6 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     crate fn new(
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
-        mir: &'a Mir<'tcx>,
         universal_regions: &'a UniversalRegions<'tcx>,
         location_table: &'a LocationTable,
         region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
@@ -54,7 +51,6 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     ) -> Self {
         Self {
             tcx,
-            mir,
             universal_regions,
             location_table,
             region_bound_pairs,
@@ -91,8 +87,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
         // will start to fail.
         let ty::OutlivesPredicate(k1, r2) =
             query_constraint.no_late_bound_regions().unwrap_or_else(|| {
-                span_bug!(
-                    self.span(),
+                bug!(
                     "query_constraint {:?} contained bound regions",
                     query_constraint,
                 );
@@ -125,7 +120,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
             UnpackedKind::Type(t1) => {
                 // we don't actually use this for anything, but
                 // the `TypeOutlives` code needs an origin.
-                let origin = infer::RelateParamBound(self.span(), t1);
+                let origin = infer::RelateParamBound(DUMMY_SP, t1);
 
                 TypeOutlives::new(
                     &mut *self,
@@ -146,15 +141,12 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     ) -> TypeTest<'tcx> {
         let lower_bound = self.to_region_vid(region);
 
-        let point = self.locations.from_location().unwrap_or(Location::START);
-
         let test = self.verify_bound_to_region_test(&bound);
 
         TypeTest {
             generic_kind,
             lower_bound,
-            point,
-            span: self.span(),
+            locations: self.locations,
             test,
         }
     }
@@ -189,17 +181,9 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
         self.universal_regions.to_region_vid(r)
     }
 
-    fn span(&self) -> Span {
-        self.mir
-            .source_info(self.locations.from_location().unwrap_or(Location::START))
-            .span
-    }
-
     fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
-        let span = self.span();
-
         self.outlives_constraints.push(OutlivesConstraint {
-            span,
+            locations: self.locations,
             sub,
             sup,
             next: None,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 404e04ef4ccef..782b07d02f438 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -147,7 +147,6 @@ fn type_check_internal<'gcx, 'tcx>(
         region_bound_pairs,
         implicit_region_bound,
         borrowck_context,
-        mir,
     );
     let errors_reported = {
         let mut verifier = TypeVerifier::new(&mut checker, mir);
@@ -597,7 +596,6 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
     constraints: MirTypeckRegionConstraints<'tcx>,
     borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
-    mir: &'a Mir<'tcx>,
 }
 
 struct BorrowCheckContext<'a, 'tcx: 'a> {
@@ -628,7 +626,7 @@ crate struct MirTypeckRegionConstraints<'tcx> {
 /// required to hold. Normally, this is at a particular point which
 /// created the obligation, but for constraints that the user gave, we
 /// want the constraint to hold at all points.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 pub enum Locations {
     /// Indicates that a type constraint should always be true. This
     /// is particularly important in the new borrowck analysis for
@@ -663,21 +661,42 @@ pub enum Locations {
     /// assigned to `x` are of `'static` lifetime.
     All,
 
-    Pair {
-        /// The location in the MIR that generated these constraints.
-        /// This is intended for error reporting and diagnosis; the
-        /// constraints may *take effect* at a distinct spot.
-        from_location: Location,
-    },
+    /// A "boring" constraint (caused by the given location) is one that
+    /// the user probably doesn't want to see described in diagnostics,
+    /// because it is kind of an artifact of the type system setup.
+    ///
+    /// Example: `x = Foo { field: y }` technically creates
+    /// intermediate regions representing the "type of `Foo { field: y
+    /// }`", and data flows from `y` into those variables, but they
+    /// are not very interesting. The assignment into `x` on the other
+    /// hand might be.
+    Boring(Location),
+
+    /// An *important* outlives constraint (caused by the given
+    /// location) is one that would be useful to highlight in
+    /// diagnostics, because it represents a point where references
+    /// flow from one spot to another (e.g., `x = y`)
+    Interesting(Location),
 }
 
 impl Locations {
     pub fn from_location(&self) -> Option<Location> {
         match self {
             Locations::All => None,
-            Locations::Pair { from_location, .. } => Some(*from_location),
+            Locations::Boring(from_location) | Locations::Interesting(from_location) => {
+                Some(*from_location)
+            }
         }
     }
+
+    /// Gets a span representing the location.
+    pub fn span(&self, mir: &Mir<'_>) -> Span {
+        let span_location = match self {
+            Locations::All => Location::START,
+            Locations::Boring(l) | Locations::Interesting(l) => *l,
+        };
+        mir.source_info(span_location).span
+    }
 }
 
 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
@@ -688,7 +707,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
         implicit_region_bound: Option<ty::Region<'tcx>>,
         borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
-        mir: &'a Mir<'tcx>,
     ) -> Self {
         TypeChecker {
             infcx,
@@ -698,7 +716,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             region_bound_pairs,
             implicit_region_bound,
             borrowck_context,
-            mir,
             reported_errors: FxHashSet(),
             constraints: MirTypeckRegionConstraints::default(),
         }
@@ -741,7 +758,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         if let Some(borrowck_context) = &mut self.borrowck_context {
             constraint_conversion::ConstraintConversion::new(
                 self.infcx.tcx,
-                self.mir,
                 borrowck_context.universal_regions,
                 borrowck_context.location_table,
                 self.region_bound_pairs,
@@ -886,9 +902,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 let place_ty = location.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = value.ty(mir, tcx);
 
-                let locations = Locations::Pair {
-                    from_location: term_location,
-                };
+                let locations = term_location.interesting();
                 if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
                     span_mirbug!(
                         self,
@@ -988,7 +1002,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 match mir.yield_ty {
                     None => span_mirbug!(self, term, "yield in non-generator"),
                     Some(ty) => {
-                        if let Err(terr) = self.sub_types(value_ty, ty, term_location.interesting()) {
+                        if let Err(terr) = self.sub_types(value_ty, ty, term_location.interesting())
+                        {
                             span_mirbug!(
                                 self,
                                 term,
@@ -1016,9 +1031,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         match *destination {
             Some((ref dest, _target_block)) => {
                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
-                let locations = Locations::Pair {
-                    from_location: term_location,
-                };
+                let locations = term_location.interesting();
                 if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) {
                     span_mirbug!(
                         self,
@@ -1630,7 +1643,7 @@ impl MirPass for TypeckMir {
     }
 }
 
-trait AtLocation {
+pub trait AtLocation {
     /// Indicates a "boring" constraint that the user probably
     /// woudln't want to see highlights.
     fn boring(self) -> Locations;
@@ -1642,13 +1655,11 @@ trait AtLocation {
 
 impl AtLocation for Location {
     fn boring(self) -> Locations {
-        Locations::Pair {
-            from_location: self,
-        }
+        Locations::Boring(self)
     }
 
     fn interesting(self) -> Locations {
-        self.boring()
+        Locations::Interesting(self)
     }
 }
 

From 9e2157fdcac358646d2ff2ca888d2a63df565239 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Tue, 5 Jun 2018 06:13:28 -0400
Subject: [PATCH 05/15] don't consider assignments to temporaries "interesting"

---
 .../borrow_check/nll/type_check/mod.rs             | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 782b07d02f438..911e543425916 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -798,9 +798,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         let tcx = self.tcx();
         match stmt.kind {
             StatementKind::Assign(ref place, ref rv) => {
+                // Assignments to temporaries are not "interesting";
+                // they are not caused by the user, but rather artifacts
+                // of lowering. Assignments to other sorts of places *are* interesting
+                // though.
+                let is_temp = if let Place::Local(l) = place {
+                    !mir.local_decls[*l].is_user_variable.is_some()
+                } else {
+                    false
+                };
+
+                let locations = if is_temp { location.boring() } else { location.interesting() };
+
                 let place_ty = place.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = rv.ty(mir, tcx);
-                if let Err(terr) = self.sub_types(rv_ty, place_ty, location.interesting()) {
+                if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
                     span_mirbug!(
                         self,
                         stmt,

From 56274be4b541599b0a1a02c710cc293659715345 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Mon, 11 Jun 2018 23:07:54 +0100
Subject: [PATCH 06/15] Added bfs for constraint paths from regions.

---
 .../borrow_check/nll/region_infer/mod.rs      | 110 +++++++++++++++++-
 1 file changed, 109 insertions(+), 1 deletion(-)

diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index ace701eeb789c..1fa530f5492ab 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -26,6 +26,7 @@ use rustc::mir::{
 use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc::util::common::{self, ErrorReported};
 use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use std::rc::Rc;
 use syntax_pos::Span;
@@ -504,7 +505,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
 
             if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
-                if self.try_promote_type_test(infcx, mir, type_test, propagated_outlives_requirements) {
+                if self.try_promote_type_test(infcx, mir, type_test,
+                                              propagated_outlives_requirements) {
                     continue;
                 }
             }
@@ -963,6 +965,104 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
     }
 
+    fn find_constraint_paths_from_region(
+        &self,
+        r0: RegionVid
+    ) -> Vec<Vec<ConstraintIndex>> {
+        let constraints = self.constraints.clone();
+
+        // Mapping of regions to the previous region and constraint index that led to it.
+        let mut previous = FxHashMap();
+        // Current region in traversal.
+        let mut current = r0;
+        // Regions yet to be visited.
+        let mut next = vec! [ current ];
+        // Regions that have been visited.
+        let mut visited = FxHashSet();
+        // Ends of paths.
+        let mut end_regions: Vec<RegionVid> = Vec::new();
+
+        // When we've still got points to visit...
+        while !next.is_empty() {
+            // ...take the next point...
+            debug!("find_constraint_paths_from_region: next={:?}", next);
+            current = next.pop().unwrap(); // Can unwrap here as we know the vector is not empty.
+
+            // ...find the edges containing it...
+            let mut upcoming = Vec::new();
+            for (index, constraint) in constraints.iter_enumerated() {
+                if constraint.sub == current {
+                    // ...add the regions that join us with to the path we've taken...
+                    debug!("find_constraint_paths_from_region: index={:?} constraint={:?}",
+                           index, constraint);
+                    let next_region = constraint.sup.clone();
+
+                    // ...unless we've visited it since this was added...
+                    if visited.contains(&next_region) {
+                        debug!("find_constraint_paths_from_region: skipping as visited");
+                        continue;
+                    }
+
+                    previous.insert(next_region, (index, Some(current)));
+                    upcoming.push(next_region);
+                }
+            }
+
+            if upcoming.is_empty() {
+                // If we didn't find any edges then this is the end of a path...
+                debug!("find_constraint_paths_from_region: new end region current={:?}", current);
+                end_regions.push(current);
+            } else {
+                // ...but, if we did find edges, then add these to the regions yet to visit...
+                debug!("find_constraint_paths_from_region: extend next upcoming={:?}", upcoming);
+                next.extend(upcoming);
+            }
+
+            // ...and don't visit it again.
+            visited.insert(current.clone());
+            debug!("find_constraint_paths_from_region: next={:?} visited={:?}", next, visited);
+        }
+
+        // Now we've visited each point, compute the final paths.
+        let mut paths: Vec<Vec<ConstraintIndex>> = Vec::new();
+        debug!("find_constraint_paths_from_region: end_regions={:?}", end_regions);
+        for end_region in end_regions {
+            debug!("find_constraint_paths_from_region: end_region={:?}", end_region);
+
+            // Get the constraint and region that led to this end point.
+            // We can unwrap as we know if end_point was in the vector that it
+            // must also be in our previous map.
+            let (mut index, mut region) = previous.get(&end_region).unwrap();
+            debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region);
+
+            // Keep track of the indices.
+            let mut path: Vec<ConstraintIndex> = vec![index];
+
+            while region.is_some() && region != Some(r0) {
+                let p = previous.get(&region.unwrap()).unwrap();
+                index = p.0;
+                region = p.1;
+
+                debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region);
+                path.push(index);
+            }
+
+            // Add to our paths.
+            paths.push(path);
+        }
+
+        debug!("find_constraint_paths_from_region: paths={:?}", paths);
+        paths
+    }
+
+    fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool {
+        self.constraints.get(*index).filter(|constraint| {
+            debug!("constraint_is_interesting: locations={:?} constraint={:?}",
+                   constraint.locations, constraint);
+            if let Locations::Interesting(_) = constraint.locations { true } else { false }
+        }).is_some()
+    }
+
     /// Report an error because the universal region `fr` was required to outlive
     /// `outlived_fr` but it is not known to do so. For example:
     ///
@@ -992,6 +1092,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
         }
 
+        let constraints = self.find_constraint_paths_from_region(fr.clone());
+        let path = constraints.iter().min_by_key(|p| p.len()).unwrap();
+        debug!("report_error: path={:?}", path);
+        let path = path.iter()
+            .filter(|index| self.constraint_is_interesting(index))
+            .collect::<Vec<&ConstraintIndex>>();
+        debug!("report_error: path={:?}", path);
+
         let fr_string = match fr_name {
             Some(r) => format!("free region `{}`", r),
             None => format!("free region `{:?}`", fr),

From fd0806618c259a31da2c7824610d3224e71dad34 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Tue, 12 Jun 2018 20:43:14 +0100
Subject: [PATCH 07/15] Constraints are now being categorized, sorted and the
 error labelled. Categorization needs a bit of work.

---
 .../borrow_check/nll/constraint_set.rs        | 36 +++++++
 .../borrow_check/nll/region_infer/mod.rs      | 96 +++++++++++++++----
 2 files changed, 116 insertions(+), 16 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs
index 3bdf78ff3db54..232242b552f7f 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_set.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs
@@ -13,6 +13,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use borrow_check::nll::type_check::Locations;
 
 use std::fmt;
+use std::cmp::Ordering;
 use std::ops::Deref;
 
 #[derive(Clone, Default)]
@@ -109,4 +110,39 @@ impl fmt::Debug for OutlivesConstraint {
     }
 }
 
+/// Constraints that are considered interesting can be categorized to
+/// determine why they are interesting.
+#[derive(Debug, Eq, PartialEq)]
+crate enum ConstraintCategory {
+    Assignment,
+    CallArgument,
+    Cast,
+    Other,
+}
+
+impl Ord for ConstraintCategory {
+    fn cmp(&self, other: &Self) -> Ordering {
+        if self == other {
+            return Ordering::Equal;
+        }
+
+        match (self, other) {
+            (ConstraintCategory::Assignment, _) => Ordering::Greater,
+            (_, ConstraintCategory::Assignment) => Ordering::Less,
+            (ConstraintCategory::CallArgument, _) => Ordering::Greater,
+            (_, ConstraintCategory::CallArgument) => Ordering::Less,
+            (ConstraintCategory::Cast, _) => Ordering::Greater,
+            (_, ConstraintCategory::Cast) => Ordering::Less,
+            (ConstraintCategory::Other, _) => Ordering::Greater,
+        }
+    }
+}
+
+impl PartialOrd for ConstraintCategory {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+
 newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 1fa530f5492ab..713ff7002b324 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -10,7 +10,8 @@
 
 use super::universal_regions::UniversalRegions;
 use borrow_check::nll::region_infer::values::ToElementIndex;
-use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintSet, OutlivesConstraint};
+use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintCategory, ConstraintSet};
+use borrow_check::nll::constraint_set::{OutlivesConstraint};
 use borrow_check::nll::type_check::Locations;
 use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryRegionConstraint;
@@ -21,13 +22,14 @@ use rustc::infer::NLLRegionVariableOrigin;
 use rustc::infer::RegionVariableOrigin;
 use rustc::mir::{
     ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
-    Mir,
+    Mir, StatementKind, TerminatorKind, Rvalue
 };
 use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc::util::common::{self, ErrorReported};
 use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+
 use std::rc::Rc;
 use syntax_pos::Span;
 
@@ -961,10 +963,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // Note: in this case, we use the unapproximated regions
             // to report the error. This gives better error messages
             // in some cases.
-            self.report_error(infcx, mir_def_id, longer_fr, shorter_fr, blame_span);
+            self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, blame_span);
         }
     }
 
+    /// When reporting an error, it is useful to be able to determine which constraints influenced
+    /// the region being reported as an error. This function finds all of the paths from the
+    /// constraint.
     fn find_constraint_paths_from_region(
         &self,
         r0: RegionVid
@@ -1055,6 +1060,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         paths
     }
 
+    /// This function will return true if a constraint is interesting and false if a constraint
+    /// is not. It is useful in filtering constraint paths to only interesting points.
     fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool {
         self.constraints.get(*index).filter(|constraint| {
             debug!("constraint_is_interesting: locations={:?} constraint={:?}",
@@ -1063,6 +1070,32 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }).is_some()
     }
 
+    /// This function classifies a constraint from a location.
+    fn classify_constraint(&self, location: Location, mir: &Mir<'tcx>) -> ConstraintCategory {
+        let data = &mir[location.block];
+        if location.statement_index == data.statements.len() {
+            if let Some(ref terminator) = data.terminator {
+                match terminator.kind {
+                    TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
+                    TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
+                    _ => ConstraintCategory::Other,
+                }
+            } else {
+                ConstraintCategory::Other
+            }
+        } else {
+            let statement = &data.statements[location.statement_index];
+            match statement.kind {
+                StatementKind::Assign(_, ref rvalue) => match rvalue {
+                    Rvalue::Cast(..) => ConstraintCategory::Cast,
+                    Rvalue::Use(..) => ConstraintCategory::Assignment,
+                    _ => ConstraintCategory::Other,
+                },
+                _ => ConstraintCategory::Other,
+            }
+        }
+    }
+
     /// Report an error because the universal region `fr` was required to outlive
     /// `outlived_fr` but it is not known to do so. For example:
     ///
@@ -1073,6 +1106,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
     fn report_error(
         &self,
+        mir: &Mir<'tcx>,
         infcx: &InferCtxt<'_, '_, 'tcx>,
         mir_def_id: DefId,
         fr: RegionVid,
@@ -1095,27 +1129,57 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let constraints = self.find_constraint_paths_from_region(fr.clone());
         let path = constraints.iter().min_by_key(|p| p.len()).unwrap();
         debug!("report_error: path={:?}", path);
+
         let path = path.iter()
             .filter(|index| self.constraint_is_interesting(index))
             .collect::<Vec<&ConstraintIndex>>();
         debug!("report_error: path={:?}", path);
 
-        let fr_string = match fr_name {
-            Some(r) => format!("free region `{}`", r),
-            None => format!("free region `{:?}`", fr),
-        };
+        let mut categorized_path = path.iter().filter_map(|index| {
+            self.constraints.get(**index).iter().filter_map(|constraint| {
+                let span = constraint.locations.span(mir);
+                constraint.locations.from_location().iter().filter_map(|location| {
+                    let classification = self.classify_constraint(*location, mir);
+                    Some((classification, span))
+                }).next()
+            }).next()
+        }).collect::<Vec<(ConstraintCategory, Span)>>();
+        debug!("report_error: categorized_path={:?}", categorized_path);
+
+        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
+        debug!("report_error: sorted_path={:?}", categorized_path);
+
+        if categorized_path.len() > 0 {
+            let blame_constraint = &categorized_path[0];
+
+            let mut diag = infcx.tcx.sess.struct_span_err(
+                blame_constraint.1,
+                &format!("{:?}", blame_constraint.0),
+            );
 
-        let outlived_fr_string = match outlived_fr_name {
-            Some(r) => format!("free region `{}`", r),
-            None => format!("free region `{:?}`", outlived_fr),
-        };
+            for secondary in categorized_path.iter().skip(1) {
+                diag.span_label(secondary.1, format!("{:?}", secondary.0));
+            }
 
-        let mut diag = infcx.tcx.sess.struct_span_err(
-            blame_span,
-            &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
-        );
+            diag.emit();
+        } else {
+            let fr_string = match fr_name {
+                Some(r) => format!("free region `{}`", r),
+                None => format!("free region `{:?}`", fr),
+            };
+
+            let outlived_fr_string = match outlived_fr_name {
+                Some(r) => format!("free region `{}`", r),
+                None => format!("free region `{:?}`", outlived_fr),
+            };
+
+            let mut diag = infcx.tcx.sess.struct_span_err(
+                blame_span,
+                &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
+            );
 
-        diag.emit();
+            diag.emit();
+        }
     }
 
     crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {

From 58a723209d170634ecc4f9be02e9bc3659541125 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Wed, 20 Jun 2018 21:11:27 +0100
Subject: [PATCH 08/15] Switched to while let in DFS and deriving Ord on
 ConstraintCategory.

---
 .../borrow_check/nll/constraint_set.rs        | 28 +------------------
 .../borrow_check/nll/region_infer/mod.rs      |  9 ++----
 2 files changed, 4 insertions(+), 33 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs
index 232242b552f7f..d8c26960a7219 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_set.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs
@@ -13,7 +13,6 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use borrow_check::nll::type_check::Locations;
 
 use std::fmt;
-use std::cmp::Ordering;
 use std::ops::Deref;
 
 #[derive(Clone, Default)]
@@ -112,7 +111,7 @@ impl fmt::Debug for OutlivesConstraint {
 
 /// Constraints that are considered interesting can be categorized to
 /// determine why they are interesting.
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
 crate enum ConstraintCategory {
     Assignment,
     CallArgument,
@@ -120,29 +119,4 @@ crate enum ConstraintCategory {
     Other,
 }
 
-impl Ord for ConstraintCategory {
-    fn cmp(&self, other: &Self) -> Ordering {
-        if self == other {
-            return Ordering::Equal;
-        }
-
-        match (self, other) {
-            (ConstraintCategory::Assignment, _) => Ordering::Greater,
-            (_, ConstraintCategory::Assignment) => Ordering::Less,
-            (ConstraintCategory::CallArgument, _) => Ordering::Greater,
-            (_, ConstraintCategory::CallArgument) => Ordering::Less,
-            (ConstraintCategory::Cast, _) => Ordering::Greater,
-            (_, ConstraintCategory::Cast) => Ordering::Less,
-            (ConstraintCategory::Other, _) => Ordering::Greater,
-        }
-    }
-}
-
-impl PartialOrd for ConstraintCategory {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-
 newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 713ff7002b324..d7e818c50437d 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -978,20 +978,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         // Mapping of regions to the previous region and constraint index that led to it.
         let mut previous = FxHashMap();
-        // Current region in traversal.
-        let mut current = r0;
         // Regions yet to be visited.
-        let mut next = vec! [ current ];
+        let mut next = vec! [ r0 ];
         // Regions that have been visited.
         let mut visited = FxHashSet();
         // Ends of paths.
         let mut end_regions: Vec<RegionVid> = Vec::new();
 
         // When we've still got points to visit...
-        while !next.is_empty() {
+        while let Some(current) = next.pop() {
             // ...take the next point...
-            debug!("find_constraint_paths_from_region: next={:?}", next);
-            current = next.pop().unwrap(); // Can unwrap here as we know the vector is not empty.
+            debug!("find_constraint_paths_from_region: current={:?} next={:?}", current, next);
 
             // ...find the edges containing it...
             let mut upcoming = Vec::new();

From 27ce0cca8e93885d16890e712a7bc4ac27475176 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Wed, 20 Jun 2018 21:34:34 +0100
Subject: [PATCH 09/15] Moved region inference error reporting into own module.

---
 .../borrow_check/nll/constraint_set.rs        |  10 -
 .../nll/region_infer/error_reporting.rs       | 324 ++++++++++++++++++
 .../borrow_check/nll/region_infer/mod.rs      | 302 +---------------
 3 files changed, 328 insertions(+), 308 deletions(-)
 create mode 100644 src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs

diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs
index d8c26960a7219..3bdf78ff3db54 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_set.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs
@@ -109,14 +109,4 @@ impl fmt::Debug for OutlivesConstraint {
     }
 }
 
-/// Constraints that are considered interesting can be categorized to
-/// determine why they are interesting.
-#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
-crate enum ConstraintCategory {
-    Assignment,
-    CallArgument,
-    Cast,
-    Other,
-}
-
 newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
new file mode 100644
index 0000000000000..261bc31b6f606
--- /dev/null
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
@@ -0,0 +1,324 @@
+// Copyright 2017 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.
+
+use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext};
+use borrow_check::nll::region_infer::values::ToElementIndex;
+use borrow_check::nll::type_check::Locations;
+use rustc::hir::def_id::DefId;
+use rustc::infer::InferCtxt;
+use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
+use rustc::mir::{Location, Mir, StatementKind, TerminatorKind, Rvalue};
+use rustc::ty::RegionVid;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::indexed_vec::IndexVec;
+use syntax_pos::Span;
+
+/// Constraints that are considered interesting can be categorized to
+/// determine why they are interesting.
+#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
+enum ConstraintCategory {
+    Assignment,
+    Cast,
+    CallArgument,
+    Other,
+}
+
+impl<'tcx> RegionInferenceContext<'tcx> {
+    /// When reporting an error, it is useful to be able to determine which constraints influenced
+    /// the region being reported as an error. This function finds all of the paths from the
+    /// constraint.
+    fn find_constraint_paths_from_region(
+        &self,
+        r0: RegionVid
+    ) -> Vec<Vec<ConstraintIndex>> {
+        let constraints = self.constraints.clone();
+
+        // Mapping of regions to the previous region and constraint index that led to it.
+        let mut previous = FxHashMap();
+        // Regions yet to be visited.
+        let mut next = vec! [ r0 ];
+        // Regions that have been visited.
+        let mut visited = FxHashSet();
+        // Ends of paths.
+        let mut end_regions: Vec<RegionVid> = Vec::new();
+
+        // When we've still got points to visit...
+        while let Some(current) = next.pop() {
+            // ...take the next point...
+            debug!("find_constraint_paths_from_region: current={:?} next={:?}", current, next);
+
+            // ...find the edges containing it...
+            let mut upcoming = Vec::new();
+            for (index, constraint) in constraints.iter_enumerated() {
+                if constraint.sub == current {
+                    // ...add the regions that join us with to the path we've taken...
+                    debug!("find_constraint_paths_from_region: index={:?} constraint={:?}",
+                           index, constraint);
+                    let next_region = constraint.sup.clone();
+
+                    // ...unless we've visited it since this was added...
+                    if visited.contains(&next_region) {
+                        debug!("find_constraint_paths_from_region: skipping as visited");
+                        continue;
+                    }
+
+                    previous.insert(next_region, (index, Some(current)));
+                    upcoming.push(next_region);
+                }
+            }
+
+            if upcoming.is_empty() {
+                // If we didn't find any edges then this is the end of a path...
+                debug!("find_constraint_paths_from_region: new end region current={:?}", current);
+                end_regions.push(current);
+            } else {
+                // ...but, if we did find edges, then add these to the regions yet to visit...
+                debug!("find_constraint_paths_from_region: extend next upcoming={:?}", upcoming);
+                next.extend(upcoming);
+            }
+
+            // ...and don't visit it again.
+            visited.insert(current.clone());
+            debug!("find_constraint_paths_from_region: next={:?} visited={:?}", next, visited);
+        }
+
+        // Now we've visited each point, compute the final paths.
+        let mut paths: Vec<Vec<ConstraintIndex>> = Vec::new();
+        debug!("find_constraint_paths_from_region: end_regions={:?}", end_regions);
+        for end_region in end_regions {
+            debug!("find_constraint_paths_from_region: end_region={:?}", end_region);
+
+            // Get the constraint and region that led to this end point.
+            // We can unwrap as we know if end_point was in the vector that it
+            // must also be in our previous map.
+            let (mut index, mut region) = previous.get(&end_region).unwrap();
+            debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region);
+
+            // Keep track of the indices.
+            let mut path: Vec<ConstraintIndex> = vec![index];
+
+            while region.is_some() && region != Some(r0) {
+                let p = previous.get(&region.unwrap()).unwrap();
+                index = p.0;
+                region = p.1;
+
+                debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region);
+                path.push(index);
+            }
+
+            // Add to our paths.
+            paths.push(path);
+        }
+
+        debug!("find_constraint_paths_from_region: paths={:?}", paths);
+        paths
+    }
+
+    /// This function will return true if a constraint is interesting and false if a constraint
+    /// is not. It is useful in filtering constraint paths to only interesting points.
+    fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool {
+        self.constraints.get(*index).filter(|constraint| {
+            debug!("constraint_is_interesting: locations={:?} constraint={:?}",
+                   constraint.locations, constraint);
+            if let Locations::Interesting(_) = constraint.locations { true } else { false }
+        }).is_some()
+    }
+
+    /// This function classifies a constraint from a location.
+    fn classify_constraint(&self, location: Location, mir: &Mir<'tcx>) -> ConstraintCategory {
+        let data = &mir[location.block];
+        if location.statement_index == data.statements.len() {
+            if let Some(ref terminator) = data.terminator {
+                match terminator.kind {
+                    TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
+                    TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
+                    _ => ConstraintCategory::Other,
+                }
+            } else {
+                ConstraintCategory::Other
+            }
+        } else {
+            let statement = &data.statements[location.statement_index];
+            match statement.kind {
+                StatementKind::Assign(_, ref rvalue) => match rvalue {
+                    Rvalue::Cast(..) => ConstraintCategory::Cast,
+                    Rvalue::Use(..) => ConstraintCategory::Assignment,
+                    _ => ConstraintCategory::Other,
+                },
+                _ => ConstraintCategory::Other,
+            }
+        }
+    }
+
+    /// Report an error because the universal region `fr` was required to outlive
+    /// `outlived_fr` but it is not known to do so. For example:
+    ///
+    /// ```
+    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
+    /// ```
+    ///
+    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
+    pub(super) fn report_error(
+        &self,
+        mir: &Mir<'tcx>,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
+        mir_def_id: DefId,
+        fr: RegionVid,
+        outlived_fr: RegionVid,
+        blame_span: Span,
+    ) {
+        // Obviously uncool error reporting.
+
+        let fr_name = self.to_error_region(fr);
+        let outlived_fr_name = self.to_error_region(outlived_fr);
+
+        if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
+            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
+            let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
+            if let Some(_error_reported) = nice.try_report() {
+                return;
+            }
+        }
+
+        let constraints = self.find_constraint_paths_from_region(fr.clone());
+        let path = constraints.iter().min_by_key(|p| p.len()).unwrap();
+        debug!("report_error: path={:?}", path);
+
+        let path = path.iter()
+            .filter(|index| self.constraint_is_interesting(index))
+            .collect::<Vec<&ConstraintIndex>>();
+        debug!("report_error: path={:?}", path);
+
+        let mut categorized_path = path.iter().filter_map(|index| {
+            self.constraints.get(**index).iter().filter_map(|constraint| {
+                let span = constraint.locations.span(mir);
+                constraint.locations.from_location().iter().filter_map(|location| {
+                    let classification = self.classify_constraint(*location, mir);
+                    Some((classification, span))
+                }).next()
+            }).next()
+        }).collect::<Vec<(ConstraintCategory, Span)>>();
+        debug!("report_error: categorized_path={:?}", categorized_path);
+
+        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
+        debug!("report_error: sorted_path={:?}", categorized_path);
+
+        if categorized_path.len() > 0 {
+            let blame_constraint = &categorized_path[0];
+
+            let mut diag = infcx.tcx.sess.struct_span_err(
+                blame_constraint.1,
+                &format!("{:?}", blame_constraint.0),
+            );
+
+            for secondary in categorized_path.iter().skip(1) {
+                diag.span_label(secondary.1, format!("{:?}", secondary.0));
+            }
+
+            diag.emit();
+        } else {
+            let fr_string = match fr_name {
+                Some(r) => format!("free region `{}`", r),
+                None => format!("free region `{:?}`", fr),
+            };
+
+            let outlived_fr_string = match outlived_fr_name {
+                Some(r) => format!("free region `{}`", r),
+                None => format!("free region `{:?}`", outlived_fr),
+            };
+
+            let mut diag = infcx.tcx.sess.struct_span_err(
+                blame_span,
+                &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
+            );
+
+            diag.emit();
+        }
+    }
+
+    crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {
+        // Find some constraint `X: Y` where:
+        // - `fr1: X` transitively
+        // - and `Y` is live at `elem`
+        let index = self.blame_constraint(fr1, elem);
+        let region_sub = self.constraints[index].sub;
+
+        // then return why `Y` was live at `elem`
+        self.liveness_constraints.cause(region_sub, elem)
+    }
+
+    /// Tries to finds a good span to blame for the fact that `fr1`
+    /// contains `fr2`.
+    pub(super) fn blame_constraint(&self, fr1: RegionVid,
+                                   elem: impl ToElementIndex) -> ConstraintIndex {
+        // Find everything that influenced final value of `fr`.
+        let influenced_fr1 = self.dependencies(fr1);
+
+        // Try to find some outlives constraint `'X: fr2` where `'X`
+        // influenced `fr1`. Blame that.
+        //
+        // NB, this is a pretty bad choice most of the time. In
+        // particular, the connection between `'X` and `fr1` may not
+        // be obvious to the user -- not to mention the naive notion
+        // of dependencies, which doesn't account for the locations of
+        // contraints at all. But it will do for now.
+        let relevant_constraint = self.constraints
+            .iter_enumerated()
+            .filter_map(|(i, constraint)| {
+                if !self.liveness_constraints.contains(constraint.sub, elem) {
+                    None
+                } else {
+                    influenced_fr1[constraint.sup]
+                        .map(|distance| (distance, i))
+                }
+            })
+            .min() // constraining fr1 with fewer hops *ought* to be more obvious
+            .map(|(_dist, i)| i);
+
+        relevant_constraint.unwrap_or_else(|| {
+            bug!(
+                "could not find any constraint to blame for {:?}: {:?}",
+                fr1,
+                elem,
+            );
+        })
+    }
+
+    /// Finds all regions whose values `'a` may depend on in some way.
+    /// For each region, returns either `None` (does not influence
+    /// `'a`) or `Some(d)` which indicates that it influences `'a`
+    /// with distinct `d` (minimum number of edges that must be
+    /// traversed).
+    ///
+    /// Used during error reporting, extremely naive and inefficient.
+    fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
+        let mut result_set = IndexVec::from_elem(None, &self.definitions);
+        let mut changed = true;
+        result_set[r0] = Some(0); // distance 0 from `r0`
+
+        while changed {
+            changed = false;
+            for constraint in &*self.constraints {
+                if let Some(n) = result_set[constraint.sup] {
+                    let m = n + 1;
+                    if result_set[constraint.sub]
+                        .map(|distance| m < distance)
+                        .unwrap_or(true)
+                    {
+                        result_set[constraint.sub] = Some(m);
+                        changed = true;
+                    }
+                }
+            }
+        }
+
+        result_set
+    }
+}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index d7e818c50437d..09e425ff55508 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -9,32 +9,28 @@
 // except according to those terms.
 
 use super::universal_regions::UniversalRegions;
-use borrow_check::nll::region_infer::values::ToElementIndex;
-use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintCategory, ConstraintSet};
-use borrow_check::nll::constraint_set::{OutlivesConstraint};
+use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintSet, OutlivesConstraint};
 use borrow_check::nll::type_check::Locations;
 use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryRegionConstraint;
-use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc::infer::region_constraints::{GenericKind, VarInfos};
 use rustc::infer::InferCtxt;
 use rustc::infer::NLLRegionVariableOrigin;
 use rustc::infer::RegionVariableOrigin;
 use rustc::mir::{
     ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
-    Mir, StatementKind, TerminatorKind, Rvalue
+    Mir
 };
 use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
-use rustc::util::common::{self, ErrorReported};
+use rustc::util::common;
 use rustc_data_structures::bitvec::BitVector;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 
 use std::rc::Rc;
-use syntax_pos::Span;
 
 mod annotation;
 mod dump_mir;
+mod error_reporting;
 mod graphviz;
 mod values;
 use self::values::{RegionValueElements, RegionValues};
@@ -966,296 +962,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, blame_span);
         }
     }
-
-    /// When reporting an error, it is useful to be able to determine which constraints influenced
-    /// the region being reported as an error. This function finds all of the paths from the
-    /// constraint.
-    fn find_constraint_paths_from_region(
-        &self,
-        r0: RegionVid
-    ) -> Vec<Vec<ConstraintIndex>> {
-        let constraints = self.constraints.clone();
-
-        // Mapping of regions to the previous region and constraint index that led to it.
-        let mut previous = FxHashMap();
-        // Regions yet to be visited.
-        let mut next = vec! [ r0 ];
-        // Regions that have been visited.
-        let mut visited = FxHashSet();
-        // Ends of paths.
-        let mut end_regions: Vec<RegionVid> = Vec::new();
-
-        // When we've still got points to visit...
-        while let Some(current) = next.pop() {
-            // ...take the next point...
-            debug!("find_constraint_paths_from_region: current={:?} next={:?}", current, next);
-
-            // ...find the edges containing it...
-            let mut upcoming = Vec::new();
-            for (index, constraint) in constraints.iter_enumerated() {
-                if constraint.sub == current {
-                    // ...add the regions that join us with to the path we've taken...
-                    debug!("find_constraint_paths_from_region: index={:?} constraint={:?}",
-                           index, constraint);
-                    let next_region = constraint.sup.clone();
-
-                    // ...unless we've visited it since this was added...
-                    if visited.contains(&next_region) {
-                        debug!("find_constraint_paths_from_region: skipping as visited");
-                        continue;
-                    }
-
-                    previous.insert(next_region, (index, Some(current)));
-                    upcoming.push(next_region);
-                }
-            }
-
-            if upcoming.is_empty() {
-                // If we didn't find any edges then this is the end of a path...
-                debug!("find_constraint_paths_from_region: new end region current={:?}", current);
-                end_regions.push(current);
-            } else {
-                // ...but, if we did find edges, then add these to the regions yet to visit...
-                debug!("find_constraint_paths_from_region: extend next upcoming={:?}", upcoming);
-                next.extend(upcoming);
-            }
-
-            // ...and don't visit it again.
-            visited.insert(current.clone());
-            debug!("find_constraint_paths_from_region: next={:?} visited={:?}", next, visited);
-        }
-
-        // Now we've visited each point, compute the final paths.
-        let mut paths: Vec<Vec<ConstraintIndex>> = Vec::new();
-        debug!("find_constraint_paths_from_region: end_regions={:?}", end_regions);
-        for end_region in end_regions {
-            debug!("find_constraint_paths_from_region: end_region={:?}", end_region);
-
-            // Get the constraint and region that led to this end point.
-            // We can unwrap as we know if end_point was in the vector that it
-            // must also be in our previous map.
-            let (mut index, mut region) = previous.get(&end_region).unwrap();
-            debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region);
-
-            // Keep track of the indices.
-            let mut path: Vec<ConstraintIndex> = vec![index];
-
-            while region.is_some() && region != Some(r0) {
-                let p = previous.get(&region.unwrap()).unwrap();
-                index = p.0;
-                region = p.1;
-
-                debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region);
-                path.push(index);
-            }
-
-            // Add to our paths.
-            paths.push(path);
-        }
-
-        debug!("find_constraint_paths_from_region: paths={:?}", paths);
-        paths
-    }
-
-    /// This function will return true if a constraint is interesting and false if a constraint
-    /// is not. It is useful in filtering constraint paths to only interesting points.
-    fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool {
-        self.constraints.get(*index).filter(|constraint| {
-            debug!("constraint_is_interesting: locations={:?} constraint={:?}",
-                   constraint.locations, constraint);
-            if let Locations::Interesting(_) = constraint.locations { true } else { false }
-        }).is_some()
-    }
-
-    /// This function classifies a constraint from a location.
-    fn classify_constraint(&self, location: Location, mir: &Mir<'tcx>) -> ConstraintCategory {
-        let data = &mir[location.block];
-        if location.statement_index == data.statements.len() {
-            if let Some(ref terminator) = data.terminator {
-                match terminator.kind {
-                    TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
-                    TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
-                    _ => ConstraintCategory::Other,
-                }
-            } else {
-                ConstraintCategory::Other
-            }
-        } else {
-            let statement = &data.statements[location.statement_index];
-            match statement.kind {
-                StatementKind::Assign(_, ref rvalue) => match rvalue {
-                    Rvalue::Cast(..) => ConstraintCategory::Cast,
-                    Rvalue::Use(..) => ConstraintCategory::Assignment,
-                    _ => ConstraintCategory::Other,
-                },
-                _ => ConstraintCategory::Other,
-            }
-        }
-    }
-
-    /// Report an error because the universal region `fr` was required to outlive
-    /// `outlived_fr` but it is not known to do so. For example:
-    ///
-    /// ```
-    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
-    /// ```
-    ///
-    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
-    fn report_error(
-        &self,
-        mir: &Mir<'tcx>,
-        infcx: &InferCtxt<'_, '_, 'tcx>,
-        mir_def_id: DefId,
-        fr: RegionVid,
-        outlived_fr: RegionVid,
-        blame_span: Span,
-    ) {
-        // Obviously uncool error reporting.
-
-        let fr_name = self.to_error_region(fr);
-        let outlived_fr_name = self.to_error_region(outlived_fr);
-
-        if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
-            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
-            let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
-            if let Some(ErrorReported) = nice.try_report() {
-                return;
-            }
-        }
-
-        let constraints = self.find_constraint_paths_from_region(fr.clone());
-        let path = constraints.iter().min_by_key(|p| p.len()).unwrap();
-        debug!("report_error: path={:?}", path);
-
-        let path = path.iter()
-            .filter(|index| self.constraint_is_interesting(index))
-            .collect::<Vec<&ConstraintIndex>>();
-        debug!("report_error: path={:?}", path);
-
-        let mut categorized_path = path.iter().filter_map(|index| {
-            self.constraints.get(**index).iter().filter_map(|constraint| {
-                let span = constraint.locations.span(mir);
-                constraint.locations.from_location().iter().filter_map(|location| {
-                    let classification = self.classify_constraint(*location, mir);
-                    Some((classification, span))
-                }).next()
-            }).next()
-        }).collect::<Vec<(ConstraintCategory, Span)>>();
-        debug!("report_error: categorized_path={:?}", categorized_path);
-
-        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
-        debug!("report_error: sorted_path={:?}", categorized_path);
-
-        if categorized_path.len() > 0 {
-            let blame_constraint = &categorized_path[0];
-
-            let mut diag = infcx.tcx.sess.struct_span_err(
-                blame_constraint.1,
-                &format!("{:?}", blame_constraint.0),
-            );
-
-            for secondary in categorized_path.iter().skip(1) {
-                diag.span_label(secondary.1, format!("{:?}", secondary.0));
-            }
-
-            diag.emit();
-        } else {
-            let fr_string = match fr_name {
-                Some(r) => format!("free region `{}`", r),
-                None => format!("free region `{:?}`", fr),
-            };
-
-            let outlived_fr_string = match outlived_fr_name {
-                Some(r) => format!("free region `{}`", r),
-                None => format!("free region `{:?}`", outlived_fr),
-            };
-
-            let mut diag = infcx.tcx.sess.struct_span_err(
-                blame_span,
-                &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
-            );
-
-            diag.emit();
-        }
-    }
-
-    crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {
-        // Find some constraint `X: Y` where:
-        // - `fr1: X` transitively
-        // - and `Y` is live at `elem`
-        let index = self.blame_constraint(fr1, elem);
-        let region_sub = self.constraints[index].sub;
-
-        // then return why `Y` was live at `elem`
-        self.liveness_constraints.cause(region_sub, elem)
-    }
-
-    /// Tries to finds a good span to blame for the fact that `fr1`
-    /// contains `fr2`.
-    fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> ConstraintIndex {
-        // Find everything that influenced final value of `fr`.
-        let influenced_fr1 = self.dependencies(fr1);
-
-        // Try to find some outlives constraint `'X: fr2` where `'X`
-        // influenced `fr1`. Blame that.
-        //
-        // NB, this is a pretty bad choice most of the time. In
-        // particular, the connection between `'X` and `fr1` may not
-        // be obvious to the user -- not to mention the naive notion
-        // of dependencies, which doesn't account for the locations of
-        // contraints at all. But it will do for now.
-        let relevant_constraint = self.constraints
-            .iter_enumerated()
-            .filter_map(|(i, constraint)| {
-                if !self.liveness_constraints.contains(constraint.sub, elem) {
-                    None
-                } else {
-                    influenced_fr1[constraint.sup]
-                        .map(|distance| (distance, i))
-                }
-            })
-            .min() // constraining fr1 with fewer hops *ought* to be more obvious
-            .map(|(_dist, i)| i);
-
-        relevant_constraint.unwrap_or_else(|| {
-            bug!(
-                "could not find any constraint to blame for {:?}: {:?}",
-                fr1,
-                elem,
-            );
-        })
-    }
-
-    /// Finds all regions whose values `'a` may depend on in some way.
-    /// For each region, returns either `None` (does not influence
-    /// `'a`) or `Some(d)` which indicates that it influences `'a`
-    /// with distinct `d` (minimum number of edges that must be
-    /// traversed).
-    ///
-    /// Used during error reporting, extremely naive and inefficient.
-    fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
-        let mut result_set = IndexVec::from_elem(None, &self.definitions);
-        let mut changed = true;
-        result_set[r0] = Some(0); // distance 0 from `r0`
-
-        while changed {
-            changed = false;
-            for constraint in self.constraints.iter() {
-                if let Some(n) = result_set[constraint.sup] {
-                    let m = n + 1;
-                    if result_set[constraint.sub]
-                        .map(|distance| m < distance)
-                        .unwrap_or(true)
-                    {
-                        result_set[constraint.sub] = Some(m);
-                        changed = true;
-                    }
-                }
-            }
-        }
-
-        result_set
-    }
 }
 
 impl<'tcx> RegionDefinition<'tcx> {

From e01e883e4f2e86961f02ce3041e4773a04286cfb Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Tue, 26 Jun 2018 23:00:24 +0100
Subject: [PATCH 10/15] Introduce new categories and show a reasonable error
 message.

---
 .../nll/region_infer/error_reporting.rs       | 100 ++++++++++--------
 1 file changed, 58 insertions(+), 42 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
index 261bc31b6f606..cc78043b83cce 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
@@ -8,26 +8,42 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::fmt;
 use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext};
 use borrow_check::nll::region_infer::values::ToElementIndex;
 use borrow_check::nll::type_check::Locations;
 use rustc::hir::def_id::DefId;
 use rustc::infer::InferCtxt;
 use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
-use rustc::mir::{Location, Mir, StatementKind, TerminatorKind, Rvalue};
+use rustc::mir::{self, Location, Mir, Place, StatementKind, TerminatorKind, Rvalue};
 use rustc::ty::RegionVid;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::IndexVec;
 use syntax_pos::Span;
 
 /// Constraints that are considered interesting can be categorized to
-/// determine why they are interesting.
+/// determine why they are interesting. Order of variants indicates
+/// sort order of the category, thereby influencing diagnostic output.
 #[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
 enum ConstraintCategory {
-    Assignment,
     Cast,
+    Assignment,
+    Return,
     CallArgument,
     Other,
+    Boring,
+}
+
+impl fmt::Display for ConstraintCategory {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            ConstraintCategory::Assignment => write!(f, "Assignment"),
+            ConstraintCategory::Return => write!(f, "Return"),
+            ConstraintCategory::Cast => write!(f, "Cast"),
+            ConstraintCategory::CallArgument => write!(f, "Argument"),
+            _ => write!(f, "Free region"),
+        }
+    }
 }
 
 impl<'tcx> RegionInferenceContext<'tcx> {
@@ -132,9 +148,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     }
 
     /// This function classifies a constraint from a location.
-    fn classify_constraint(&self, location: Location, mir: &Mir<'tcx>) -> ConstraintCategory {
+    fn classify_constraint(&self, index: &ConstraintIndex,
+                           mir: &Mir<'tcx>) -> Option<(ConstraintCategory, Span)> {
+        let constraint = self.constraints.get(*index)?;
+        let span = constraint.locations.span(mir);
+        let location = constraint.locations.from_location()?;
+
+        if !self.constraint_is_interesting(index) {
+            return Some((ConstraintCategory::Boring, span));
+        }
+
         let data = &mir[location.block];
-        if location.statement_index == data.statements.len() {
+        let category = if location.statement_index == data.statements.len() {
             if let Some(ref terminator) = data.terminator {
                 match terminator.kind {
                     TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
@@ -147,14 +172,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         } else {
             let statement = &data.statements[location.statement_index];
             match statement.kind {
-                StatementKind::Assign(_, ref rvalue) => match rvalue {
-                    Rvalue::Cast(..) => ConstraintCategory::Cast,
-                    Rvalue::Use(..) => ConstraintCategory::Assignment,
-                    _ => ConstraintCategory::Other,
+                StatementKind::Assign(ref place, ref rvalue) => {
+                    if *place == Place::Local(mir::RETURN_PLACE) {
+                        ConstraintCategory::Return
+                    } else {
+                        match rvalue {
+                            Rvalue::Cast(..) => ConstraintCategory::Cast,
+                            Rvalue::Use(..) => ConstraintCategory::Assignment,
+                            _ => ConstraintCategory::Other,
+                        }
+                    }
                 },
                 _ => ConstraintCategory::Other,
             }
-        }
+        };
+
+        Some((category, span))
     }
 
     /// Report an error because the universal region `fr` was required to outlive
@@ -187,53 +220,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
         }
 
+        let fr_string = match fr_name {
+            Some(r) => format!("free region `{}`", r),
+            None => format!("free region `{:?}`", fr),
+        };
+
+        let outlived_fr_string = match outlived_fr_name {
+            Some(r) => format!("free region `{}`", r),
+            None => format!("free region `{:?}`", outlived_fr),
+        };
+
         let constraints = self.find_constraint_paths_from_region(fr.clone());
         let path = constraints.iter().min_by_key(|p| p.len()).unwrap();
-        debug!("report_error: path={:?}", path);
-
-        let path = path.iter()
-            .filter(|index| self.constraint_is_interesting(index))
-            .collect::<Vec<&ConstraintIndex>>();
-        debug!("report_error: path={:?}", path);
+        debug!("report_error: shortest_path={:?}", path);
 
         let mut categorized_path = path.iter().filter_map(|index| {
-            self.constraints.get(**index).iter().filter_map(|constraint| {
-                let span = constraint.locations.span(mir);
-                constraint.locations.from_location().iter().filter_map(|location| {
-                    let classification = self.classify_constraint(*location, mir);
-                    Some((classification, span))
-                }).next()
-            }).next()
+            self.classify_constraint(index, mir)
         }).collect::<Vec<(ConstraintCategory, Span)>>();
         debug!("report_error: categorized_path={:?}", categorized_path);
 
         categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
         debug!("report_error: sorted_path={:?}", categorized_path);
 
-        if categorized_path.len() > 0 {
-            let blame_constraint = &categorized_path[0];
-
+        if let Some((category, span)) = &categorized_path.first() {
             let mut diag = infcx.tcx.sess.struct_span_err(
-                blame_constraint.1,
-                &format!("{:?}", blame_constraint.0),
+                *span, &format!("{} requires that data must outlive {}",
+                                category, outlived_fr_string),
             );
 
-            for secondary in categorized_path.iter().skip(1) {
-                diag.span_label(secondary.1, format!("{:?}", secondary.0));
-            }
-
             diag.emit();
         } else {
-            let fr_string = match fr_name {
-                Some(r) => format!("free region `{}`", r),
-                None => format!("free region `{:?}`", fr),
-            };
-
-            let outlived_fr_string = match outlived_fr_name {
-                Some(r) => format!("free region `{}`", r),
-                None => format!("free region `{:?}`", outlived_fr),
-            };
-
             let mut diag = infcx.tcx.sess.struct_span_err(
                 blame_span,
                 &format!("{} does not outlive {}", fr_string, outlived_fr_string,),

From 59e64e908504a6ce6cd549acd735e38871f88368 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Tue, 26 Jun 2018 23:30:52 +0100
Subject: [PATCH 11/15] Updated affected tests.

---
 src/test/ui/borrowck/issue-45983.nll.stderr   |  2 +-
 .../regions-escape-bound-fn-2.nll.stderr      |  2 +-
 ...horter-to-static-comparing-against-free.rs |  2 +-
 ...er-to-static-comparing-against-free.stderr |  8 +++----
 ...approximated-shorter-to-static-no-bound.rs |  2 +-
 ...oximated-shorter-to-static-no-bound.stderr | 13 +++++-----
 ...roximated-shorter-to-static-wrong-bound.rs |  2 +-
 ...mated-shorter-to-static-wrong-bound.stderr | 13 +++++-----
 ...te-fail-to-approximate-longer-no-bounds.rs |  2 +-
 ...ail-to-approximate-longer-no-bounds.stderr |  8 +++----
 .../projection-one-region-closure.rs          |  6 ++---
 .../projection-one-region-closure.stderr      | 24 +++++++++----------
 ...ojection-one-region-trait-bound-closure.rs |  6 ++---
 ...tion-one-region-trait-bound-closure.stderr | 24 +++++++++----------
 ...ojection-two-region-trait-bound-closure.rs |  2 +-
 ...tion-two-region-trait-bound-closure.stderr |  8 +++----
 .../dyn-trait-underscore.nll.stderr           | 12 ++++------
 17 files changed, 65 insertions(+), 71 deletions(-)

diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr
index a008a408d9711..9b5fcbc56d5cd 100644
--- a/src/test/ui/borrowck/issue-45983.nll.stderr
+++ b/src/test/ui/borrowck/issue-45983.nll.stderr
@@ -4,7 +4,7 @@ warning: not reporting region error due to nll
 LL |     give_any(|y| x = Some(y));
    |                           ^
 
-error: free region `` does not outlive free region `'_#2r`
+error: Assignment requires that data must outlive free region `'_#2r`
   --> $DIR/issue-45983.rs:17:27
    |
 LL |     give_any(|y| x = Some(y));
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
index ee3970aa8fd8f..91161d6820c34 100644
--- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
+++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
@@ -4,7 +4,7 @@ warning: not reporting region error due to nll
 LL |     with_int(|y| x = Some(y));
    |                           ^
 
-error: free region `` does not outlive free region `'_#2r`
+error: Assignment requires that data must outlive free region `'_#2r`
   --> $DIR/regions-escape-bound-fn-2.rs:18:27
    |
 LL |     with_int(|y| x = Some(y));
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
index 84bfd6ea4f253..248933fc39e14 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
@@ -31,7 +31,7 @@ fn case1() {
     foo(cell, |cell_a, cell_x| {
         //~^ WARNING not reporting region error due to nll
         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
-        //~^ ERROR does not outlive free region
+        //~^ ERROR Argument requires that data must outlive free region
     })
 }
 
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index ac4efecc8ac07..7b1cba1d937f6 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -4,11 +4,11 @@ warning: not reporting region error due to nll
 LL |     foo(cell, |cell_a, cell_x| {
    |     ^^^
 
-error: free region `ReFree(DefId(0/1:12 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]), BrAnon(1))` does not outlive free region `'_#1r`
-  --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:9
+error: Argument requires that data must outlive free region `'_#1r`
+  --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:20
    |
 LL |         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
-   |         ^^^^^^
+   |                    ^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15
@@ -17,7 +17,7 @@ LL |       foo(cell, |cell_a, cell_x| {
    |  _______________^
 LL | |         //~^ WARNING not reporting region error due to nll
 LL | |         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR Argument requires that data must outlive free region
 LL | |     })
    | |_____^
    |
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
index df715c52921a0..4c8c2b1b95bb0 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
@@ -43,7 +43,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3
 #[rustc_regions]
 fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-        //~^ ERROR does not outlive free region
+        //~^ ERROR Argument requires that data must outlive free region
 
         // Only works if 'x: 'y:
         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index 122e393f97a53..8a18af90e195c 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -9,7 +9,7 @@ note: External requirements
    |
 LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |  _______________________________________________^
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR Argument requires that data must outlive free region
 LL | |
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
@@ -23,12 +23,11 @@ LL | |     });
    = note: number of external vids: 2
    = note: where '_#1r: '_#0r
 
-error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic`
-  --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:47
+error: Argument requires that data must outlive free region `ReStatic`
+  --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5
    |
-LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-   |  _______________________________________________^
-LL | |         //~^ ERROR does not outlive free region
+LL | /     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+LL | |         //~^ ERROR Argument requires that data must outlive free region
 LL | |
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
@@ -40,7 +39,7 @@ note: No external requirements
    |
 LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
 LL | |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR Argument requires that data must outlive free region
 LL | |
 ...  |
 LL | |     });
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
index fdbb312572f89..d9cfea4c891c4 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
@@ -46,7 +46,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3
 #[rustc_regions]
 fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-        //~^ ERROR does not outlive free region
+        //~^ ERROR Argument requires that data must outlive free region
         // Only works if 'x: 'y:
         demand_y(x, y, x.get())
         //~^ WARNING not reporting region error due to nll
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 8cdbc26458150..dda1c44b4d8b4 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -9,7 +9,7 @@ note: External requirements
    |
 LL |       establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
    |  _______________________________________________^
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR Argument requires that data must outlive free region
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARNING not reporting region error due to nll
@@ -23,12 +23,11 @@ LL | |     });
    = note: number of external vids: 3
    = note: where '_#1r: '_#0r
 
-error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic`
-  --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:47
+error: Argument requires that data must outlive free region `ReStatic`
+  --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5
    |
-LL |       establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-   |  _______________________________________________^
-LL | |         //~^ ERROR does not outlive free region
+LL | /     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+LL | |         //~^ ERROR Argument requires that data must outlive free region
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARNING not reporting region error due to nll
@@ -40,7 +39,7 @@ note: No external requirements
    |
 LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
 LL | |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR Argument requires that data must outlive free region
 LL | |         // Only works if 'x: 'y:
 ...  |
 LL | |     });
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
index 7699d10173495..480461b6b639c 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
@@ -46,7 +46,7 @@ fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
         // Only works if 'x: 'y:
         demand_y(x, y, x.get())
         //~^ WARN not reporting region error due to nll
-        //~| ERROR does not outlive free region
+        //~| ERROR Argument requires that data must outlive free region
     });
 }
 
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 8b6cd2ea432db..00e4c289e7eb5 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
@@ -4,11 +4,11 @@ warning: not reporting region error due to nll
 LL |         demand_y(x, y, x.get())
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(4))` does not outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))`
-  --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:18
+error: Argument requires that data must outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))`
+  --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9
    |
 LL |         demand_y(x, y, x.get())
-   |                  ^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47
@@ -18,7 +18,7 @@ LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARN not reporting region error due to nll
-LL | |         //~| ERROR does not outlive free region
+LL | |         //~| ERROR Argument requires that data must outlive free region
 LL | |     });
    | |_____^
    |
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
index 77024c4119ff9..5e695f3f7c7d7 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
@@ -55,7 +55,7 @@ where
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR does not outlive free region
+    //~| ERROR Argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -67,7 +67,7 @@ where
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR does not outlive free region
+    //~| ERROR Argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -89,7 +89,7 @@ where
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+    //~| ERROR Argument requires that data must outlive free region
 }
 
 #[rustc_regions]
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
index e1218830dbb64..fac0a0b0064c0 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -40,11 +40,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |
    = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`...
 
-error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
-  --> $DIR/projection-one-region-closure.rs:55:20
+error: Argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
+  --> $DIR/projection-one-region-closure.rs:55:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-closure.rs:51:1
@@ -54,7 +54,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | | {
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR Argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -88,11 +88,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |
    = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
 
-error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
-  --> $DIR/projection-one-region-closure.rs:67:20
+error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-closure.rs:67:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-closure.rs:62:1
@@ -102,7 +102,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     'a: 'a,
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR Argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -137,11 +137,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |
    = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
 
-error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
-  --> $DIR/projection-one-region-closure.rs:89:20
+error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-closure.rs:89:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-closure.rs:74:1
@@ -151,7 +151,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     T::AssocType: 'a,
 ...  |
-LL | |     //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+LL | |     //~| ERROR Argument requires that data must outlive free region
 LL | | }
    | |_^
    |
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
index fb1009c9cc8e8..24d1753eea826 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
@@ -46,7 +46,7 @@ where
 {
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR does not outlive free region
+    //~| ERROR Argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -57,7 +57,7 @@ where
 {
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR does not outlive free region
+    //~| ERROR Argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -78,7 +78,7 @@ where
 
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR does not outlive free region
+    //~| ERROR Argument requires that data must outlive free region
 }
 
 #[rustc_regions]
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
index 76554e29f62ea..07e65fb405158 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -31,11 +31,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 3
    = note: where '_#1r: '_#2r
 
-error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
-  --> $DIR/projection-one-region-trait-bound-closure.rs:47:20
+error: Argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
+  --> $DIR/projection-one-region-trait-bound-closure.rs:47:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:43:1
@@ -45,7 +45,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | | {
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR Argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -70,11 +70,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 4
    = note: where '_#2r: '_#3r
 
-error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
-  --> $DIR/projection-one-region-trait-bound-closure.rs:58:20
+error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-trait-bound-closure.rs:58:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:53:1
@@ -84,7 +84,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     'a: 'a,
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR Argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -110,11 +110,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 4
    = note: where '_#2r: '_#3r
 
-error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
-  --> $DIR/projection-one-region-trait-bound-closure.rs:79:20
+error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-trait-bound-closure.rs:79:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:64:1
@@ -124,7 +124,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     T::AssocType: 'a,
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR Argument requires that data must outlive free region
 LL | | }
    | |_^
    |
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
index 5307d0880d4da..8129f93736b64 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
@@ -107,7 +107,7 @@ where
 {
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR does not outlive free region
+    //~| ERROR Argument requires that data must outlive free region
 }
 
 #[rustc_regions]
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index c7f456929609e..c778f23a2c450 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -239,11 +239,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 3
    = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
 
-error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))`
-  --> $DIR/projection-two-region-trait-bound-closure.rs:108:20
+error: Argument requires that data must outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))`
+  --> $DIR/projection-two-region-trait-bound-closure.rs:108:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:104:1
@@ -253,7 +253,7 @@ LL | | where
 LL | |     T: Anything<'b, 'b>,
 LL | | {
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR Argument requires that data must outlive free region
 LL | | }
    | |_^
    |
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
index cdc0c78e69414..681c0dce7d172 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
@@ -22,15 +22,11 @@ warning: not reporting region error due to nll
 LL |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: free region `` does not outlive free region `'static`
-  --> $DIR/dyn-trait-underscore.rs:16:52
+error: Cast requires that data must outlive free region `'static`
+  --> $DIR/dyn-trait-underscore.rs:18:5
    |
-LL |   fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
-   |  ____________________________________________________^
-LL | |     //                      ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
-LL | |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
-LL | | }
-   | |_^
+LL |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 

From a11245f80e56e8281f7bbc237140926fe428d8bc Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Wed, 27 Jun 2018 21:18:07 +0100
Subject: [PATCH 12/15] Ensure that changed errors are lower case.

---
 .../borrow_check/nll/region_infer/error_reporting.rs | 10 +++++-----
 src/test/ui/borrowck/issue-45983.nll.stderr          |  2 +-
 .../ui/borrowck/regions-escape-bound-fn-2.nll.stderr |  2 +-
 ...mated-shorter-to-static-comparing-against-free.rs |  2 +-
 ...d-shorter-to-static-comparing-against-free.stderr |  4 ++--
 ...pagate-approximated-shorter-to-static-no-bound.rs |  2 +-
 ...te-approximated-shorter-to-static-no-bound.stderr |  8 ++++----
 ...ate-approximated-shorter-to-static-wrong-bound.rs |  2 +-
 ...approximated-shorter-to-static-wrong-bound.stderr |  8 ++++----
 ...propagate-fail-to-approximate-longer-no-bounds.rs |  2 +-
 ...agate-fail-to-approximate-longer-no-bounds.stderr |  4 ++--
 .../nll/ty-outlives/projection-one-region-closure.rs |  6 +++---
 .../ty-outlives/projection-one-region-closure.stderr | 12 ++++++------
 .../projection-one-region-trait-bound-closure.rs     |  6 +++---
 .../projection-one-region-trait-bound-closure.stderr | 12 ++++++------
 .../projection-two-region-trait-bound-closure.rs     |  2 +-
 .../projection-two-region-trait-bound-closure.stderr |  4 ++--
 .../dyn-trait-underscore.nll.stderr                  |  2 +-
 18 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
index cc78043b83cce..f3372f6be703b 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
@@ -37,11 +37,11 @@ enum ConstraintCategory {
 impl fmt::Display for ConstraintCategory {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
-            ConstraintCategory::Assignment => write!(f, "Assignment"),
-            ConstraintCategory::Return => write!(f, "Return"),
-            ConstraintCategory::Cast => write!(f, "Cast"),
-            ConstraintCategory::CallArgument => write!(f, "Argument"),
-            _ => write!(f, "Free region"),
+            ConstraintCategory::Assignment => write!(f, "assignment"),
+            ConstraintCategory::Return => write!(f, "return"),
+            ConstraintCategory::Cast => write!(f, "cast"),
+            ConstraintCategory::CallArgument => write!(f, "argument"),
+            _ => write!(f, "free region"),
         }
     }
 }
diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr
index 9b5fcbc56d5cd..a62d81c033333 100644
--- a/src/test/ui/borrowck/issue-45983.nll.stderr
+++ b/src/test/ui/borrowck/issue-45983.nll.stderr
@@ -4,7 +4,7 @@ warning: not reporting region error due to nll
 LL |     give_any(|y| x = Some(y));
    |                           ^
 
-error: Assignment requires that data must outlive free region `'_#2r`
+error: assignment requires that data must outlive free region `'_#2r`
   --> $DIR/issue-45983.rs:17:27
    |
 LL |     give_any(|y| x = Some(y));
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
index 91161d6820c34..7a4db0802a846 100644
--- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
+++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
@@ -4,7 +4,7 @@ warning: not reporting region error due to nll
 LL |     with_int(|y| x = Some(y));
    |                           ^
 
-error: Assignment requires that data must outlive free region `'_#2r`
+error: assignment requires that data must outlive free region `'_#2r`
   --> $DIR/regions-escape-bound-fn-2.rs:18:27
    |
 LL |     with_int(|y| x = Some(y));
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
index 248933fc39e14..5a71e75d4b2cd 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
@@ -31,7 +31,7 @@ fn case1() {
     foo(cell, |cell_a, cell_x| {
         //~^ WARNING not reporting region error due to nll
         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
-        //~^ ERROR Argument requires that data must outlive free region
+        //~^ ERROR argument requires that data must outlive free region
     })
 }
 
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 7b1cba1d937f6..656c1b46a3ce5 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -4,7 +4,7 @@ warning: not reporting region error due to nll
 LL |     foo(cell, |cell_a, cell_x| {
    |     ^^^
 
-error: Argument requires that data must outlive free region `'_#1r`
+error: argument requires that data must outlive free region `'_#1r`
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:20
    |
 LL |         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
@@ -17,7 +17,7 @@ LL |       foo(cell, |cell_a, cell_x| {
    |  _______________^
 LL | |         //~^ WARNING not reporting region error due to nll
 LL | |         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
-LL | |         //~^ ERROR Argument requires that data must outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |     })
    | |_____^
    |
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
index 4c8c2b1b95bb0..b25b0e25df211 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
@@ -43,7 +43,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3
 #[rustc_regions]
 fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-        //~^ ERROR Argument requires that data must outlive free region
+        //~^ ERROR argument requires that data must outlive free region
 
         // Only works if 'x: 'y:
         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index 8a18af90e195c..582417b0da934 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -9,7 +9,7 @@ note: External requirements
    |
 LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |  _______________________________________________^
-LL | |         //~^ ERROR Argument requires that data must outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
@@ -23,11 +23,11 @@ LL | |     });
    = note: number of external vids: 2
    = note: where '_#1r: '_#0r
 
-error: Argument requires that data must outlive free region `ReStatic`
+error: argument requires that data must outlive free region `ReStatic`
   --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5
    |
 LL | /     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-LL | |         //~^ ERROR Argument requires that data must outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
@@ -39,7 +39,7 @@ note: No external requirements
    |
 LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
 LL | |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-LL | |         //~^ ERROR Argument requires that data must outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |
 ...  |
 LL | |     });
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
index d9cfea4c891c4..db9951bcc0f21 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
@@ -46,7 +46,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3
 #[rustc_regions]
 fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-        //~^ ERROR Argument requires that data must outlive free region
+        //~^ ERROR argument requires that data must outlive free region
         // Only works if 'x: 'y:
         demand_y(x, y, x.get())
         //~^ WARNING not reporting region error due to nll
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index dda1c44b4d8b4..481ba512972fa 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -9,7 +9,7 @@ note: External requirements
    |
 LL |       establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
    |  _______________________________________________^
-LL | |         //~^ ERROR Argument requires that data must outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARNING not reporting region error due to nll
@@ -23,11 +23,11 @@ LL | |     });
    = note: number of external vids: 3
    = note: where '_#1r: '_#0r
 
-error: Argument requires that data must outlive free region `ReStatic`
+error: argument requires that data must outlive free region `ReStatic`
   --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5
    |
 LL | /     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-LL | |         //~^ ERROR Argument requires that data must outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARNING not reporting region error due to nll
@@ -39,7 +39,7 @@ note: No external requirements
    |
 LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
 LL | |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-LL | |         //~^ ERROR Argument requires that data must outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |         // Only works if 'x: 'y:
 ...  |
 LL | |     });
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
index 480461b6b639c..316268e7e726d 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
@@ -46,7 +46,7 @@ fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
         // Only works if 'x: 'y:
         demand_y(x, y, x.get())
         //~^ WARN not reporting region error due to nll
-        //~| ERROR Argument requires that data must outlive free region
+        //~| ERROR argument requires that data must outlive free region
     });
 }
 
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 00e4c289e7eb5..74c0576e03b62 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
@@ -4,7 +4,7 @@ warning: not reporting region error due to nll
 LL |         demand_y(x, y, x.get())
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Argument requires that data must outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))`
+error: argument requires that data must outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))`
   --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9
    |
 LL |         demand_y(x, y, x.get())
@@ -18,7 +18,7 @@ LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARN not reporting region error due to nll
-LL | |         //~| ERROR Argument requires that data must outlive free region
+LL | |         //~| ERROR argument requires that data must outlive free region
 LL | |     });
    | |_____^
    |
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
index 5e695f3f7c7d7..3832be6288aef 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
@@ -55,7 +55,7 @@ where
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR Argument requires that data must outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -67,7 +67,7 @@ where
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR Argument requires that data must outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -89,7 +89,7 @@ where
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR Argument requires that data must outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
index fac0a0b0064c0..898c995e09b9d 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -40,7 +40,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |
    = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`...
 
-error: Argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
+error: argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
   --> $DIR/projection-one-region-closure.rs:55:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
@@ -54,7 +54,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | | {
 ...  |
-LL | |     //~| ERROR Argument requires that data must outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -88,7 +88,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |
    = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
 
-error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
   --> $DIR/projection-one-region-closure.rs:67:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
@@ -102,7 +102,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     'a: 'a,
 ...  |
-LL | |     //~| ERROR Argument requires that data must outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -137,7 +137,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |
    = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
 
-error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
   --> $DIR/projection-one-region-closure.rs:89:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
@@ -151,7 +151,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     T::AssocType: 'a,
 ...  |
-LL | |     //~| ERROR Argument requires that data must outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
index 24d1753eea826..da76193459b30 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
@@ -46,7 +46,7 @@ where
 {
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR Argument requires that data must outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -57,7 +57,7 @@ where
 {
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR Argument requires that data must outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -78,7 +78,7 @@ where
 
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR Argument requires that data must outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
index 07e65fb405158..be11c6249f0ba 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -31,7 +31,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 3
    = note: where '_#1r: '_#2r
 
-error: Argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
+error: argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
   --> $DIR/projection-one-region-trait-bound-closure.rs:47:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
@@ -45,7 +45,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | | {
 ...  |
-LL | |     //~| ERROR Argument requires that data must outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -70,7 +70,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 4
    = note: where '_#2r: '_#3r
 
-error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
   --> $DIR/projection-one-region-trait-bound-closure.rs:58:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
@@ -84,7 +84,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     'a: 'a,
 ...  |
-LL | |     //~| ERROR Argument requires that data must outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -110,7 +110,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 4
    = note: where '_#2r: '_#3r
 
-error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
   --> $DIR/projection-one-region-trait-bound-closure.rs:79:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
@@ -124,7 +124,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     T::AssocType: 'a,
 ...  |
-LL | |     //~| ERROR Argument requires that data must outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
index 8129f93736b64..5e481a9626f08 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
@@ -107,7 +107,7 @@ where
 {
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR Argument requires that data must outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index c778f23a2c450..546384e8545e3 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -239,7 +239,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 3
    = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
 
-error: Argument requires that data must outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))`
+error: argument requires that data must outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))`
   --> $DIR/projection-two-region-trait-bound-closure.rs:108:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
@@ -253,7 +253,7 @@ LL | | where
 LL | |     T: Anything<'b, 'b>,
 LL | | {
 ...  |
-LL | |     //~| ERROR Argument requires that data must outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
index 681c0dce7d172..49f9044b19b24 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
@@ -22,7 +22,7 @@ warning: not reporting region error due to nll
 LL |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: Cast requires that data must outlive free region `'static`
+error: cast requires that data must outlive free region `'static`
   --> $DIR/dyn-trait-underscore.rs:18:5
    |
 LL |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime

From f334a9e8dd3438fb2f827b8f3932b18ae50e76ce Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Thu, 28 Jun 2018 15:00:00 -0400
Subject: [PATCH 13/15] WIP boring() long line

---
 src/librustc_mir/borrow_check/nll/type_check/mod.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 911e543425916..e3d20d9a8dbcb 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -1523,7 +1523,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
         };
 
-        self.normalize_and_prove_instantiated_predicates(instantiated_predicates, location.boring());
+        self.normalize_and_prove_instantiated_predicates(
+            instantiated_predicates,
+            location.boring(),
+        );
     }
 
     fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations) {

From 15aad8356083e6098f7e8aefa1293b68201ec43c Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Fri, 29 Jun 2018 22:17:35 +0100
Subject: [PATCH 14/15] Fix infinite loops when regions are self-referential.

---
 .../nll/region_infer/error_reporting.rs            | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
index f3372f6be703b..970652d8872cd 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
@@ -63,12 +63,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // Regions that have been visited.
         let mut visited = FxHashSet();
         // Ends of paths.
-        let mut end_regions: Vec<RegionVid> = Vec::new();
+        let mut end_regions = FxHashSet();
 
         // When we've still got points to visit...
         while let Some(current) = next.pop() {
             // ...take the next point...
-            debug!("find_constraint_paths_from_region: current={:?} next={:?}", current, next);
+            debug!("find_constraint_paths_from_region: current={:?} visited={:?} next={:?}",
+                   current, visited, next);
+            // ...but make sure not to visit this point again...
+            visited.insert(current);
 
             // ...find the edges containing it...
             let mut upcoming = Vec::new();
@@ -93,16 +96,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             if upcoming.is_empty() {
                 // If we didn't find any edges then this is the end of a path...
                 debug!("find_constraint_paths_from_region: new end region current={:?}", current);
-                end_regions.push(current);
+                end_regions.insert(current);
             } else {
-                // ...but, if we did find edges, then add these to the regions yet to visit...
+                // ...but, if we did find edges, then add these to the regions yet to visit.
                 debug!("find_constraint_paths_from_region: extend next upcoming={:?}", upcoming);
                 next.extend(upcoming);
             }
 
-            // ...and don't visit it again.
-            visited.insert(current.clone());
-            debug!("find_constraint_paths_from_region: next={:?} visited={:?}", next, visited);
         }
 
         // Now we've visited each point, compute the final paths.

From c0c4741ef794d707a4378ace1547e8a41961016a Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Sat, 30 Jun 2018 00:10:00 +0100
Subject: [PATCH 15/15] Updated affected tests after rebase.

---
 src/test/ui/borrowck/issue-45983.nll.stderr                   | 2 +-
 src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr     | 2 +-
 .../propagate-approximated-shorter-to-static-no-bound.stderr  | 2 +-
 ...ropagate-approximated-shorter-to-static-wrong-bound.stderr | 2 +-
 src/test/ui/nll/issue-50716.rs                                | 2 +-
 src/test/ui/nll/issue-50716.stderr                            | 4 ++--
 6 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr
index a62d81c033333..a008a408d9711 100644
--- a/src/test/ui/borrowck/issue-45983.nll.stderr
+++ b/src/test/ui/borrowck/issue-45983.nll.stderr
@@ -4,7 +4,7 @@ warning: not reporting region error due to nll
 LL |     give_any(|y| x = Some(y));
    |                           ^
 
-error: assignment requires that data must outlive free region `'_#2r`
+error: free region `` does not outlive free region `'_#2r`
   --> $DIR/issue-45983.rs:17:27
    |
 LL |     give_any(|y| x = Some(y));
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
index 7a4db0802a846..ee3970aa8fd8f 100644
--- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
+++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
@@ -4,7 +4,7 @@ warning: not reporting region error due to nll
 LL |     with_int(|y| x = Some(y));
    |                           ^
 
-error: assignment requires that data must outlive free region `'_#2r`
+error: free region `` does not outlive free region `'_#2r`
   --> $DIR/regions-escape-bound-fn-2.rs:18:27
    |
 LL |     with_int(|y| x = Some(y));
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index 582417b0da934..40f215619c689 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -32,7 +32,7 @@ LL | |
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
 LL | |     });
-   | |_____^
+   | |______^
 
 note: No external requirements
   --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 481ba512972fa..d89ff028a5042 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -32,7 +32,7 @@ LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARNING not reporting region error due to nll
 LL | |     });
-   | |_____^
+   | |______^
 
 note: No external requirements
   --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1
diff --git a/src/test/ui/nll/issue-50716.rs b/src/test/ui/nll/issue-50716.rs
index 310600aaf9ac8..a41af168c3e4e 100644
--- a/src/test/ui/nll/issue-50716.rs
+++ b/src/test/ui/nll/issue-50716.rs
@@ -22,7 +22,7 @@ where
     for<'b> &'b T: A,
     <&'static T as A>::X: Sized
 {
-    let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static`
+    let _x = *s; //~ ERROR assignment requires that data must outlive free region `'static`
 }
 
 fn main() {}
diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr
index 20b03d648d9b6..de69f8cfbcb6e 100644
--- a/src/test/ui/nll/issue-50716.stderr
+++ b/src/test/ui/nll/issue-50716.stderr
@@ -1,7 +1,7 @@
-error: free region `'a` does not outlive free region `'static`
+error: assignment requires that data must outlive free region `'static`
   --> $DIR/issue-50716.rs:25:14
    |
-LL |     let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static`
+LL |     let _x = *s; //~ ERROR assignment requires that data must outlive free region `'static`
    |              ^^
 
 error: aborting due to previous error