about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/diagnostics.rs60
-rw-r--r--src/librustc/infer/error_reporting/different_lifetimes.rs (renamed from src/librustc/infer/error_reporting/anon_anon_conflict.rs)126
-rw-r--r--src/librustc/infer/error_reporting/mod.rs2
-rw-r--r--src/librustc/infer/error_reporting/named_anon_conflict.rs50
-rw-r--r--src/librustc/infer/error_reporting/util.rs178
-rw-r--r--src/librustc/ty/sty.rs13
-rw-r--r--src/test/compile-fail/associated-types-subtyping-1.rs4
-rw-r--r--src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs2
-rw-r--r--src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs4
-rw-r--r--src/test/compile-fail/regions-free-region-ordering-caller.rs10
-rw-r--r--src/test/compile-fail/regions-infer-contravariance-due-to-decl.rs2
-rw-r--r--src/test/compile-fail/regions-infer-covariance-due-to-decl.rs2
-rw-r--r--src/test/compile-fail/regions-lifetime-bounds-on-fns.rs2
-rw-r--r--src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs2
-rw-r--r--src/test/compile-fail/regions-variance-contravariant-use-covariant.rs2
-rw-r--r--src/test/compile-fail/regions-variance-covariant-use-contravariant.rs2
-rw-r--r--src/test/compile-fail/regions-variance-invariant-use-contravariant.rs2
-rw-r--r--src/test/compile-fail/variance-cell-is-invariant.rs2
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.rs21
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.stderr11
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.rs15
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr10
22 files changed, 344 insertions, 178 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index be7bb4d8114..717d0b0c3be 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1389,30 +1389,66 @@ A lifetime of reference outlives lifetime of borrowed content.
 Erroneous code example:
 
 ```compile_fail,E0312
-fn make_child<'human, 'elve>(x: &mut &'human isize, y: &mut &'elve isize) {
-    *x = *y;
-    // error: lifetime of reference outlives lifetime of borrowed content
+fn make_child<'tree, 'human>(
+  x: &'human i32,
+  y: &'tree i32
+) -> &'human i32 {
+    if x > y
+       { x }
+    else
+       { y }
+       // error: lifetime of reference outlives lifetime of borrowed content
 }
 ```
 
-The compiler cannot determine if the `human` lifetime will live long enough
-to keep up on the elve one. To solve this error, you have to give an
-explicit lifetime hierarchy:
+The function declares that it returns a reference with the `'human`
+lifetime, but it may return data with the `'tree` lifetime. As neither
+lifetime is declared longer than the other, this results in an
+error. Sometimes, this error is because the function *body* is
+incorrect -- that is, maybe you did not *mean* to return data from
+`y`. In that case, you should fix the function body.
+
+Often, however, the body is correct. In that case, the function
+signature needs to be altered to match the body, so that the caller
+understands that data from either `x` or `y` may be returned. The
+simplest way to do this is to give both function parameters the *same*
+named lifetime:
 
 ```
-fn make_child<'human, 'elve: 'human>(x: &mut &'human isize,
-                                     y: &mut &'elve isize) {
-    *x = *y; // ok!
+fn make_child<'human>(
+  x: &'human i32,
+  y: &'human i32
+) -> &'human i32 {
+    if x > y
+       { x }
+    else
+       { y } // ok!
 }
 ```
 
-Or use the same lifetime for every variable:
+However, in some cases, you may prefer to explicitly declare that one lifetime
+outlives another using a `where` clause:
 
 ```
-fn make_child<'elve>(x: &mut &'elve isize, y: &mut &'elve isize) {
-    *x = *y; // ok!
+fn make_child<'tree, 'human>(
+  x: &'human i32,
+  y: &'tree i32
+) -> &'tree i32
+where
+  'tree: 'human
+{
+    if x > y
+       { x }
+    else
+       { y } // ok!
 }
 ```
+
+Here, the where clause `'tree: 'human` can be read as "the lifetime
+'tree outlives the lifetime 'human" -- meaning, references with the
+`'tree` lifetime live *at least as long as* references with the
+`'human` lifetime. Therefore, it is safe to return data with lifetime
+`'tree` when data with the lifetime `'human` is needed.
 "##,
 
 E0317: r##"
