]> git.lizzy.rs Git - rust.git/commitdiff
adding E0623 for LateBound regions
authorgaurikholkar <f2013002@goa.bits-pilani.ac.in>
Fri, 25 Aug 2017 06:21:22 +0000 (11:51 +0530)
committergaurikholkar <f2013002@goa.bits-pilani.ac.in>
Sat, 9 Sep 2017 05:42:27 +0000 (11:12 +0530)
23 files changed:
src/librustc/diagnostics.rs
src/librustc/infer/error_reporting/anon_anon_conflict.rs [deleted file]
src/librustc/infer/error_reporting/different_lifetimes.rs [new file with mode: 0644]
src/librustc/infer/error_reporting/mod.rs
src/librustc/infer/error_reporting/named_anon_conflict.rs
src/librustc/infer/error_reporting/util.rs
src/librustc/ty/sty.rs
src/test/compile-fail/associated-types-subtyping-1.rs
src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs
src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs
src/test/compile-fail/regions-free-region-ordering-caller.rs
src/test/compile-fail/regions-infer-contravariance-due-to-decl.rs
src/test/compile-fail/regions-infer-covariance-due-to-decl.rs
src/test/compile-fail/regions-lifetime-bounds-on-fns.rs
src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs
src/test/compile-fail/regions-variance-contravariant-use-covariant.rs
src/test/compile-fail/regions-variance-covariant-use-contravariant.rs
src/test/compile-fail/regions-variance-invariant-use-contravariant.rs
src/test/compile-fail/variance-cell-is-invariant.rs
src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.rs [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.stderr [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.rs [new file with mode: 0644]
src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr [new file with mode: 0644]

index be7bb4d8114132d042132107c6de1e5da71a3ef1..717d0b0c3be6b96e4afa4120c72eb9c1d690ccfe 100644 (file)
@@ -1389,30 +1389,66 @@ struct Foo<T: 'static> {
 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/anon_anon_conflict.rs
deleted file mode 100644 (file)
index d3fff4c..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2012-2013 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.
-
-//! Error Reporting for Anonymous Region Lifetime Errors
-//! where both the regions are anonymous.
-use hir;
-use infer::InferCtxt;
-use ty::{self, Region};
-use infer::region_inference::RegionResolutionError::*;
-use infer::region_inference::RegionResolutionError;
-use hir::map as hir_map;
-use middle::resolve_lifetime as rl;
-use hir::intravisit::{self, Visitor, NestedVisitorMap};
-
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    // This method prints the error message for lifetime errors when both the concerned regions
-    // are anonymous.
-    // Consider a case where we have
-    // fn foo(x: &mut Vec<&u8>, y: &u8)
-    //    { x.push(y); }.
-    // The example gives
-    // fn foo(x: &mut Vec<&u8>, y: &u8) {
-    //                    ---      --- these references are declared with different lifetimes...
-    //            x.push(y);
-    //            ^ ...but data from `y` flows into `x` here
-    // It has been extended for the case of structs too.
-    // Consider the example
-    // struct Ref<'a> { x: &'a u32 }
-    // fn foo(mut x: Vec<Ref>, y: Ref) {
-    //                   ---      --- these structs are declared with different lifetimes...
-    //               x.push(y);
-    //               ^ ...but data from `y` flows into `x` here
-    // }
-    // It will later be extended to trait objects.
-    pub fn try_report_anon_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
-        let (span, sub, sup) = match *error {
-            ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
-            _ => return false, // inapplicable
-        };
-
-        // 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_sub = or_false!(self.is_suitable_anonymous_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;
-        let bregion_sub = anon_reg_sub.boundregion;
-
-        let ty_sup = or_false!(self.find_anon_type(sup, &bregion_sup));
-
-        let ty_sub = or_false!(self.find_anon_type(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)) {
-
-            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);
-            if self.is_self_anon(is_first_sup, scope_def_id_sup) ||
-               self.is_self_anon(is_first_sub, scope_def_id_sub) {
-                return false;
-            }
-
-            if self.is_return_type_anon(scope_def_id_sup, bregion_sup) ||
-               self.is_return_type_anon(scope_def_id_sub, bregion_sub) {
-                return false;
-            }
-
-            if anon_arg_sup == anon_arg_sub {
-                (format!("this type was declared with multiple lifetimes..."),
-                 format!(" with one lifetime"),
-                 format!(" into the other"))
-            } else {
-                let span_label_var1 = if let Some(simple_name) = anon_arg_sup.pat.simple_name() {
-                    format!(" from `{}`", simple_name)
-                } else {
-                    format!("")
-                };
-
-                let span_label_var2 = if let Some(simple_name) = anon_arg_sub.pat.simple_name() {
-                    format!(" into `{}`", simple_name)
-                } else {
-                    format!("")
-                };
-
-                let span_label =
-                    format!("these two types are declared with different lifetimes...",);
-
-                (span_label, span_label_var1, span_label_var2)
-            }
-        } else {
-            return false;
-        };
-
-        struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
-            .span_label(ty_sup.span, main_label)
-            .span_label(ty_sub.span, format!(""))
-            .span_label(span, format!("...but data{} flows{} here", label1, label2))
-            .emit();
-        return true;
-    }
-
-    /// This function calls the `visit_ty` method for the parameters
-    /// corresponding to the anonymous regions. The `nested_visitor.found_type`
-    /// contains the anonymous type.
-    ///
-    /// # Arguments
-    /// region - the anonymous region corresponding to the anon_anon conflict
-    /// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
-    ///
-    /// # Example
-    /// ```
-    /// fn foo(x: &mut Vec<&u8>, y: &u8)
-    ///    { x.push(y); }
-    /// ```
-    /// 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) {
-            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,
-
-                            _ => &[],
-                        };
-
-                    return inputs
-                               .iter()
-                               .filter_map(|arg| {
-                                               self.find_component_for_bound_region(&**arg, br)
-                                           })
-                               .next();
-                }
-            }
-        }
-        None
-    }
-
-    // This method creates a FindNestedTypeVisitor which returns the type corresponding
-    // to the anonymous region.
-    fn find_component_for_bound_region(&self,
-                                       arg: &'gcx hir::Ty,
-                                       br: &ty::BoundRegion)
-                                       -> Option<(&'gcx hir::Ty)> {
-        let mut nested_visitor = FindNestedTypeVisitor {
-            infcx: &self,
-            hir_map: &self.tcx.hir,
-            bound_region: *br,
-            found_type: None,
-        };
-        nested_visitor.visit_ty(arg);
-        nested_visitor.found_type
-    }
-}
-
-// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
-// anonymous region. The example above would lead to a conflict between
-// the two anonymous lifetimes for &u8 in x and y respectively. This visitor
-// would be invoked twice, once for each lifetime, and would
-// walk the types like &mut Vec<&u8> and &u8 looking for the HIR
-// where that lifetime appears. This allows us to highlight the
-// specific part of the type in the error message.
-struct FindNestedTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    hir_map: &'a hir::map::Map<'gcx>,
-    // The bound_region corresponding to the Refree(freeregion)
-    // associated with the anonymous region we are looking for.
-    bound_region: ty::BoundRegion,
-    // The type where the anonymous lifetime appears
-    // for e.g. Vec<`&u8`> and <`&u8`>
-    found_type: Option<&'gcx hir::Ty>,
-}
-
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.hir_map)
-    }
-
-    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, _) => {
-                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)) => {
-                        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 => {
-                        debug!("no arg found");
-                    }
-                }
-            }
-            // Checks if it is of type `hir::TyPath` which corresponds to a struct.
-            hir::TyPath(_) => {
-                let subvisitor = &mut TyPathVisitor {
-                                          infcx: self.infcx,
-                                          found_it: false,
-                                          bound_region: self.bound_region,
-                                          hir_map: self.hir_map,
-                                      };
-                intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
-                // this will visit only outermost type
-                if subvisitor.found_it {
-                    self.found_type = Some(arg);
-                }
-            }
-            _ => {}
-        }
-        // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
-        // go on to visit `&Foo`
-        intravisit::walk_ty(self, arg);
-    }
-}
-
-// The visitor captures the corresponding `hir::Ty` of the anonymous region
-// in the case of structs ie. `hir::TyPath`.
-// This visitor would be invoked for each lifetime corresponding to a struct,
-// and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
-// where that lifetime appears. This allows us to highlight the
-// specific part of the type in the error message.
-struct TyPathVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    hir_map: &'a hir::map::Map<'gcx>,
-    found_it: bool,
-    bound_region: ty::BoundRegion,
-}
-
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.hir_map)
-    }
-
-    fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
-        let br_index = match self.bound_region {
-            ty::BrAnon(index) => index,
-            _ => return,
-        };
-
-        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 TyPath!
-            Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)) => {
-                if debruijn_index.depth == 1 && anon_index == br_index {
-                    self.found_it = true;
-                }
-            }
-            Some(rl::Region::Static) |
-            Some(rl::Region::EarlyBound(_, _)) |
-            Some(rl::Region::LateBound(_, _)) |
-            Some(rl::Region::Free(_, _)) |
-            None => {
-                debug!("no arg found");
-            }
-        }
-    }
-
-    fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
-        // ignore nested types
-        //
-        // If you have a type like `Foo<'a, &Ty>` we
-        // are only interested in the immediate lifetimes ('a).
-        //
-        // Making `visit_ty` empty will ignore the `&Ty` embedded
-        // inside, it will get reached by the outer visitor.
-        debug!("`Ty` corresponding to a struct is {:?}", arg);
-    }
-}
diff --git a/src/librustc/infer/error_reporting/different_lifetimes.rs b/src/librustc/infer/error_reporting/different_lifetimes.rs
new file mode 100644 (file)
index 0000000..23f6d1a
--- /dev/null
@@ -0,0 +1,340 @@
+// Copyright 2012-2013 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.
+
+//! Error Reporting for Anonymous Region Lifetime Errors
+//! where both the regions are anonymous.
+use hir;
+use infer::InferCtxt;
+use ty::{self, Region};
+use infer::region_inference::RegionResolutionError::*;
+use infer::region_inference::RegionResolutionError;
+use hir::map as hir_map;
+use middle::resolve_lifetime as rl;
+use hir::intravisit::{self, Visitor, NestedVisitorMap};
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+    // This method prints the error message for lifetime errors when both the concerned regions
+    // are anonymous.
+    // Consider a case where we have
+    // fn foo(x: &mut Vec<&u8>, y: &u8)
+    //    { x.push(y); }.
+    // The example gives
+    // fn foo(x: &mut Vec<&u8>, y: &u8) {
+    //                    ---      --- these references are declared with different lifetimes...
+    //            x.push(y);
+    //            ^ ...but data from `y` flows into `x` here
+    // It has been extended for the case of structs too.
+    // Consider the example
+    // struct Ref<'a> { x: &'a u32 }
+    // fn foo(mut x: Vec<Ref>, y: Ref) {
+    //                   ---      --- these structs are declared with different lifetimes...
+    //               x.push(y);
+    //               ^ ...but data from `y` flows into `x` here
+    // }
+    // It will later be extended to trait objects.
+    pub fn try_report_anon_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
+        let (span, sub, sup) = match *error {
+            ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
+            _ => return false, // inapplicable
+        };
+
+        // Determine whether the sub and sup consist of both anonymous (elided) regions.
+        let anon_reg_sup = or_false!(self.is_suitable_region(sup));
+
+        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;
+        let bregion_sub = anon_reg_sub.boundregion;
+
+        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_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);
+            if self.is_self_anon(is_first_sup, scope_def_id_sup) ||
+               self.is_self_anon(is_first_sub, scope_def_id_sub) {
+                return false;
+            }
+
+            if self.is_return_type_anon(scope_def_id_sup, bregion_sup) ||
+               self.is_return_type_anon(scope_def_id_sub, bregion_sub) {
+                return false;
+            }
+
+            if anon_arg_sup == anon_arg_sub {
+                (format!("this type was declared with multiple lifetimes..."),
+                 format!(" with one lifetime"),
+                 format!(" into the other"))
+            } else {
+                let span_label_var1 = if let Some(simple_name) = anon_arg_sup.pat.simple_name() {
+                    format!(" from `{}`", simple_name)
+                } else {
+                    format!("")
+                };
+
+                let span_label_var2 = if let Some(simple_name) = anon_arg_sub.pat.simple_name() {
+                    format!(" into `{}`", simple_name)
+                } else {
+                    format!("")
+                };
+
+                let span_label =
+                    format!("these two types are declared with different lifetimes...",);
+
+                (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;
+        };
+
+        struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
+            .span_label(ty_sup.span, main_label)
+            .span_label(ty_sub.span, format!(""))
+            .span_label(span, format!("...but data{} flows{} here", label1, label2))
+            .emit();
+        return true;
+    }
+
+    /// This function calls the `visit_ty` method for the parameters
+    /// corresponding to the anonymous regions. The `nested_visitor.found_type`
+    /// contains the anonymous type.
+    ///
+    /// # Arguments
+    /// region - the anonymous region corresponding to the anon_anon conflict
+    /// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
+    ///
+    /// # Example
+    /// ```
+    /// fn foo(x: &mut Vec<&u8>, y: &u8)
+    ///    { x.push(y); }
+    /// ```
+    /// 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_region(region) {
+            let def_id = anon_reg.def_id;
+            if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
+                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();
+            }
+        }
+        None
+    }
+
+    // This method creates a FindNestedTypeVisitor which returns the type corresponding
+    // to the anonymous region.
+    fn find_component_for_bound_region(&self,
+                                       arg: &'gcx hir::Ty,
+                                       br: &ty::BoundRegion)
+                                       -> Option<(&'gcx hir::Ty)> {
+        let mut nested_visitor = FindNestedTypeVisitor {
+            infcx: &self,
+            hir_map: &self.tcx.hir,
+            bound_region: *br,
+            found_type: None,
+        };
+        nested_visitor.visit_ty(arg);
+        nested_visitor.found_type
+    }
+}
+
+// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
+// anonymous region. The example above would lead to a conflict between
+// the two anonymous lifetimes for &u8 in x and y respectively. This visitor
+// would be invoked twice, once for each lifetime, and would
+// walk the types like &mut Vec<&u8> and &u8 looking for the HIR
+// where that lifetime appears. This allows us to highlight the
+// specific part of the type in the error message.
+struct FindNestedTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    hir_map: &'a hir::map::Map<'gcx>,
+    // The bound_region corresponding to the Refree(freeregion)
+    // associated with the anonymous region we are looking for.
+    bound_region: ty::BoundRegion,
+    // The type where the anonymous lifetime appears
+    // for e.g. Vec<`&u8`> and <`&u8`>
+    found_type: Option<&'gcx hir::Ty>,
+}
+
+impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
+        NestedVisitorMap::OnlyBodies(&self.hir_map)
+    }
+
+    fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
+        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), 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
+                        }
+                    }
+
+                    // 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");
+                    }
+                }
+            }
+            // Checks if it is of type `hir::TyPath` which corresponds to a struct.
+            hir::TyPath(_) => {
+                let subvisitor = &mut TyPathVisitor {
+                                          infcx: self.infcx,
+                                          found_it: false,
+                                          bound_region: self.bound_region,
+                                          hir_map: self.hir_map,
+                                      };
+                intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
+                // this will visit only outermost type
+                if subvisitor.found_it {
+                    self.found_type = Some(arg);
+                }
+            }
+            _ => {}
+        }
+        // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
+        // go on to visit `&Foo`
+        intravisit::walk_ty(self, arg);
+    }
+}
+
+// The visitor captures the corresponding `hir::Ty` of the anonymous region
+// in the case of structs ie. `hir::TyPath`.
+// This visitor would be invoked for each lifetime corresponding to a struct,
+// and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
+// where that lifetime appears. This allows us to highlight the
+// specific part of the type in the error message.
+struct TyPathVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    hir_map: &'a hir::map::Map<'gcx>,
+    found_it: bool,
+    bound_region: ty::BoundRegion,
+}
+
+impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
+        NestedVisitorMap::OnlyBodies(&self.hir_map)
+    }
+
+    fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
+        let br_index = match self.bound_region {
+            ty::BrAnon(index) => index,
+            _ => return,
+        };
+
+        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 TyPath!
+            Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)) => {
+                if debruijn_index.depth == 1 && anon_index == br_index {
+                    self.found_it = true;
+                }
+            }
+            Some(rl::Region::Static) |
+            Some(rl::Region::EarlyBound(_, _)) |
+            Some(rl::Region::LateBound(_, _)) |
+            Some(rl::Region::Free(_, _)) |
+            None => {
+                debug!("no arg found");
+            }
+        }
+    }
+
+    fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
+        // ignore nested types
+        //
+        // If you have a type like `Foo<'a, &Ty>` we
+        // are only interested in the immediate lifetimes ('a).
+        //
+        // Making `visit_ty` empty will ignore the `&Ty` embedded
+        // inside, it will get reached by the outer visitor.
+        debug!("`Ty` corresponding to a struct is {:?}", arg);
+    }
+}
index ff52f1e4e39ff785cfc35f4efbbc5594d818aa7e..c0d88f6022c2abf2bb2f824d826dc14036234a5e 100644 (file)
@@ -79,7 +79,7 @@
 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,
