diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs index 3acaed6ca480..33d38cfb0405 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -10,14 +10,9 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where both the regions are anonymous. -use hir; use infer::InferCtxt; -use ty::{self, Region}; use infer::lexical_region_resolve::RegionResolutionError::*; use infer::lexical_region_resolve::RegionResolutionError; -use hir::map as hir_map; -use middle::resolve_lifetime as rl; -use hir::intravisit::{self, Visitor, NestedVisitorMap}; use infer::error_reporting::nice_region_error::util::AnonymousArgInfo; impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { @@ -153,263 +148,5 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .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, &hir::FnDecl)> { - 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 fndecl = match self.tcx.hir.get(node_id) { - hir_map::NodeItem(&hir::Item { node: hir::ItemFn(ref fndecl, ..), .. }) => { - &fndecl - } - hir_map::NodeTraitItem(&hir::TraitItem { - node: hir::TraitItemKind::Method(ref m, ..), .. - }) | - hir_map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method(ref m, ..), .. - }) => &m.decl, - _ => return None, - }; - - return fndecl - .inputs - .iter() - .filter_map(|arg| self.find_component_for_bound_region(arg, br)) - .next() - .map(|ty| (ty, &**fndecl)); - } - } - 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, - 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) { - match arg.node { - hir::TyBareFn(_) => { - self.depth += 1; - intravisit::walk_ty(self, arg); - self.depth -= 1; - 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); - 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 == self.depth && anon_index == br_index { - self.found_type = Some(arg); - return; // we can stop visiting now - } - } - - // Find the index of the named region that was part of the - // error. We will then search the function parameters for a bound - // region at the right depth with the same index - (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { - debug!("EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \ - def_id={:?}", id, def_id); - if 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)={:?}", id); - debug!("def_id={:?}", def_id); - if debruijn_index.depth == self.depth && id == def_id { - self.found_type = Some(arg); - return; // we can stop visiting now - } - } - - (Some(rl::Region::Static), _) | - (Some(rl::Region::Free(_, _)), _) | - (Some(rl::Region::EarlyBound(_, _, _)), _) | - (Some(rl::Region::LateBound(_, _, _)), _) | - (Some(rl::Region::LateBoundAnon(_, _)), _) | - (None, _) => { - debug!("no arg found"); - } - } - } - // Checks if it is of type `hir::TyPath` which corresponds to a struct. - hir::TyPath(_) => { - let subvisitor = &mut TyPathVisitor { - infcx: self.infcx, - found_it: false, - bound_region: self.bound_region, - hir_map: self.hir_map, - depth: self.depth, - }; - 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, - depth: u32, -} - -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 hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id); - match (self.infcx.tcx.named_region(hir_id), self.bound_region) { - // the lifetime of the TyPath! - (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => { - if debruijn_index.depth == self.depth && anon_index == br_index { - self.found_it = true; - return; - } - } - - (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { - debug!("EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \ - def_id={:?}", id, def_id); - if id == def_id { - self.found_it = true; - return; // we can stop visiting now - } - } - - (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => { - debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", - debruijn_index.depth); - debug!("id={:?}", id); - debug!("def_id={:?}", def_id); - if debruijn_index.depth == self.depth && id == def_id { - self.found_it = true; - return; // we can stop visiting now - } - } - - (Some(rl::Region::Static), _) | - (Some(rl::Region::EarlyBound(_, _, _)), _) | - (Some(rl::Region::LateBound(_, _, _)), _) | - (Some(rl::Region::LateBoundAnon(_, _)), _) | - (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/nice_region_error/find_anon_type.rs b/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs new file mode 100644 index 000000000000..e93b93fcc7ca --- /dev/null +++ b/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -0,0 +1,295 @@ +// 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. + +use hir; +use infer::InferCtxt; +use ty::{self, Region}; +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 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(super) fn find_anon_type( + &self, + region: Region<'tcx>, + br: &ty::BoundRegion, + ) -> Option<(&hir::Ty, &hir::FnDecl)> { + 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 fndecl = match self.tcx.hir.get(node_id) { + hir_map::NodeItem(&hir::Item { + node: hir::ItemFn(ref fndecl, ..), + .. + }) => &fndecl, + hir_map::NodeTraitItem(&hir::TraitItem { + node: hir::TraitItemKind::Method(ref m, ..), + .. + }) + | hir_map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(ref m, ..), + .. + }) => &m.decl, + _ => return None, + }; + + return fndecl + .inputs + .iter() + .filter_map(|arg| self.find_component_for_bound_region(arg, br)) + .next() + .map(|ty| (ty, &**fndecl)); + } + } + 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, + 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) { + match arg.node { + hir::TyBareFn(_) => { + self.depth += 1; + intravisit::walk_ty(self, arg); + self.depth -= 1; + 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); + 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 == self.depth && anon_index == br_index { + self.found_type = Some(arg); + return; // we can stop visiting now + } + } + + // Find the index of the named region that was part of the + // error. We will then search the function parameters for a bound + // region at the right depth with the same index + (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { + debug!( + "EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \ + def_id={:?}", + id, + def_id + ); + if 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)={:?}", id); + debug!("def_id={:?}", def_id); + if debruijn_index.depth == self.depth && id == def_id { + self.found_type = Some(arg); + return; // we can stop visiting now + } + } + + (Some(rl::Region::Static), _) + | (Some(rl::Region::Free(_, _)), _) + | (Some(rl::Region::EarlyBound(_, _, _)), _) + | (Some(rl::Region::LateBound(_, _, _)), _) + | (Some(rl::Region::LateBoundAnon(_, _)), _) + | (None, _) => { + debug!("no arg found"); + } + } + } + // Checks if it is of type `hir::TyPath` which corresponds to a struct. + hir::TyPath(_) => { + let subvisitor = &mut TyPathVisitor { + infcx: self.infcx, + found_it: false, + bound_region: self.bound_region, + hir_map: self.hir_map, + depth: self.depth, + }; + 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, + depth: u32, +} + +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 hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id); + match (self.infcx.tcx.named_region(hir_id), self.bound_region) { + // the lifetime of the TyPath! + (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => { + if debruijn_index.depth == self.depth && anon_index == br_index { + self.found_it = true; + return; + } + } + + (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { + debug!( + "EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \ + def_id={:?}", + id, + def_id + ); + if id == def_id { + self.found_it = true; + return; // we can stop visiting now + } + } + + (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => { + debug!( + "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", + debruijn_index.depth + ); + debug!("id={:?}", id); + debug!("def_id={:?}", def_id); + if debruijn_index.depth == self.depth && id == def_id { + self.found_it = true; + return; // we can stop visiting now + } + } + + (Some(rl::Region::Static), _) + | (Some(rl::Region::EarlyBound(_, _, _)), _) + | (Some(rl::Region::LateBound(_, _, _)), _) + | (Some(rl::Region::LateBoundAnon(_, _)), _) + | (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/nice_region_error/mod.rs b/src/librustc/infer/error_reporting/nice_region_error/mod.rs index 1d83b3b1b8f3..ca6247defe01 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/mod.rs @@ -10,5 +10,6 @@ #[macro_use] mod util; +mod find_anon_type; mod different_lifetimes; mod named_anon_conflict;