diff --git a/src/librustc/infer/error_reporting/anon_anon_conflict.rs b/src/librustc/infer/error_reporting/different_lifetimes.rs
index d3fff4c66af..23f6d1a3fb0 100644
--- a/src/librustc/infer/error_reporting/anon_anon_conflict.rs
+++ b/src/librustc/infer/error_reporting/different_lifetimes.rs
@@ -46,9 +46,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         };
 
         // Determine whether the sub and sup consist of both anonymous (elided) regions.
-        let anon_reg_sup = or_false!(self.is_suitable_anonymous_region(sup));
+        let anon_reg_sup = or_false!(self.is_suitable_region(sup));
 
-        let anon_reg_sub = or_false!(self.is_suitable_anonymous_region(sub));
+        let anon_reg_sub = or_false!(self.is_suitable_region(sub));
         let scope_def_id_sup = anon_reg_sup.def_id;
         let bregion_sup = anon_reg_sup.boundregion;
         let scope_def_id_sub = anon_reg_sub.def_id;
@@ -57,10 +57,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         let ty_sup = or_false!(self.find_anon_type(sup, &bregion_sup));
 
         let ty_sub = or_false!(self.find_anon_type(sub, &bregion_sub));
+        debug!("try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}",
+               ty_sub,
+               sup,
+               bregion_sup);
+        debug!("try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}",
+               ty_sup,
+               sub,
+               bregion_sub);
 
         let (main_label, label1, label2) = if let (Some(sup_arg), Some(sub_arg)) =
-            (self.find_arg_with_anonymous_region(sup, sup),
-             self.find_arg_with_anonymous_region(sub, sub)) {
+            (self.find_arg_with_region(sup, sup), self.find_arg_with_region(sub, sub)) {
 
             let (anon_arg_sup, is_first_sup, anon_arg_sub, is_first_sub) =
                 (sup_arg.arg, sup_arg.is_first, sub_arg.arg, sub_arg.is_first);
@@ -97,6 +104,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 (span_label, span_label_var1, span_label_var2)
             }
         } else {
+            debug!("no arg with anon region found");
+            debug!("try_report_anon_anon_conflict: is_suitable(sub) = {:?}",
+                   self.is_suitable_region(sub));
+            debug!("try_report_anon_anon_conflict: is_suitable(sup) = {:?}",
+                   self.is_suitable_region(sup));
             return false;
         };
 
@@ -124,35 +136,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// The function returns the nested type corresponding to the anonymous region
     /// for e.g. `&u8` and Vec<`&u8`.
     pub fn find_anon_type(&self, region: Region<'tcx>, br: &ty::BoundRegion) -> Option<&hir::Ty> {
-        if let Some(anon_reg) = self.is_suitable_anonymous_region(region) {
+        if let Some(anon_reg) = self.is_suitable_region(region) {
             let def_id = anon_reg.def_id;
             if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
-                let ret_ty = self.tcx.type_of(def_id);
-                if let ty::TyFnDef(_, _) = ret_ty.sty {
-                    let inputs: &[_] =
-                        match self.tcx.hir.get(node_id) {
-                            hir_map::NodeItem(&hir::Item {
-                                                  node: hir::ItemFn(ref fndecl, ..), ..
-                                              }) => &fndecl.inputs,
-                            hir_map::NodeTraitItem(&hir::TraitItem {
-                                                   node: hir::TraitItemKind::Method(ref fndecl, ..),
-                                                   ..
-                                               }) => &fndecl.decl.inputs,
-                            hir_map::NodeImplItem(&hir::ImplItem {
-                                                  node: hir::ImplItemKind::Method(ref fndecl, ..),
-                                                  ..
-                                              }) => &fndecl.decl.inputs,
+                let inputs: &[_] = match self.tcx.hir.get(node_id) {
+                    hir_map::NodeItem(&hir::Item { node: hir::ItemFn(ref fndecl, ..), .. }) => {
+                        &fndecl.inputs
+                    }
+                    hir_map::NodeTraitItem(&hir::TraitItem {
+                                               node: hir::TraitItemKind::Method(ref fndecl, ..), ..
+                                           }) => &fndecl.decl.inputs,
+                    hir_map::NodeImplItem(&hir::ImplItem {
+                                              node: hir::ImplItemKind::Method(ref fndecl, ..), ..
+                                          }) => &fndecl.decl.inputs,
 
-                            _ => &[],
-                        };
+                    _ => &[],
+                };
 
-                    return inputs
-                               .iter()
-                               .filter_map(|arg| {
-                                               self.find_component_for_bound_region(&**arg, br)
-                                           })
-                               .next();
-                }
+                return inputs
+                           .iter()
+                           .filter_map(|arg| self.find_component_for_bound_region(&**arg, br))
+                           .next();
             }
         }
         None
@@ -199,30 +203,62 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
     }
 
     fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
