diff --git a/src/librustc/infer/error_reporting/anon_anon_conflict.rs b/src/librustc/infer/error_reporting/anon_anon_conflict.rs index 2e91096881815..c80ce3c96f1a9 100644 --- a/src/librustc/infer/error_reporting/anon_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/anon_anon_conflict.rs @@ -27,65 +27,84 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // { x.push(y); }. // The example gives // fn foo(x: &mut Vec<&u8>, y: &u8) { - // --- --- these references must have the same lifetime + // --- --- these references are declared with different lifetimes... // x.push(y); - // ^ data from `y` flows into `x` here - // It will later be extended to trait objects and structs. + // ^ ...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, 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 (ty1, ty2) = if self.is_suitable_anonymous_region(sup).is_some() && - self.is_suitable_anonymous_region(sub).is_some() { - if let (Some(anon_reg1), Some(anon_reg2)) = - (self.is_suitable_anonymous_region(sup), self.is_suitable_anonymous_region(sub)) { - let ((_, br1), (_, br2)) = (anon_reg1, anon_reg2); - if self.find_anon_type(sup, &br1).is_some() && - self.find_anon_type(sub, &br2).is_some() { - (self.find_anon_type(sup, &br1).unwrap(), - self.find_anon_type(sub, &br2).unwrap()) - } else { - return false; - } - } else { - return false; - } - } else { - return false; // inapplicable - }; + let anon_reg_sup = or_false!(self.is_suitable_anonymous_region(sup)); - if let (Some(sup_arg), Some(sub_arg)) = + 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_arg1, _, _, _), (anon_arg2, _, _, _)) = (sup_arg, sub_arg); - let span_label_var1 = if let Some(simple_name) = anon_arg1.pat.simple_name() { - format!(" from `{}` ", simple_name) - } else { - format!(" ") - }; + 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; + } - let span_label_var2 = if let Some(simple_name) = anon_arg2.pat.simple_name() { - format!(" into `{}` ", simple_name) + 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 { - format!(" ") - }; - - struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch") - .span_label(ty1.span, - format!("these references are not declared with the same lifetime...")) - .span_label(ty2.span, format!("")) - .span_label(span, - format!("...but data{}flows{}here", span_label_var1, span_label_var2)) - .emit(); + 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; } @@ -94,7 +113,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// 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(_)` /// @@ -105,39 +123,56 @@ 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`. - fn find_anon_type(&self, region: Region<'tcx>, br: &ty::BoundRegion) -> Option<&hir::Ty> { + 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; + 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 { - if let hir_map::NodeItem(it) = self.tcx.hir.get(node_id) { - if let hir::ItemFn(ref fndecl, _, _, _, _, _) = it.node { - return fndecl - .inputs - .iter() - .filter_map(|arg| { - let mut nested_visitor = FindNestedTypeVisitor { - infcx: &self, - hir_map: &self.tcx.hir, - bound_region: *br, - found_type: None, - }; - nested_visitor.visit_ty(&**arg); - if nested_visitor.found_type.is_some() { - nested_visitor.found_type - } else { - None - } - }) - .next(); - } - } + 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 @@ -176,8 +211,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { hir::TyRptr(ref lifetime, _) => { match self.infcx.tcx.named_region_map.defs.get(&lifetime.id) { // the lifetime of the TyRptr - Some(&rl::Region::LateBoundAnon(debuijn_index, anon_index)) => { - if debuijn_index.depth == 1 && anon_index == br_index { + 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 } @@ -191,6 +226,20 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { } } } + // 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>`, @@ -198,3 +247,56 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { 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 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, + }; + + match self.infcx.tcx.named_region_map.defs.get(&lifetime.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/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 9f70b4834ddc5..195609992f757 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -75,8 +75,10 @@ use errors::{DiagnosticBuilder, DiagnosticStyledString}; mod note; mod need_type_info; -mod util; + mod named_anon_conflict; +#[macro_use] +mod util; mod anon_anon_conflict; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/librustc/infer/error_reporting/named_anon_conflict.rs b/src/librustc/infer/error_reporting/named_anon_conflict.rs index 491079a1f9259..0aae008396a00 100644 --- a/src/librustc/infer/error_reporting/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/named_anon_conflict.rs @@ -11,7 +11,6 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where one region is named and the other is anonymous. use infer::InferCtxt; -use ty; use infer::region_inference::RegionResolutionError::*; use infer::region_inference::RegionResolutionError; @@ -30,8 +29,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // where the anonymous region appears (there must always be one; we // only introduced anonymous regions in parameters) as well as a // version new_ty of its type where the anonymous region is replaced - // with the named one. - let (named, (arg, new_ty, br, is_first), (scope_def_id, _)) = + // 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() { (sub, self.find_arg_with_anonymous_region(sup, sub).unwrap(), @@ -44,50 +43,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return false; // inapplicable }; - // Here, we check for the case where the anonymous region - // is in the return type. - // FIXME(#42703) - Need to handle certain cases here. - let ret_ty = self.tcx.type_of(scope_def_id); - match ret_ty.sty { - ty::TyFnDef(_, _) => { - let sig = ret_ty.fn_sig(self.tcx); - let late_bound_regions = self.tcx - .collect_referenced_late_bound_regions(&sig.output()); - if late_bound_regions.iter().any(|r| *r == br) { - return false; - } - } - _ => {} - } - - // Here we check for the case where anonymous region - // corresponds to self and if yes, we display E0312. - // FIXME(#42700) - Need to format self properly to - // enable E0621 for it. - if is_first && - self.tcx - .opt_associated_item(scope_def_id) - .map(|i| i.method_has_self_argument) - .unwrap_or(false) { + 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); + if is_impl_item { return false; } - 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)) + if self.is_return_type_anon(scope_def_id, br) || self.is_self_anon(is_first, scope_def_id) { + return false; } else { - ("parameter type".to_owned(), "type".to_owned()) - }; - struct_span_err!(self.tcx.sess, - span, - E0621, - "explicit lifetime required in {}", - error_var) - .span_label(arg.pat.span, - format!("consider changing {} to `{}`", span_label_var, new_ty)) - .span_label(span, format!("lifetime `{}` required", named)) - .emit(); + 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 { + ("parameter type".to_owned(), "type".to_owned()) + }; + + struct_span_err!(self.tcx.sess, + span, + E0621, + "explicit lifetime required in {}", + error_var) + .span_label(arg.pat.span, + format!("consider changing {} to `{}`", span_label_var, new_ty)) + .span_label(span, format!("lifetime `{}` required", named)) + .emit(); + + } return true; } } diff --git a/src/librustc/infer/error_reporting/util.rs b/src/librustc/infer/error_reporting/util.rs index 14fe8e699c7f2..f9ff2d2e2a5a2 100644 --- a/src/librustc/infer/error_reporting/util.rs +++ b/src/librustc/infer/error_reporting/util.rs @@ -16,6 +16,40 @@ use ty::{self, Region}; use hir::def_id::DefId; use hir::map as hir_map; +macro_rules! or_false { + ($v:expr) => { + match $v { + Some(v) => v, + None => return false, + } + } +} + +// The struct contains the information about the anonymous region +// we are searching for. +pub struct AnonymousArgInfo<'tcx> { + // the argument corresponding to the anonymous region + pub arg: &'tcx hir::Arg, + // the type corresponding to the anonymopus region argument + pub arg_ty: ty::Ty<'tcx>, + // the ty::BoundRegion corresponding to the anonymous region + pub bound_region: ty::BoundRegion, + // corresponds to id the argument is the first parameter + // in the declaration + pub is_first: bool, +} + +// This struct contains information regarding the +// Refree((FreeRegion) corresponding to lifetime conflict +pub struct FreeRegionInfo { + // def id corresponding to FreeRegion + pub def_id: DefId, + // the bound region corresponding to FreeRegion + pub boundregion: ty::BoundRegion, + // checks if bound region is in Impl Item + pub is_impl_item: bool, +} + impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // This method walks the Type of the function body arguments using // `fold_regions()` function and returns the @@ -28,14 +62,12 @@ 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<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion, bool)> { + 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) { @@ -57,7 +89,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }); if found_anon_region { let is_first = index == 0; - Some((arg, new_arg_ty, free_region.bound_region, is_first)) + Some(AnonymousArgInfo { + arg: arg, + arg_ty: new_arg_ty, + bound_region: free_region.bound_region, + is_first: is_first, + }) } else { None } @@ -79,42 +116,81 @@ 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<(DefId, ty::BoundRegion)> { + 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(); - 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(..)) => { - let container_id = self.tcx - .associated_item(anonymous_region_binding_scope) - .container - .id(); - if self.tcx.impl_trait_ref(container_id).is_some() { - // For now, we do not try to target impls of traits. This is - // because this message is going to suggest that the user - // change the fn signature, but they may not be free to do so, - // since the signature must match the trait. - // - // FIXME(#42706) -- in some cases, we could do better here. - return None; - } - } - _ => return None, // inapplicable - // we target only top-level functions + 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 } - return Some((anonymous_region_binding_scope, free_region.bound_region)); + 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, + }); } - None } + None + } + + // Here, we check for the case where the anonymous region + // is in the return type. + // FIXME(#42703) - Need to handle certain cases here. + pub fn is_return_type_anon(&self, scope_def_id: DefId, br: ty::BoundRegion) -> bool { + let ret_ty = self.tcx.type_of(scope_def_id); + match ret_ty.sty { + ty::TyFnDef(_, _) => { + let sig = ret_ty.fn_sig(self.tcx); + let late_bound_regions = self.tcx + .collect_referenced_late_bound_regions(&sig.output()); + if late_bound_regions.iter().any(|r| *r == br) { + return true; + } + } + _ => {} + } + false + } + // Here we check for the case where anonymous region + // corresponds to self and if yes, we display E0312. + // FIXME(#42700) - Need to format self properly to + // enable E0621 for it. + pub fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool { + is_first && + self.tcx + .opt_associated_item(scope_def_id) + .map(|i| i.method_has_self_argument) == Some(true) + } + + // 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 { + let container_id = self.tcx + .associated_item(anonymous_region_binding_scope) + .container + .id(); + if self.tcx.impl_trait_ref(container_id).is_some() { + // For now, we do not try to target impls of traits. This is + // because this message is going to suggest that the user + // change the fn signature, but they may not be free to do so, + // since the signature must match the trait. + // + // FIXME(#42706) -- in some cases, we could do better here. + return true; + } + false + } } diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr index 6764c58f4bb59..1ee0099799760 100644 --- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr +++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr @@ -1,25 +1,10 @@ -error[E0308]: mismatched types +error[E0623]: lifetime mismatch --> $DIR/ex2b-push-no-existing-names.rs:16:12 | +15 | fn foo(x: &mut Vec>, y: Ref) { + | -------- -------- these two types are declared with different lifetimes... 16 | x.push(y); - | ^ lifetime mismatch - | - = note: expected type `Ref<'_, _>` - found type `Ref<'_, _>` -note: the anonymous lifetime #3 defined on the function body at 15:1... - --> $DIR/ex2b-push-no-existing-names.rs:15:1 - | -15 | / fn foo(x: &mut Vec>, y: Ref) { -16 | | x.push(y); -17 | | } - | |_^ -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 15:1 - --> $DIR/ex2b-push-no-existing-names.rs:15:1 - | -15 | / fn foo(x: &mut Vec>, y: Ref) { -16 | | x.push(y); -17 | | } - | |_^ + | ^ ...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-2.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr index 4c878f3c0dc03..74a40c87c2fb1 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr @@ -2,7 +2,7 @@ error[E0623]: lifetime mismatch --> $DIR/ex3-both-anon-regions-2.rs:12:9 | 11 | fn foo((v, w): (&u8, &u8), x: &u8) { - | --- --- these references are not declared with the same lifetime... + | --- --- these two types are declared with different lifetimes... 12 | v = x; | ^ ...but data from `x` flows here diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs index 7bd5ebf805f1e..51271243bdfdc 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo((v, w): (&u8, &u8), (x, y): (&u8, &u8)) { - v = x; +fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + z.push((x,y)); } fn main() { } + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr index 08506b8befa03..898866c75f214 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr @@ -1,10 +1,18 @@ error[E0623]: lifetime mismatch - --> $DIR/ex3-both-anon-regions-3.rs:12:9 + --> $DIR/ex3-both-anon-regions-3.rs:12:13 | -11 | fn foo((v, w): (&u8, &u8), (x, y): (&u8, &u8)) { - | --- --- these references are not declared with the same lifetime... -12 | v = x; - | ^ ...but data flows here +11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + | --- --- these two types are declared with different lifetimes... +12 | z.push((x,y)); + | ^ ...but data flows into `z` here -error: aborting due to previous error +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-3.rs:12:15 + | +11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + | --- --- these two types are declared with different lifetimes... +12 | z.push((x,y)); + | ^ ...but data flows into `z` here + +error: aborting due to 2 previous errors diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr deleted file mode 100644 index 9c2630fc81143..0000000000000 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0601]: main function not found - -error[E0623]: lifetime mismatch - --> $DIR/ex3-both-anon-regions-4.rs:12:13 - | -11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { - | --- --- these references are not declared with the same lifetime... -12 | z.push((x,y)); - | ^ ...but data flows into `z` here - -error[E0623]: lifetime mismatch - --> $DIR/ex3-both-anon-regions-4.rs:12:15 - | -11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { - | --- --- these references are not declared with the same lifetime... -12 | z.push((x,y)); - | ^ ...but data flows into `z` here - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.rs new file mode 100644 index 0000000000000..2fbf31aead5ed --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.rs @@ -0,0 +1,19 @@ +// 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. +struct Ref<'a, 'b> { + a: &'a u32, + b: &'b u32, +} + +fn foo(mut x: Ref, y: Ref) { + x.b = y.b; +} + +fn main() {} diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr new file mode 100644 index 0000000000000..26f31defc9eb1 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:16:11 + | +15 | fn foo(mut x: Ref, y: Ref) { + | --- --- these two types are declared with different lifetimes... +16 | x.b = y.b; + | ^^^ ...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-both-are-structs-3.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.rs new file mode 100644 index 0000000000000..120a7ca74aeee --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.rs @@ -0,0 +1,19 @@ +// 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. +struct Ref<'a, 'b> { + a: &'a u32, + b: &'b u32, +} + +fn foo(mut x: Ref) { + x.a = x.b; +} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr new file mode 100644 index 0000000000000..1b5ac7c7b57ee --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr @@ -0,0 +1,12 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:16:11 + | +15 | fn foo(mut x: Ref) { + | --- + | | + | this type was declared with multiple lifetimes... +16 | x.a = x.b; + | ^^^ ...but data with one lifetime flows into the other here + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.rs similarity index 71% rename from src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs rename to src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.rs index fdb010a04f4c6..67ba8ee532ad0 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -7,7 +7,12 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +struct Ref<'a> { + x: &'a u32, +} -fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { - z.push((x,y)); +fn foo(mut x: Vec, y: Ref) { + x.push(y); } + +fn main() {} diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr new file mode 100644 index 0000000000000..6ad795400b334 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs.rs:15:12 + | +14 | fn foo(mut x: Vec, y: Ref) { + | --- --- these two types are declared with different lifetimes... +15 | 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-one-is-struct-2.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.rs new file mode 100644 index 0000000000000..a8b1f53fc98d6 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.rs @@ -0,0 +1,17 @@ +// 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. + +struct Ref<'a, 'b> { a: &'a u32, b: &'b u32 } + +fn foo(mut x: Ref, y: &u32) { + y = x.b; +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr new file mode 100644 index 0000000000000..31c7ebf6504cc --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr @@ -0,0 +1,12 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:9 + | +13 | fn foo(mut x: Ref, y: &u32) { + | --- ---- + | | + | these two types are declared with different lifetimes... +14 | y = x.b; + | ^^^ ...but data from `x` flows into `y` here + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.rs new file mode 100644 index 0000000000000..4933dbb7e7a7a --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.rs @@ -0,0 +1,17 @@ +// 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. + +struct Ref<'a, 'b> { a: &'a u32, b: &'b u32 } + +fn foo(mut y: Ref, x: &u32) { + y.b = x; +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr new file mode 100644 index 0000000000000..d54b526aef97f --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:14:11 + | +13 | fn foo(mut y: Ref, x: &u32) { + | --- ---- these two types are declared with different lifetimes... +14 | y.b = x; + | ^ ...but data from `x` flows into `y` here + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.rs new file mode 100644 index 0000000000000..e1594b1a277cd --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.rs @@ -0,0 +1,20 @@ +// 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. + +struct Ref<'a, 'b> { + a: &'a u32, + b: &'b u32, +} + +fn foo(mut x: Ref, y: &u32) { + x.b = y; +} + +fn main() {} diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr new file mode 100644 index 0000000000000..bb7b9ea68436c --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-one-is-struct.rs:17:11 + | +16 | fn foo(mut x: Ref, y: &u32) { + | --- ---- these two types are declared with different lifetimes... +17 | x.b = 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-return-type-is-anon.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs new file mode 100644 index 0000000000000..0dc257ac0921e --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs @@ -0,0 +1,22 @@ +// 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. + +struct Foo { + field: i32 +} + +impl Foo { + fn foo<'a>(&self, x: &i32) -> &i32 { + x + } +} + +fn main() { } + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr new file mode 100644 index 0000000000000..890f9b311e7d2 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr @@ -0,0 +1,23 @@ +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:17:5 + | +17 | x + | ^ + | +note: ...the reference is valid for the anonymous lifetime #1 defined on the method body at 16:3... + --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:16:3 + | +16 | / fn foo<'a>(&self, x: &i32) -> &i32 { +17 | | x +18 | | } + | |___^ +note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the method body at 16:3 + --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:16:3 + | +16 | / fn foo<'a>(&self, x: &i32) -> &i32 { +17 | | x +18 | | } + | |___^ + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs new file mode 100644 index 0000000000000..0940ce15d1e76 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs @@ -0,0 +1,22 @@ +// 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. + +struct Foo { + field: i32, +} + +impl Foo { + fn foo<'a>(&self, x: &Foo) -> &Foo { + if true { x } else { self } + } +} + +fn main() {} + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr new file mode 100644 index 0000000000000..43f00c32c6285 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr @@ -0,0 +1,23 @@ +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/ex3-both-anon-regions-self-is-anon.rs:17:19 + | +17 | if true { x } else { self } + | ^ + | +note: ...the reference is valid for the anonymous lifetime #1 defined on the method body at 16:5... + --> $DIR/ex3-both-anon-regions-self-is-anon.rs:16:5 + | +16 | / fn foo<'a>(&self, x: &Foo) -> &Foo { +17 | | if true { x } else { self } +18 | | } + | |_____^ +note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the method body at 16:5 + --> $DIR/ex3-both-anon-regions-self-is-anon.rs:16:5 + | +16 | / fn foo<'a>(&self, x: &Foo) -> &Foo { +17 | | if true { x } else { self } +18 | | } + | |_____^ + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.rs new file mode 100644 index 0000000000000..3a7ba415c0ded --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.rs @@ -0,0 +1,18 @@ +// 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 { + fn foo<'a>(x: &mut Vec<&u8>, y: &u8); +} +impl Foo for () { + fn foo(x: &mut Vec<&u8>, y: &u8) { + x.push(y); + } +} +fn main() {} diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr new file mode 100644 index 0000000000000..9591df8e8aad2 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-using-impl-items.rs:15:16 + | +14 | fn foo(x: &mut Vec<&u8>, y: &u8) { + | --- --- these two types are declared with different lifetimes... +15 | 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.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs index 9ebff5118768d..be48d07b94e06 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// 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. // diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr index a183d1fffc0b6..d3291063859ca 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr @@ -2,7 +2,7 @@ error[E0623]: lifetime mismatch --> $DIR/ex3-both-anon-regions.rs:12:12 | 11 | fn foo(x: &mut Vec<&u8>, y: &u8) { - | --- --- these references are not declared with the same lifetime... + | --- --- these two types are declared with different lifetimes... 12 | x.push(y); | ^ ...but data from `y` flows into `x` here