index 0aae008396a00615b09cd7386ac0baec47506c90..a3bbdab497a9b2439de7250a9ff577bbecfe6fb9 100644 (file)
@@ -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 @@ pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'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 @@ pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'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 @@ pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>
                                 format!("consider changing {} to `{}`", span_label_var, new_ty))
                     .span_label(span, format!("lifetime `{}` required", named))
                     .emit();
-
-
+            return true;
         }
-        return true;
     }
 }
index 04153038da89faaede49e3cfdc849454a4337f67..b58fa6b0e7cbdc3f3ca153adcde528c0bde086d9 100644 (file)
 
 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 @@ pub fn find_arg_with_anonymous_region(&self,
         }
     }
 
-    // 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 @@ pub fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool {
     }
 
     // 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 @@ pub fn is_bound_region_in_impl_item(&self, anonymous_region_binding_scope: DefId
         }
         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,
+        }
+    }
 }
index fc244cabcd11c7f4577d0ab19f77568c4667562f..14ea66a1b67faadd1a9e961654c3fd359e1f9aed 100644 (file)
@@ -1041,19 +1041,6 @@ pub fn type_flags(&self) -> TypeFlags {
 
         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
index f9106ba3960b13879ebebe6781b76f0ce6c5d2c5..64dcdd39e7c2c59e30c2aedccd7113844132f336 100644 (file)
@@ -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)
index 6364db1f4b49c2e33bf095020ab237b3257144c9..f886c0255ccbf08631500c18f692fafd98c6dd58 100644 (file)
@@ -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) {
index 154135eba38baf7bd4cbf6b175429a7824c66c9d..bae9608c3f05afa741e68eb59aa52676ec6379a0 100644 (file)
@@ -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) {
index edca3b7ed41e4c9a1cb613e7552140b31ab80056..66b16744cc7df38586facf55c2c8f1c3250422ea 100644 (file)
 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() {}
index b7ef19d1e3bfc11be9c557cfc157ace2b5c160f8..6e1c765724b0b8b2eaba427b45f3c69e06f5f70b 100644 (file)
@@ -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() {}
index 0d3d9dacbd6f6c0a3517aed2045a09155c1b1931..1ab8ba4439b5d0568dbe2f5ca5288d0d1fd20e55 100644 (file)
@@ -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() {}
index 89254516ac600554386c34b54394a76c3e80cbdf..ef1c58bf972e31ba07c8c9a185fae164f1262958 100644 (file)
@@ -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) {
index a7ef3ec9ac190472da666a21068ed9eb2a0e2d33..1dfebd54ec3b3522ff461485babb426402678a43 100644 (file)
@@ -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() {}
index a79249ade4f5ccd9185ef7cee6f9d590f4c1080a..caf6a86fc0b26e7bbe9bbd51cf1d34ee9b299cfc 100644 (file)
@@ -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() {}
index f42b7027d9e00a8d23902442d69b8ea0b39e3359..60dc3d94a2edb2b3ac66162642a49d64c171e734 100644 (file)
@@ -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() {}
index 71023b26c27693b795dd8c4c365570eac3d9a3a4..96478fa590979288f66621ef6d5da23e83597a18 100644 (file)
@@ -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() { }
index b8a8f9ad91c72c94edbfb83a87bb61b713528ad7..1ddbcf4ab84c75065bdfd1df2cac8d4b9a40236a 100644 (file)
@@ -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 (file)
index 0000000..5d18200
--- /dev/null
@@ -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 (file)
index 0000000..58f2cb9
--- /dev/null
@@ -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 (file)
index 0000000..5abfc98
--- /dev/null
@@ -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 (file)
index 0000000..be628f2
--- /dev/null
@@ -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
+