-        // Find the index of the anonymous region that was part of the
-        // error. We will then search the function parameters for a bound
-        // region at the right depth with the same index.
-        let br_index = match self.bound_region {
-            ty::BrAnon(index) => index,
-            _ => return,
-        };
-
         match arg.node {
             hir::TyRptr(ref lifetime, _) => {
+                // the lifetime of the TyRptr
                 let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id);
-                match self.infcx.tcx.named_region(hir_id) {
-                    // the lifetime of the TyRptr
-                    Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)) => {
+                match (self.infcx.tcx.named_region(hir_id), self.bound_region) {
+                    // Find the index of the anonymous region that was part of the
+                    // error. We will then search the function parameters for a bound
+                    // region at the right depth with the same index
+                    (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)),
+                     ty::BrAnon(br_index)) => {
+                        debug!("LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}",
+                               debruijn_index.depth,
+                               anon_index,
+                               br_index);
                         if debruijn_index.depth == 1 && anon_index == br_index {
                             self.found_type = Some(arg);
                             return; // we can stop visiting now
                         }
                     }
-                    Some(rl::Region::Static) |
-                    Some(rl::Region::EarlyBound(_, _)) |
-                    Some(rl::Region::LateBound(_, _)) |
-                    Some(rl::Region::Free(_, _)) |
-                    None => {
+
+                    // Find the index of the named region that was part of the
+                    // error. We will then search the function parameters for a bound
+                    // region at the right depth with the same index
+                    (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+                        debug!("EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \
+                                        def_id={:?}",
+                               self.infcx.tcx.hir.local_def_id(id),
+                               def_id);
+                        if self.infcx.tcx.hir.local_def_id(id) == def_id {
+                            self.found_type = Some(arg);
+                            return; // we can stop visiting now
+                        }
+                    }
+
+                    // Find the index of the named region that was part of the
+                    // error. We will then search the function parameters for a bound
+                    // region at the right depth with the same index
+                    (Some(rl::Region::LateBound(debruijn_index, id)), ty::BrNamed(def_id, _)) => {
+                        debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
+                               debruijn_index.depth);
+                        debug!("self.infcx.tcx.hir.local_def_id(id)={:?}",
+                               self.infcx.tcx.hir.local_def_id(id));
+                        debug!("def_id={:?}", def_id);
+                        if debruijn_index.depth == 1 &&
+                           self.infcx.tcx.hir.local_def_id(id) == def_id {
+                            self.found_type = Some(arg);
+                            return; // we can stop visiting now
+                        }
+                    }
+
+                    (Some(rl::Region::Static), _) |
+                    (Some(rl::Region::Free(_, _)), _) |
+                    (Some(rl::Region::EarlyBound(_, _)), _) |
+                    (Some(rl::Region::LateBound(_, _)), _) |
+                    (Some(rl::Region::LateBoundAnon(_, _)), _) |
+                    (None, _) => {
                         debug!("no arg found");
                     }
                 }
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index ff52f1e4e39..c0d88f6022c 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -79,7 +79,7 @@ mod need_type_info;
 mod named_anon_conflict;
 #[macro_use]
 mod util;
-mod anon_anon_conflict;
+mod different_lifetimes;
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn note_and_explain_region(self,
diff --git a/src/librustc/infer/error_reporting/named_anon_conflict.rs b/src/librustc/infer/error_reporting/named_anon_conflict.rs
index 0aae008396a..a3bbdab497a 100644
--- a/src/librustc/infer/error_reporting/named_anon_conflict.rs
+++ b/src/librustc/infer/error_reporting/named_anon_conflict.rs
@@ -13,6 +13,7 @@
 use infer::InferCtxt;
 use infer::region_inference::RegionResolutionError::*;
 use infer::region_inference::RegionResolutionError;
+use ty;
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // This method generates the error message for the case when
@@ -24,6 +25,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             _ => return false, // inapplicable
         };
 
