diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index be7bb4d811413..4d21e5e0f4708 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 +) -> &'human 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 similarity index 69% rename from src/librustc/infer/error_reporting/anon_anon_conflict.rs rename to src/librustc/infer/error_reporting/different_lifetimes.rs index d3fff4c66af07..23f6d1a3fb0d4 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 ff52f1e4e39ff..c0d88f6022c2a 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 0aae008396a00..a3bbdab497a9b 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 04153038da89f..b58fa6b0e7cbd 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 { - - 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 { + + 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 { - 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 { + + 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 fc244cabcd11c..14ea66a1b67fa 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 f9106ba3960b1..64dcdd39e7c2c 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: >::Type = loop { }; let b: >::Type = loop { }; - let _: >::Type = a; //~ ERROR mismatched types + let _: >::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: >::Type = loop { }; let b: >::Type = loop { }; - let _: >::Type = b; //~ ERROR mismatched types + let _: >::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 6364db1f4b49c..f886c0255ccbf 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 154135eba38ba..bae9608c3f05a 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 edca3b7ed41e4..66b16744cc7df 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 b7ef19d1e3bfc..6e1c765724b0b 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 0d3d9dacbd6f6..1ab8ba4439b5d 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 89254516ac600..ef1c58bf972e3 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 a7ef3ec9ac190..1dfebd54ec3b3 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 a79249ade4f5c..caf6a86fc0b26 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 f42b7027d9e00..60dc3d94a2edb 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 71023b26c2769..96478fa590979 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 b8a8f9ad91c72..1ddbcf4ab84c7 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 0000000000000..5d1820082093e --- /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 or the MIT license +// , 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 0000000000000..58f2cb94cec1d --- /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 0000000000000..5abfc983f883a --- /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 or the MIT license +// , 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 0000000000000..be628f226d3dd --- /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 +