From 2f50c33290c81a548ea3237447cef0d1dbdc1a61 Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Sun, 6 Aug 2017 04:09:43 +0530 Subject: [PATCH 1/8] Adding E0623 for structs --- .../error_reporting/anon_anon_conflict.rs | 326 ++++++++++++++++++ .../error_reporting/different_lifetimes.rs | 7 + .../ex3-both-anon-regions-4.stderr | 18 + ...x3-both-anon-regions-both-are-structs-4.rs | 19 + ...oth-anon-regions-both-are-structs-4.stderr | 12 + .../ex3-both-anon-regions-one-is-struct-3.rs | 4 + .../ex3-both-anon-regions-one-is-struct-4.rs | 17 + ...3-both-anon-regions-one-is-struct-4.stderr | 10 + 8 files changed, 413 insertions(+) create mode 100644 src/librustc/infer/error_reporting/anon_anon_conflict.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr diff --git a/src/librustc/infer/error_reporting/anon_anon_conflict.rs b/src/librustc/infer/error_reporting/anon_anon_conflict.rs new file mode 100644 index 00000000000..c86bc71d310 --- /dev/null +++ b/src/librustc/infer/error_reporting/anon_anon_conflict.rs @@ -0,0 +1,326 @@ +// 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 or the MIT license +// , 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, 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, scope_def_id_1, scope_def_id_2, bregion1, bregion2) = if + self.is_suitable_anonymous_region(sup, true).is_some() && + self.is_suitable_anonymous_region(sub, true).is_some() { + if let (Some(anon_reg1), Some(anon_reg2)) = + (self.is_suitable_anonymous_region(sup, true), + self.is_suitable_anonymous_region(sub, true)) { + let ((def_id1, br1), (def_id2, br2)) = (anon_reg1, anon_reg2); + let found_arg1 = self.find_anon_type(sup, &br1); + let found_arg2 = self.find_anon_type(sub, &br2); + match (found_arg1, found_arg2) { + (Some(anonarg_1), Some(anonarg_2)) => { + (anonarg_1, anonarg_2, def_id1, def_id2, br1, br2) + } + _ => { + return false; + } + } + + } else { + return false; + } + } else { + return false; //inapplicable + }; + + let (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, _, _, is_first1), (anon_arg2, _, _, is_first2)) = (sup_arg, sub_arg); + if self.is_self_anon(is_first1, scope_def_id_1) || + self.is_self_anon(is_first2, scope_def_id_2) { + return false; + } + + if self.is_return_type_anon(scope_def_id_1, bregion1) || + self.is_return_type_anon(scope_def_id_2, bregion2) { + return false; + } + + + + + if anon_arg1 == anon_arg2 { + (format!(" with one lifetime"), format!(" into the other")) + } else { + let span_label_var1 = if let Some(simple_name) = anon_arg1.pat.simple_name() { + format!(" from `{}`", simple_name) + } else { + format!("") + }; + + let span_label_var2 = if let Some(simple_name) = anon_arg2.pat.simple_name() { + format!(" into `{}`", simple_name) + } else { + format!("") + }; + + (span_label_var1, span_label_var2) + } + } else { + return false; + }; + + struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch") + .span_label(ty1.span, + format!("these two types are declared with different lifetimes...")) + .span_label(ty2.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, true) { + let (def_id, _) = anon_reg; + 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| { + self.find_visitor_found_type(&**arg, br) + }) + .next(); + } + } else if let hir_map::NodeTraitItem(it) = self.tcx.hir.get(node_id) { + if let hir::TraitItemKind::Method(ref fndecl, _) = it.node { + return fndecl + .decl + .inputs + .iter() + .filter_map(|arg| { + self.find_visitor_found_type(&**arg, br) + }) + .next(); + } + } else if let hir_map::NodeImplItem(it) = self.tcx.hir.get(node_id) { + if let hir::ImplItemKind::Method(ref fndecl, _) = it.node { + return fndecl + .decl + .inputs + .iter() + .filter_map(|arg| { + self.find_visitor_found_type(&**arg, br) + }) + .next(); + } + } + } + } + } + None + } + + // This method creates a FindNestedTypeVisitor which returns the type corresponding + // to the anonymous region. + fn find_visitor_found_type(&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, _) => { + 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 { + 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 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(debuijn_index, anon_index)) => { + if debuijn_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 index 23f6d1a3fb0..9546d8a4dd2 100644 --- a/src/librustc/infer/error_reporting/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/different_lifetimes.rs @@ -204,6 +204,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { fn visit_ty(&mut self, arg: &'gcx hir::Ty) { match arg.node { + hir::TyBareFn(_) => { + self.depth += 1; + intravisit::walk_ty(self, arg); + self.depth -= 1; + return; + } + hir::TyRptr(ref lifetime, _) => { // the lifetime of the TyRptr let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id); 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 new file mode 100644 index 00000000000..b159e147869 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr @@ -0,0 +1,18 @@ +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 declared with different lifetimes... +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 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-both-are-structs-4.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.rs new file mode 100644 index 00000000000..606e611865f --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.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() {} diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr new file mode 100644 index 00000000000..2ef1cd507f1 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr @@ -0,0 +1,12 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:11 + | +15 | fn foo(mut x: Ref) { + | --- + | | + | these two types are declared with different 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-one-is-struct-3.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.rs index 4933dbb7e7a..5920eeed6b1 100644 --- 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 @@ -11,7 +11,11 @@ struct Ref<'a, 'b> { a: &'a u32, b: &'b u32 } fn foo(mut y: Ref, x: &u32) { +<<<<<<< HEAD y.b = x; +======= + x = y.b; +>>>>>>> Adding E0623 for structs } fn main() { } diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs new file mode 100644 index 00000000000..4933dbb7e7a --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.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-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr new file mode 100644 index 00000000000..40f026bcb1b --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-one-is-struct-4.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 + From ed1181272e5f33c2a329c3cf0e267cae99fab06a Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Tue, 15 Aug 2017 10:21:31 +0530 Subject: [PATCH 2/8] extend E0623 for fns --- .../error_reporting/anon_anon_conflict.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/librustc/infer/error_reporting/anon_anon_conflict.rs b/src/librustc/infer/error_reporting/anon_anon_conflict.rs index c86bc71d310..bb4782d2c8f 100644 --- a/src/librustc/infer/error_reporting/anon_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/anon_anon_conflict.rs @@ -192,6 +192,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { hir_map: &self.tcx.hir, bound_region: *br, found_type: None, + depth: 0, }; nested_visitor.visit_ty(arg); nested_visitor.found_type @@ -214,6 +215,7 @@ struct FindNestedTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { // The type where the anonymous lifetime appears // for e.g. Vec<`&u8`> and <`&u8`> found_type: Option<&'gcx hir::Ty>, + depth: u32, } impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { @@ -263,11 +265,35 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { self.found_type = Some(arg); } } + + hir::TyBareFn(ref fndecl) => { + fndecl.lifetimes.iter().filter_map(|lf| { + match self.infcx.tcx.named_region_map.defs.get(&lf.lifetime.id) { + + Some(&rl::Region::LateBoundAnon(debuijn_index, anon_index)) => { + if debuijn_index.depth == self.depth && anon_index == br_index { + self.found_type = Some(arg); + return; // we can stop visiting now + }else{} + } + Some(&rl::Region::Static) | + Some(&rl::Region::EarlyBound(_, _)) | + Some(&rl::Region::LateBound(_, _)) | + Some(&rl::Region::Free(_, _)) | + None => { + debug!("no arg found"); + } + } + + }).next();} + _ => {} } // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`, // go on to visit `&Foo` + self.depth += 1; intravisit::walk_ty(self, arg); + self.depth += 1; } } From b2d869dc8075a78d5f2f163f6691bad14b16e4b0 Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Tue, 15 Aug 2017 22:16:29 +0530 Subject: [PATCH 3/8] add logs --- fn.rs | 8 ++++++++ .../infer/error_reporting/anon_anon_conflict.rs | 10 +++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 fn.rs diff --git a/fn.rs b/fn.rs new file mode 100644 index 00000000000..186eda95fec --- /dev/null +++ b/fn.rs @@ -0,0 +1,8 @@ + +fn foo(x: fn(&u8, &u8), y: Vec<&u8>, z: &u8) { +// Debruijn 1 1 1 1 +// Anon-Index 0 1 0 1 +// ------ +// debruijn indices are shifted by 1 in here + y.push(z); // index will be zero or one +} diff --git a/src/librustc/infer/error_reporting/anon_anon_conflict.rs b/src/librustc/infer/error_reporting/anon_anon_conflict.rs index bb4782d2c8f..634f5788660 100644 --- a/src/librustc/infer/error_reporting/anon_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/anon_anon_conflict.rs @@ -267,14 +267,17 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { } hir::TyBareFn(ref fndecl) => { - fndecl.lifetimes.iter().filter_map(|lf| { + fndecl.lifetimes.iter().map(|lf| { + debug!("arg we are handling is...{:?}",arg); match self.infcx.tcx.named_region_map.defs.get(&lf.lifetime.id) { - Some(&rl::Region::LateBoundAnon(debuijn_index, anon_index)) => { + debug!("debuijn_index.depth ={:?} self.depth = {:?} anon_index ={:?} br_index={:?}", + debuijn_index.depth, self.depth, anon_index, br_index); if debuijn_index.depth == self.depth && anon_index == br_index { + debug!("arg is {:?}",Some(arg)); self.found_type = Some(arg); return; // we can stop visiting now - }else{} + } } Some(&rl::Region::Static) | Some(&rl::Region::EarlyBound(_, _)) | @@ -292,6 +295,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`, // go on to visit `&Foo` self.depth += 1; + debug!("depth is {:?}",self.depth); intravisit::walk_ty(self, arg); self.depth += 1; } From 54af57018b57810c4467b6ed092a0294c3467ef5 Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Mon, 11 Sep 2017 23:58:29 +0530 Subject: [PATCH 4/8] correct depth initialisation --- .../error_reporting/anon_anon_conflict.rs | 40 +++++-------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/src/librustc/infer/error_reporting/anon_anon_conflict.rs b/src/librustc/infer/error_reporting/anon_anon_conflict.rs index 634f5788660..420ac040b30 100644 --- a/src/librustc/infer/error_reporting/anon_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/anon_anon_conflict.rs @@ -192,7 +192,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { hir_map: &self.tcx.hir, bound_region: *br, found_type: None, - depth: 0, + depth: 1, }; nested_visitor.visit_ty(arg); nested_visitor.found_type @@ -233,6 +233,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { }; match arg.node { + + hir::TyBareFn(ref fndecl) => { + self.depth += 1; + intravisit::walk_ty(self, arg); + self.depth -= 1; + return; + } + hir::TyRptr(ref lifetime, _) => { match self.infcx.tcx.named_region_map.defs.get(&lifetime.id) { // the lifetime of the TyRptr @@ -266,38 +274,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { } } - hir::TyBareFn(ref fndecl) => { - fndecl.lifetimes.iter().map(|lf| { - debug!("arg we are handling is...{:?}",arg); - match self.infcx.tcx.named_region_map.defs.get(&lf.lifetime.id) { - Some(&rl::Region::LateBoundAnon(debuijn_index, anon_index)) => { - debug!("debuijn_index.depth ={:?} self.depth = {:?} anon_index ={:?} br_index={:?}", - debuijn_index.depth, self.depth, anon_index, br_index); - if debuijn_index.depth == self.depth && anon_index == br_index { - debug!("arg is {:?}",Some(arg)); - 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"); - } - } - - }).next();} - _ => {} } // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`, // go on to visit `&Foo` - self.depth += 1; - debug!("depth is {:?}",self.depth); + debug!("depth is {:?}", self.depth); intravisit::walk_ty(self, arg); - self.depth += 1; + } } @@ -325,7 +308,6 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> { _ => return, }; - match self.infcx.tcx.named_region_map.defs.get(&lifetime.id) { // the lifetime of the TyPath! Some(&rl::Region::LateBoundAnon(debuijn_index, anon_index)) => { From a128051f87be0baa953adbedfe780c1ef35379b6 Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Tue, 12 Sep 2017 00:34:52 +0530 Subject: [PATCH 5/8] fixes --- .../error_reporting/anon_anon_conflict.rs | 338 ------------------ 1 file changed, 338 deletions(-) delete mode 100644 src/librustc/infer/error_reporting/anon_anon_conflict.rs 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 index 420ac040b30..00000000000 --- a/src/librustc/infer/error_reporting/anon_anon_conflict.rs +++ /dev/null @@ -1,338 +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 or the MIT license -// , 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, 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, scope_def_id_1, scope_def_id_2, bregion1, bregion2) = if - self.is_suitable_anonymous_region(sup, true).is_some() && - self.is_suitable_anonymous_region(sub, true).is_some() { - if let (Some(anon_reg1), Some(anon_reg2)) = - (self.is_suitable_anonymous_region(sup, true), - self.is_suitable_anonymous_region(sub, true)) { - let ((def_id1, br1), (def_id2, br2)) = (anon_reg1, anon_reg2); - let found_arg1 = self.find_anon_type(sup, &br1); - let found_arg2 = self.find_anon_type(sub, &br2); - match (found_arg1, found_arg2) { - (Some(anonarg_1), Some(anonarg_2)) => { - (anonarg_1, anonarg_2, def_id1, def_id2, br1, br2) - } - _ => { - return false; - } - } - - } else { - return false; - } - } else { - return false; //inapplicable - }; - - let (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, _, _, is_first1), (anon_arg2, _, _, is_first2)) = (sup_arg, sub_arg); - if self.is_self_anon(is_first1, scope_def_id_1) || - self.is_self_anon(is_first2, scope_def_id_2) { - return false; - } - - if self.is_return_type_anon(scope_def_id_1, bregion1) || - self.is_return_type_anon(scope_def_id_2, bregion2) { - return false; - } - - - - - if anon_arg1 == anon_arg2 { - (format!(" with one lifetime"), format!(" into the other")) - } else { - let span_label_var1 = if let Some(simple_name) = anon_arg1.pat.simple_name() { - format!(" from `{}`", simple_name) - } else { - format!("") - }; - - let span_label_var2 = if let Some(simple_name) = anon_arg2.pat.simple_name() { - format!(" into `{}`", simple_name) - } else { - format!("") - }; - - (span_label_var1, span_label_var2) - } - } else { - return false; - }; - - struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch") - .span_label(ty1.span, - format!("these two types are declared with different lifetimes...")) - .span_label(ty2.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, true) { - let (def_id, _) = anon_reg; - 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| { - self.find_visitor_found_type(&**arg, br) - }) - .next(); - } - } else if let hir_map::NodeTraitItem(it) = self.tcx.hir.get(node_id) { - if let hir::TraitItemKind::Method(ref fndecl, _) = it.node { - return fndecl - .decl - .inputs - .iter() - .filter_map(|arg| { - self.find_visitor_found_type(&**arg, br) - }) - .next(); - } - } else if let hir_map::NodeImplItem(it) = self.tcx.hir.get(node_id) { - if let hir::ImplItemKind::Method(ref fndecl, _) = it.node { - return fndecl - .decl - .inputs - .iter() - .filter_map(|arg| { - self.find_visitor_found_type(&**arg, br) - }) - .next(); - } - } - } - } - } - None - } - - // This method creates a FindNestedTypeVisitor which returns the type corresponding - // to the anonymous region. - fn find_visitor_found_type(&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, - depth: 1, - }; - 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>, - depth: u32, -} - -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::TyBareFn(ref fndecl) => { - self.depth += 1; - intravisit::walk_ty(self, arg); - self.depth -= 1; - return; - } - - 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 { - 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` - debug!("depth is {:?}", self.depth); - 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(debuijn_index, anon_index)) => { - if debuijn_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); - } -} From 93529b40ca9471ebe3f79817d4f71a5245bec50e Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Tue, 12 Sep 2017 16:48:01 +0530 Subject: [PATCH 6/8] add ui test for fn items, tidy fixes --- .../infer/error_reporting/different_lifetimes.rs | 2 +- .../ex3-both-anon-regions-one-is-struct-3.rs | 4 ---- .../ex3-both-anon-regions-using-fn-items.rs | 14 ++++++++++++++ .../ex3-both-anon-regions-using-fn-items.stderr | 10 ++++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr diff --git a/src/librustc/infer/error_reporting/different_lifetimes.rs b/src/librustc/infer/error_reporting/different_lifetimes.rs index 9546d8a4dd2..a54e75857dd 100644 --- a/src/librustc/infer/error_reporting/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/different_lifetimes.rs @@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { self.depth -= 1; return; } - + hir::TyRptr(ref lifetime, _) => { // the lifetime of the TyRptr let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id); 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 index 5920eeed6b1..4933dbb7e7a 100644 --- 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 @@ -11,11 +11,7 @@ struct Ref<'a, 'b> { a: &'a u32, b: &'b u32 } fn foo(mut y: Ref, x: &u32) { -<<<<<<< HEAD y.b = x; -======= - x = y.b; ->>>>>>> Adding E0623 for structs } fn main() { } diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.rs new file mode 100644 index 00000000000..9220c34489f --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.rs @@ -0,0 +1,14 @@ +// 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(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { + y.push(z); +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr new file mode 100644 index 00000000000..0913abad3cc --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.rs:11:10 + | +10 | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { + | --- --- these two types are declared with different lifetimes... +11 | y.push(z); + | ^ ...but data from `z` flows into `y` here + +error: aborting due to previous error + From 6e3cdcea4c600b89dd067d8af8b7e1738f7df6a5 Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Tue, 12 Sep 2017 18:22:22 +0530 Subject: [PATCH 7/8] Adding changes for trait objects --- .../infer/error_reporting/different_lifetimes.rs | 14 ++++++++++++-- .../ex3-both-anon-regions-using-trait-objects.rs | 14 ++++++++++++++ ...x3-both-anon-regions-using-trait-objects.stderr | 10 ++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr diff --git a/src/librustc/infer/error_reporting/different_lifetimes.rs b/src/librustc/infer/error_reporting/different_lifetimes.rs index a54e75857dd..051263dfb53 100644 --- a/src/librustc/infer/error_reporting/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/different_lifetimes.rs @@ -173,6 +173,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { hir_map: &self.tcx.hir, bound_region: *br, found_type: None, + depth: 1, }; nested_visitor.visit_ty(arg); nested_visitor.found_type @@ -195,6 +196,7 @@ struct FindNestedTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { // The type where the anonymous lifetime appears // for e.g. Vec<`&u8`> and <`&u8`> found_type: Option<&'gcx hir::Ty>, + depth: u32, } impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { @@ -211,6 +213,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { return; } + hir::TyTraitObject(ref bounds, _) => { + for bound in bounds { + self.depth += 1; + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + self.depth -= 1; + } + } + hir::TyRptr(ref lifetime, _) => { // the lifetime of the TyRptr let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id); @@ -224,7 +234,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { debruijn_index.depth, anon_index, br_index); - if debruijn_index.depth == 1 && anon_index == br_index { + if debruijn_index.depth == self.depth && anon_index == br_index { self.found_type = Some(arg); return; // we can stop visiting now } @@ -253,7 +263,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { 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 && + if debruijn_index.depth == self.depth && self.infcx.tcx.hir.local_def_id(id) == def_id { self.found_type = Some(arg); return; // we can stop visiting now diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs new file mode 100644 index 00000000000..78a6ad54eae --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs @@ -0,0 +1,14 @@ +// 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(x:Box , y: Vec<&u8>, z: &u8) { + y.push(z); +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr new file mode 100644 index 00000000000..ce766b2e406 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:10 + | +10 | fn foo(x:Box , y: Vec<&u8>, z: &u8) { + | --- --- these two types are declared with different lifetimes... +11 | y.push(z); + | ^ ...but data from `z` flows into `y` here + +error: aborting due to previous error + From e71eef1775f9da8bc2e8d312b83df007b4751ec6 Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Wed, 13 Sep 2017 20:56:27 +0530 Subject: [PATCH 8/8] fix ui tests --- .../ex3-both-anon-regions-both-are-structs-4.stderr | 2 +- .../lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr index 2ef1cd507f1..689a1ac292b 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr @@ -4,7 +4,7 @@ error[E0623]: lifetime mismatch 15 | fn foo(mut x: Ref) { | --- | | - | these two types are declared with different lifetimes... + | this type was declared with multiple lifetimes... 16 | x.a = x.b; | ^^^ ...but data with one lifetime flows into the other here diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr index 0913abad3cc..adfc4dc0c27 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr @@ -1,5 +1,5 @@ error[E0623]: lifetime mismatch - --> src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.rs:11:10 + --> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:10 | 10 | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { | --- --- these two types are declared with different lifetimes...