+        debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})",
+               sub,
+               sup);
+
         // Determine whether the sub and sup consist of one named region ('a)
         // and one anonymous (elided) region. If so, find the parameter arg
         // where the anonymous region appears (there must always be one; we
@@ -31,32 +36,57 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         // version new_ty of its type where the anonymous region is replaced
         // with the named one.//scope_def_id
         let (named, anon_arg_info, region_info) =
-            if sub.is_named_region() && self.is_suitable_anonymous_region(sup).is_some() {
+            if self.is_named_region(sub) && self.is_suitable_region(sup).is_some() &&
+               self.find_arg_with_region(sup, sub).is_some() {
                 (sub,
-                 self.find_arg_with_anonymous_region(sup, sub).unwrap(),
-                 self.is_suitable_anonymous_region(sup).unwrap())
-            } else if sup.is_named_region() && self.is_suitable_anonymous_region(sub).is_some() {
+                 self.find_arg_with_region(sup, sub).unwrap(),
+                 self.is_suitable_region(sup).unwrap())
+            } else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() &&
+                      self.find_arg_with_region(sub, sup).is_some() {
                 (sup,
-                 self.find_arg_with_anonymous_region(sub, sup).unwrap(),
-                 self.is_suitable_anonymous_region(sub).unwrap())
+                 self.find_arg_with_region(sub, sup).unwrap(),
+                 self.is_suitable_region(sub).unwrap())
             } else {
                 return false; // inapplicable
             };
 
+        debug!("try_report_named_anon_conflict: named = {:?}", named);
+        debug!("try_report_named_anon_conflict: anon_arg_info = {:?}",
+               anon_arg_info);
+        debug!("try_report_named_anon_conflict: region_info = {:?}",
+               region_info);
+
         let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
                                                                        anon_arg_info.arg_ty,
                                                                        anon_arg_info.bound_region,
                                                                        anon_arg_info.is_first,
                                                                        region_info.def_id,
                                                                        region_info.is_impl_item);
+        match br {
+            ty::BrAnon(_) => {}
+            _ => {
+                /* not an anonymous region */
+                debug!("try_report_named_anon_conflict: not an anonymous region");
+                return false;
+            }
+        }
+
         if is_impl_item {
+            debug!("try_report_named_anon_conflict: impl item, bail out");
             return false;
         }
 
-        if self.is_return_type_anon(scope_def_id, br) || self.is_self_anon(is_first, scope_def_id) {
+        if self.is_return_type_anon(scope_def_id, br) {
+            debug!("try_report_named_anon_conflict: is_return_type_anon({:?}, {:?}) = true",
+                   scope_def_id,
+                   br);
+            return false;
+        } else if self.is_self_anon(is_first, scope_def_id) {
+            debug!("try_report_named_anon_conflict: is_self_anon({:?}, {:?}) = true",
+                   is_first,
+                   scope_def_id);
             return false;
         } else {
-
             let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
                 (format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
             } else {
@@ -72,9 +102,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                 format!("consider changing {} to `{}`", span_label_var, new_ty))
                     .span_label(span, format!("lifetime `{}` required", named))
                     .emit();
-
-
+            return true;
         }
-        return true;
     }
 }
diff --git a/src/librustc/infer/error_reporting/util.rs b/src/librustc/infer/error_reporting/util.rs
index 04153038da8..b58fa6b0e7c 100644
--- a/src/librustc/infer/error_reporting/util.rs
+++ b/src/librustc/infer/error_reporting/util.rs
@@ -18,15 +18,19 @@ use hir::map as hir_map;
 
 macro_rules! or_false {
      ($v:expr) => {
-          match $v {
-               Some(v) => v,
-               None => return false,
-          }
+         match $v {
+             Some(v) => v,
+             None => {
+                 debug!("or_false failed: {}", stringify!($v));
+                 return false;
+             }
+         }
      }
 }
 
 // The struct contains the information about the anonymous region
 // we are searching for.
+#[derive(Debug)]
 pub struct AnonymousArgInfo<'tcx> {
     // the argument corresponding to the anonymous region
     pub arg: &'tcx hir::Arg,
@@ -41,6 +45,7 @@ pub struct AnonymousArgInfo<'tcx> {
 
 // This struct contains information regarding the
 // Refree((FreeRegion) corresponding to lifetime conflict
+#[derive(Debug)]
 pub struct FreeRegionInfo {
     // def id corresponding to FreeRegion
     pub def_id: DefId,
@@ -62,47 +67,54 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // i32, which is the type of y but with the anonymous region replaced
     // with 'a, the corresponding bound region and is_first which is true if
     // the hir::Arg is the first argument in the function declaration.
-    pub fn find_arg_with_anonymous_region(&self,
-                                          anon_region: Region<'tcx>,
-                                          replace_region: Region<'tcx>)
-                                          -> Option<AnonymousArgInfo> {
-
-        if let ty::ReFree(ref free_region) = *anon_region {
-            let id = free_region.scope;
-            let hir = &self.tcx.hir;
-            if let Some(node_id) = hir.as_local_node_id(id) {
-                if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
-                    let body = hir.body(body_id);
-                    if let Some(tables) = self.in_progress_tables {
-                        body.arguments
-                            .iter()
-                            .enumerate()
-                            .filter_map(|(index, arg)| {
-                                let ty = tables.borrow().node_id_to_type(arg.hir_id);
-                                let mut found_anon_region = false;
-                                let new_arg_ty = self.tcx
-                                    .fold_regions(&ty, &mut false, |r, _| if *r == *anon_region {
-                                        found_anon_region = true;
-                                        replace_region
-                                    } else {
-                                        r
-                                    });
-                                if found_anon_region {
-                                    let is_first = index == 0;
-                                    Some(AnonymousArgInfo {
-                                             arg: arg,
-                                             arg_ty: new_arg_ty,
-                                             bound_region: free_region.bound_region,
-                                             is_first: is_first,
-                                         })
+    pub fn find_arg_with_region(&self,
+                                anon_region: Region<'tcx>,
+                                replace_region: Region<'tcx>)
+                                -> Option<AnonymousArgInfo> {
+
+        let (id, bound_region) = match *anon_region {
+            ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
+            ty::ReEarlyBound(ref ebr) => {
+                (self.tcx.parent_def_id(ebr.def_id).unwrap(),
+                 ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
+            }
+            _ => return None, // not a free region
+        };
+
+        let hir = &self.tcx.hir;
+        if let Some(node_id) = hir.as_local_node_id(id) {
+            if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
+                let body = hir.body(body_id);
+                if let Some(tables) = self.in_progress_tables {
+                    body.arguments
+                        .iter()
+                        .enumerate()
+                        .filter_map(|(index, arg)| {
+                            let ty = match tables.borrow().node_id_to_type_opt(arg.hir_id) {
+                                Some(v) => v,
+                                None => return None, // sometimes the tables are not yet populated
+                            };
+                            let mut found_anon_region = false;
+                            let new_arg_ty = self.tcx
+                                .fold_regions(&ty, &mut false, |r, _| if *r == *anon_region {
+                                    found_anon_region = true;
+                                    replace_region
                                 } else {
-                                    None
-                                }
-                            })
-                            .next()
-                    } else {
-                        None
-                    }
+                                    r
+                                });
+                            if found_anon_region {
+                                let is_first = index == 0;
+                                Some(AnonymousArgInfo {
+                                         arg: arg,
+                                         arg_ty: new_arg_ty,
+                                         bound_region: bound_region,
+                                         is_first: is_first,
+                                     })
+                            } else {
+                                None
+                            }
+                        })
+                        .next()
                 } else {
                     None
                 }
@@ -114,37 +126,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    // This method returns whether the given Region is Anonymous
-    // and returns the DefId and the BoundRegion corresponding to the given region.
-    pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
-        if let ty::ReFree(ref free_region) = *region {
-            if let ty::BrAnon(..) = free_region.bound_region {
-                let anonymous_region_binding_scope = free_region.scope;
-                let node_id = self.tcx
-                    .hir
-                    .as_local_node_id(anonymous_region_binding_scope)
-                    .unwrap();
-                let mut is_impl_item = false;
-                match self.tcx.hir.find(node_id) {
-
-                    Some(hir_map::NodeItem(..)) |
-                    Some(hir_map::NodeTraitItem(..)) => {
-                        // Success -- proceed to return Some below
-                    }
-                    Some(hir_map::NodeImplItem(..)) => {
-                        is_impl_item =
-                            self.is_bound_region_in_impl_item(anonymous_region_binding_scope);
-                    }
-                    _ => return None,
-                }
-                return Some(FreeRegionInfo {
-                                def_id: anonymous_region_binding_scope,
-                                boundregion: free_region.bound_region,
-                                is_impl_item: is_impl_item,
-                            });
+    // This method returns the DefId and the BoundRegion corresponding to the given region.
+    pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
+
+        let (suitable_region_binding_scope, bound_region) = match *region {
+            ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
+            ty::ReEarlyBound(ref ebr) => {
+                (self.tcx.parent_def_id(ebr.def_id).unwrap(),
+                 ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
             }
-        }
-        None
+            _ => return None, // not a free region
+        };
+
+        let node_id = self.tcx
+            .hir
+            .as_local_node_id(suitable_region_binding_scope)
+            .unwrap();
+        let is_impl_item = match self.tcx.hir.find(node_id) {
+
+            Some(hir_map::NodeItem(..)) |
+            Some(hir_map::NodeTraitItem(..)) => false,
+            Some(hir_map::NodeImplItem(..)) => {
+                self.is_bound_region_in_impl_item(suitable_region_binding_scope)
+            }
+            _ => return None,
+        };
+
+        return Some(FreeRegionInfo {
+                        def_id: suitable_region_binding_scope,
+                        boundregion: bound_region,
+                        is_impl_item: is_impl_item,
+                    });
+
     }
 
     // Here, we check for the case where the anonymous region
@@ -177,9 +190,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     // Here we check if the bound region is in Impl Item.
-    pub fn is_bound_region_in_impl_item(&self, anonymous_region_binding_scope: DefId) -> bool {
+    pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: DefId) -> bool {
         let container_id = self.tcx
-            .associated_item(anonymous_region_binding_scope)
+            .associated_item(suitable_region_binding_scope)
             .container
             .id();
         if self.tcx.impl_trait_ref(container_id).is_some() {
@@ -193,4 +206,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
         false
     }
+
+    // This method returns whether the given Region is Named
+    pub fn is_named_region(&self, region: Region<'tcx>) -> bool {
+        match *region {
+            ty::ReFree(ref free_region) => {
+                match free_region.bound_region {
+                    ty::BrNamed(..) => true,
+                    _ => false,
+                }
+            }
+            _ => false,
+        }
+    }
 }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index fc244cabcd1..14ea66a1b67 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1041,19 +1041,6 @@ impl RegionKind {
 
         flags
     }
-
-    // This method returns whether the given Region is Named
-    pub fn is_named_region(&self) -> bool {
-        match *self {
-            ty::ReFree(ref free_region) => {
-                match free_region.bound_region {
-                    ty::BrNamed(..) => true,
-                    _ => false,
-                }
-            }
-            _ => false,
-        }
-    }
 }
 
 /// Type utilities
diff --git a/src/test/compile-fail/associated-types-subtyping-1.rs b/src/test/compile-fail/associated-types-subtyping-1.rs
index f9106ba3960..64dcdd39e7c 100644
--- a/src/test/compile-fail/associated-types-subtyping-1.rs
+++ b/src/test/compile-fail/associated-types-subtyping-1.rs
@@ -31,7 +31,7 @@ fn method2<'a,'b,T>(x: &'a T, y: &'b T)
     // Note that &'static T <: &'a T.
     let a: <T as Trait<'a>>::Type = loop { };
     let b: <T as Trait<'b>>::Type = loop { };
-    let _: <T as Trait<'b>>::Type = a; //~ ERROR mismatched types
+    let _: <T as Trait<'b>>::Type = a; //~ ERROR E0623
 }
 
 fn method3<'a,'b,T>(x: &'a T, y: &'b T)
@@ -40,7 +40,7 @@ fn method3<'a,'b,T>(x: &'a T, y: &'b T)
     // Note that &'static T <: &'a T.
     let a: <T as Trait<'a>>::Type = loop { };
     let b: <T as Trait<'b>>::Type = loop { };
-    let _: <T as Trait<'a>>::Type = b; //~ ERROR mismatched types
+    let _: <T as Trait<'a>>::Type = b; //~ ERROR E0623
 }
 
 fn method4<'a,'b,T>(x: &'a T, y: &'b T)
diff --git a/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs b/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs
index 6364db1f4b4..f886c0255cc 100644
--- a/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs
+++ b/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs
@@ -15,7 +15,7 @@ fn a<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) where 'b: 'a {
 
 fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
     // Illegal now because there is no `'b:'a` declaration.
-    *x = *y; //~ ERROR E0312
+    *x = *y; //~ ERROR E0623
 }
 
 fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
diff --git a/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs b/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs
index 154135eba38..bae9608c3f0 100644
--- a/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs
+++ b/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs
@@ -16,8 +16,8 @@ fn a<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) where
 
 fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
     // Illegal now because there is no `'b:'a` declaration.
-    *x = *y; //~ ERROR E0312
-    *z = *y; //~ ERROR E0312
+    *x = *y; //~ ERROR E0623
+    *z = *y; //~ ERROR E0623
 }
 
 fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
diff --git a/src/test/compile-fail/regions-free-region-ordering-caller.rs b/src/test/compile-fail/regions-free-region-ordering-caller.rs
index edca3b7ed41..66b16744cc7 100644
--- a/src/test/compile-fail/regions-free-region-ordering-caller.rs
+++ b/src/test/compile-fail/regions-free-region-ordering-caller.rs
@@ -15,20 +15,16 @@
 struct Paramd<'a> { x: &'a usize }
 
 fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
-    let z: Option<&'b &'a usize> = None;
-    //~^ ERROR reference has a longer lifetime than the data it references
+    let z: Option<&'b &'a usize> = None;//~ ERROR E0623
 }
 
 fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
     let y: Paramd<'a> = Paramd { x: a };
-    let z: Option<&'b Paramd<'a>> = None;
-    //~^ ERROR reference has a longer lifetime than the data it references
+    let z: Option<&'b Paramd<'a>> = None;//~ ERROR E0623
 }
 
 fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
-    let z: Option<&'a &'b usize> = None;
-    //~^ ERROR reference has a longer lifetime than the data it references
+    let z: Option<&'a &'b usize> = None;//~ ERROR E0623
 }
 
-
 fn main() {}
diff --git a/src/test/compile-fail/regions-infer-contravariance-due-to-decl.rs b/src/test/compile-fail/regions-infer-contravariance-due-to-decl.rs
index b7ef19d1e3b..6e1c765724b 100644
--- a/src/test/compile-fail/regions-infer-contravariance-due-to-decl.rs
+++ b/src/test/compile-fail/regions-infer-contravariance-due-to-decl.rs
@@ -32,7 +32,7 @@ fn use_<'short,'long>(c: Contravariant<'short>,
     // 'short <= 'long, this would be true if the Contravariant type were
     // covariant with respect to its parameter 'a.
 
-    let _: Contravariant<'long> = c; //~ ERROR mismatched types
+    let _: Contravariant<'long> = c; //~ ERROR E0623
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-infer-covariance-due-to-decl.rs b/src/test/compile-fail/regions-infer-covariance-due-to-decl.rs
index 0d3d9dacbd6..1ab8ba4439b 100644
--- a/src/test/compile-fail/regions-infer-covariance-due-to-decl.rs
+++ b/src/test/compile-fail/regions-infer-covariance-due-to-decl.rs
@@ -29,7 +29,7 @@ fn use_<'short,'long>(c: Covariant<'long>,
     // 'short <= 'long, this would be true if the Covariant type were
     // contravariant with respect to its parameter 'a.
 
-    let _: Covariant<'short> = c; //~ ERROR mismatched types
+    let _: Covariant<'short> = c; //~ ERROR E0623
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs
index 89254516ac6..ef1c58bf972 100644
--- a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs
+++ b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs
@@ -15,7 +15,7 @@ fn a<'a, 'b:'a>(x: &mut &'a isize, y: &mut &'b isize) {
 
 fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
     // Illegal now because there is no `'b:'a` declaration.
-    *x = *y; //~ ERROR E0312
+    *x = *y; //~ ERROR E0623
 }
 
 fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
diff --git a/src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs b/src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs
index a7ef3ec9ac1..1dfebd54ec3 100644
--- a/src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs
+++ b/src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs
@@ -32,7 +32,7 @@ fn use_<'short,'long>(c: S<'long, 'short>,
     // 'short <= 'long, this would be true if the Contravariant type were
     // covariant with respect to its parameter 'a.
 
-    let _: S<'long, 'long> = c; //~ ERROR mismatched types
+    let _: S<'long, 'long> = c; //~ ERROR E0623
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs b/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs
index a79249ade4f..caf6a86fc0b 100644
--- a/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs
+++ b/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs
@@ -30,7 +30,7 @@ fn use_<'short,'long>(c: Contravariant<'short>,
     // 'short <= 'long, this would be true if the Contravariant type were
     // covariant with respect to its parameter 'a.
 
-    let _: Contravariant<'long> = c; //~ ERROR mismatched types
+    let _: Contravariant<'long> = c; //~ ERROR E0623
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs
index f42b7027d9e..60dc3d94a2e 100644
--- a/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs
+++ b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs
@@ -30,7 +30,7 @@ fn use_<'short,'long>(c: Covariant<'long>,
     // 'short <= 'long, this would be true if the Covariant type were
     // contravariant with respect to its parameter 'a.
 
-    let _: Covariant<'short> = c; //~ ERROR mismatched types
+    let _: Covariant<'short> = c; //~ ERROR E0623
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs
index 71023b26c27..96478fa5909 100644
--- a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs
+++ b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs
@@ -27,7 +27,7 @@ fn use_<'short,'long>(c: Invariant<'long>,
     // 'short <= 'long, this would be true if the Invariant type were
     // contravariant with respect to its parameter 'a.
 
-    let _: Invariant<'short> = c; //~ ERROR mismatched types
+    let _: Invariant<'short> = c; //~ ERROR E0623
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/variance-cell-is-invariant.rs b/src/test/compile-fail/variance-cell-is-invariant.rs
index b8a8f9ad91c..1ddbcf4ab84 100644
--- a/src/test/compile-fail/variance-cell-is-invariant.rs
+++ b/src/test/compile-fail/variance-cell-is-invariant.rs
@@ -21,7 +21,7 @@ fn use_<'short,'long>(c: Foo<'short>,
                       s: &'short isize,
                       l: &'long isize,
                       _where:Option<&'short &'long ()>) {
-    let _: Foo<'long> = c; //~ ERROR mismatched types
+    let _: Foo<'long> = c; //~ ERROR E0623
 }
 
 fn main() {
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.rs
new file mode 100644
index 00000000000..5d182008209
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.rs
@@ -0,0 +1,21 @@
+// 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.
+trait Foo<'a> {}
+impl<'a, T> Foo<'a> for T {}
+
+fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
+    where i32: Foo<'a>,
+          u32: Foo<'b>
+{
+    x.push(y);
+}
+fn main() {
+let x = baz;
+}
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.stderr
new file mode 100644
index 00000000000..58f2cb94cec
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.stderr
@@ -0,0 +1,11 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-earlybound-regions.rs:17:12
+   |
+13 | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
+   |                               -----      -- these two types are declared with different lifetimes...
+...
+17 |     x.push(y);
+   |            ^ ...but data from `y` flows into `x` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.rs
new file mode 100644
index 00000000000..5abfc983f88
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.rs
@@ -0,0 +1,15 @@
+// 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.
+
+fn foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) {
+    x.push(y);
+}
+
+fn main() { }
\ No newline at end of file
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr
new file mode 100644
index 00000000000..be628f226d3
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-latebound-regions.rs:12:12
+   |
+11 | fn foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) {
+   |                           ------      ------ these two types are declared with different lifetimes...
+12 |     x.push(y);
+   |            ^ ...but data from `y` flows into `x` here
+
+error: aborting due to previous error
+