+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Error Reporting for Anonymous Region Lifetime Errors
-//! where both the regions are anonymous.
-use hir;
-use infer::InferCtxt;
-use ty::{self, Region};
-use infer::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::util::AnonymousArgInfo;
-
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
- /// Print the error message for lifetime errors when both the concerned regions are anonymous.
- ///
- /// Consider a case where we have
- ///
- /// ```no_run
- /// fn foo(x: &mut Vec<&u8>, y: &u8) {
- /// x.push(y);
- /// }
- /// ```
- ///
- /// The example gives
- ///
- /// ```text
- /// 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
- ///
- /// ```no_run
- /// struct Ref<'a> { x: &'a u32 }
- /// ```
- ///
- /// ```text
- /// fn foo(mut x: Vec<Ref>, y: Ref) {
- /// --- --- these structs are declared with different lifetimes...
- /// x.push(y);
- /// ^ ...but data from `y` flows into `x` here
- /// }
- /// ````
- ///
- /// It will later be extended to trait objects.
- pub fn try_report_anon_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
- let (span, sub, sup) = match *error {
- ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
- SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup),
- _ => return false, // inapplicable
- };
-
- // Determine whether the sub and sup consist of both anonymous (elided) regions.
- let anon_reg_sup = or_false!(self.is_suitable_region(sup));
-
- let anon_reg_sub = or_false!(self.is_suitable_region(sub));
- let scope_def_id_sup = anon_reg_sup.def_id;
- let bregion_sup = anon_reg_sup.boundregion;
- let scope_def_id_sub = anon_reg_sub.def_id;
- let bregion_sub = anon_reg_sub.boundregion;
-
- let ty_sup = or_false!(self.find_anon_type(sup, &bregion_sup));
-
- let ty_sub = or_false!(self.find_anon_type(sub, &bregion_sub));
-
- debug!("try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}",
- ty_sub,
- sup,
- bregion_sup);
- debug!("try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}",
- ty_sup,
- sub,
- bregion_sub);
-
- let (ty_sup, ty_fndecl_sup) = ty_sup;
- let (ty_sub, ty_fndecl_sub) = ty_sub;
-
- let AnonymousArgInfo { arg: anon_arg_sup, .. } =
- or_false!(self.find_arg_with_region(sup, sup));
- let AnonymousArgInfo { arg: anon_arg_sub, .. } =
- or_false!(self.find_arg_with_region(sub, sub));
-
- let sup_is_ret_type =
- self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
- let sub_is_ret_type =
- self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
-
- 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_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) {
- (None, None) => {
- let (main_label_1, span_label_1) = if ty_sup == ty_sub {
-
- (format!("this type is declared with multiple lifetimes..."),
- format!("...but data{} flows{} here",
- format!(" with one lifetime"),
- format!(" into the other")))
- } else {
- (format!("these two types are declared with different lifetimes..."),
- format!("...but data{} flows{} here",
- span_label_var1,
- span_label_var2))
- };
- (ty_sup.span, ty_sub.span, main_label_1, span_label_1)
- }
-
- (Some(ret_span), _) => {
- (ty_sub.span,
- ret_span,
- format!("this parameter and the return type are declared \
- with different lifetimes...",),
- format!("...but data{} is returned here", span_label_var1))
- }
- (_, Some(ret_span)) => {
- (ty_sup.span,
- ret_span,
- format!("this parameter and the return type are declared \
- with different lifetimes...",),
- format!("...but data{} is returned here", span_label_var1))
- }
- };
-
-
- struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
- .span_label(span_1, main_label)
- .span_label(span_2, format!(""))
- .span_label(span, span_label)
- .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<Ref> in the above example and Ref looking for the HIR
-// where that lifetime appears. This allows us to highlight the
-// specific part of the type in the error message.
-struct TyPathVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
- infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
- hir_map: &'a hir::map::Map<'gcx>,
- found_it: bool,
- bound_region: ty::BoundRegion,
- 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);
- }
-}
mod need_type_info;
-mod named_anon_conflict;
-#[macro_use]
-mod util;
-mod different_lifetimes;
+mod nice_region_error;
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn note_and_explain_region(self,
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Error Reporting for Anonymous Region Lifetime Errors
-//! where one region is named and the other is anonymous.
-use infer::InferCtxt;
-use infer::lexical_region_resolve::RegionResolutionError::*;
-use infer::lexical_region_resolve::RegionResolutionError;
-use ty;
-
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
- /// When given a `ConcreteFailure` for a function with arguments containing a named region and
- /// an anonymous region, emit an descriptive diagnostic error.
- pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
- let (span, sub, sup) = match *error {
- ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
- SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup),
- _ => return false, // inapplicable
- };
-
- debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})", sub, sup);
-
- // Determine whether the sub and sup consist of one named region ('a)
- // and one anonymous (elided) region. If so, find the parameter arg
- // where the anonymous region appears (there must always be one; we
- // 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.//scope_def_id
- let (named, anon, anon_arg_info, region_info) =
- if self.is_named_region(sub) && self.is_suitable_region(sup).is_some() &&
- self.find_arg_with_region(sup, sub).is_some() {
- (sub,
- sup,
- self.find_arg_with_region(sup, sub).unwrap(),
- self.is_suitable_region(sup).unwrap())
- } else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() &&
- self.find_arg_with_region(sub, sup).is_some() {
- (sup,
- sub,
- self.find_arg_with_region(sub, sup).unwrap(),
- self.is_suitable_region(sub).unwrap())
- } else {
- return false; // inapplicable
- };
-
- debug!("try_report_named_anon_conflict: named = {:?}", named);
- debug!("try_report_named_anon_conflict: anon_arg_info = {:?}", anon_arg_info);
- debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);
-
- let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
- anon_arg_info.arg_ty,
- anon_arg_info.bound_region,
- anon_arg_info.is_first,
- region_info.def_id,
- region_info.is_impl_item);
- match br {
- ty::BrAnon(_) => {}
- _ => {
- /* not an anonymous region */
- debug!("try_report_named_anon_conflict: not an anonymous region");
- return false;
- }
- }
-
- if is_impl_item {
- debug!("try_report_named_anon_conflict: impl item, bail out");
- return false;
- }
-
- if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
- if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() ||
- self.is_self_anon(is_first, scope_def_id) {
- 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))
- } 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;
- }
-}
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Error Reporting for Anonymous Region Lifetime Errors
+//! where both the regions are anonymous.
+use hir;
+use infer::InferCtxt;
+use ty::{self, Region};
+use infer::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> {
+ /// Print the error message for lifetime errors when both the concerned regions are anonymous.
+ ///
+ /// Consider a case where we have
+ ///
+ /// ```no_run
+ /// fn foo(x: &mut Vec<&u8>, y: &u8) {
+ /// x.push(y);
+ /// }
+ /// ```
+ ///
+ /// The example gives
+ ///
+ /// ```text
+ /// 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
+ ///
+ /// ```no_run
+ /// struct Ref<'a> { x: &'a u32 }
+ /// ```
+ ///
+ /// ```text
+ /// fn foo(mut x: Vec<Ref>, y: Ref) {
+ /// --- --- these structs are declared with different lifetimes...
+ /// x.push(y);
+ /// ^ ...but data from `y` flows into `x` here
+ /// }
+ /// ````
+ ///
+ /// It will later be extended to trait objects.
+ pub fn try_report_anon_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
+ let (span, sub, sup) = match *error {
+ ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
+ SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup),
+ _ => return false, // inapplicable
+ };
+
+ // Determine whether the sub and sup consist of both anonymous (elided) regions.
+ let anon_reg_sup = or_false!(self.is_suitable_region(sup));
+
+ let anon_reg_sub = or_false!(self.is_suitable_region(sub));
+ let scope_def_id_sup = anon_reg_sup.def_id;
+ let bregion_sup = anon_reg_sup.boundregion;
+ let scope_def_id_sub = anon_reg_sub.def_id;
+ let bregion_sub = anon_reg_sub.boundregion;
+
+ let ty_sup = or_false!(self.find_anon_type(sup, &bregion_sup));
+
+ let ty_sub = or_false!(self.find_anon_type(sub, &bregion_sub));
+
+ debug!("try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}",
+ ty_sub,
+ sup,
+ bregion_sup);
+ debug!("try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}",
+ ty_sup,
+ sub,
+ bregion_sub);
+
+ let (ty_sup, ty_fndecl_sup) = ty_sup;
+ let (ty_sub, ty_fndecl_sub) = ty_sub;
+
+ let AnonymousArgInfo { arg: anon_arg_sup, .. } =
+ or_false!(self.find_arg_with_region(sup, sup));
+ let AnonymousArgInfo { arg: anon_arg_sub, .. } =
+ or_false!(self.find_arg_with_region(sub, sub));
+
+ let sup_is_ret_type =
+ self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
+ let sub_is_ret_type =
+ self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
+
+ 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_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) {
+ (None, None) => {
+ let (main_label_1, span_label_1) = if ty_sup == ty_sub {
+
+ (format!("this type is declared with multiple lifetimes..."),
+ format!("...but data{} flows{} here",
+ format!(" with one lifetime"),
+ format!(" into the other")))
+ } else {
+ (format!("these two types are declared with different lifetimes..."),
+ format!("...but data{} flows{} here",
+ span_label_var1,
+ span_label_var2))
+ };
+ (ty_sup.span, ty_sub.span, main_label_1, span_label_1)
+ }
+
+ (Some(ret_span), _) => {
+ (ty_sub.span,
+ ret_span,
+ format!("this parameter and the return type are declared \
+ with different lifetimes...",),
+ format!("...but data{} is returned here", span_label_var1))
+ }
+ (_, Some(ret_span)) => {
+ (ty_sup.span,
+ ret_span,
+ format!("this parameter and the return type are declared \
+ with different lifetimes...",),
+ format!("...but data{} is returned here", span_label_var1))
+ }
+ };
+
+
+ struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
+ .span_label(span_1, main_label)
+ .span_label(span_2, format!(""))
+ .span_label(span, span_label)
+ .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<Ref> in the above example and Ref looking for the HIR
+// where that lifetime appears. This allows us to highlight the
+// specific part of the type in the error message.
+struct TyPathVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+ infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+ hir_map: &'a hir::map::Map<'gcx>,
+ found_it: bool,
+ bound_region: ty::BoundRegion,
+ 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);
+ }
+}
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[macro_use] mod util;
+
+mod different_lifetimes;
+mod named_anon_conflict;
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Error Reporting for Anonymous Region Lifetime Errors
+//! where one region is named and the other is anonymous.
+use infer::InferCtxt;
+use infer::lexical_region_resolve::RegionResolutionError::*;
+use infer::lexical_region_resolve::RegionResolutionError;
+use ty;
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+ /// When given a `ConcreteFailure` for a function with arguments containing a named region and
+ /// an anonymous region, emit an descriptive diagnostic error.
+ pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
+ let (span, sub, sup) = match *error {
+ ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
+ SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup),
+ _ => return false, // inapplicable
+ };
+
+ debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})", sub, sup);
+
+ // Determine whether the sub and sup consist of one named region ('a)
+ // and one anonymous (elided) region. If so, find the parameter arg
+ // where the anonymous region appears (there must always be one; we
+ // 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.//scope_def_id
+ let (named, anon, anon_arg_info, region_info) =
+ if self.is_named_region(sub) && self.is_suitable_region(sup).is_some() &&
+ self.find_arg_with_region(sup, sub).is_some() {
+ (sub,
+ sup,
+ self.find_arg_with_region(sup, sub).unwrap(),
+ self.is_suitable_region(sup).unwrap())
+ } else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() &&
+ self.find_arg_with_region(sub, sup).is_some() {
+ (sup,
+ sub,
+ self.find_arg_with_region(sub, sup).unwrap(),
+ self.is_suitable_region(sub).unwrap())
+ } else {
+ return false; // inapplicable
+ };
+
+ debug!("try_report_named_anon_conflict: named = {:?}", named);
+ debug!("try_report_named_anon_conflict: anon_arg_info = {:?}", anon_arg_info);
+ debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);
+
+ let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
+ anon_arg_info.arg_ty,
+ anon_arg_info.bound_region,
+ anon_arg_info.is_first,
+ region_info.def_id,
+ region_info.is_impl_item);
+ match br {
+ ty::BrAnon(_) => {}
+ _ => {
+ /* not an anonymous region */
+ debug!("try_report_named_anon_conflict: not an anonymous region");
+ return false;
+ }
+ }
+
+ if is_impl_item {
+ debug!("try_report_named_anon_conflict: impl item, bail out");
+ return false;
+ }
+
+ if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
+ if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() ||
+ self.is_self_anon(is_first, scope_def_id) {
+ 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))
+ } 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;
+ }
+}
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Helper functions corresponding to lifetime errors due to
+//! anonymous regions.
+use hir;
+use infer::InferCtxt;
+use ty::{self, Region, Ty};
+use hir::def_id::DefId;
+use hir::map as hir_map;
+use syntax_pos::Span;
+
+macro_rules! or_false {
+ ($v:expr) => {
+ match $v {
+ Some(v) => v,
+ None => {
+ debug!("or_false failed: {}", stringify!($v));
+ return false;
+ }
+ }
+ }
+}
+
+// The struct contains the information about the anonymous region
+// we are searching for.
+#[derive(Debug)]
+pub struct AnonymousArgInfo<'tcx> {
+ // the argument corresponding to the anonymous region
+ pub arg: &'tcx hir::Arg,
+ // the type corresponding to the anonymopus region argument
+ pub arg_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
+#[derive(Debug)]
+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
+ // &hir::Arg of the function argument corresponding to the anonymous
+ // region and the Ty corresponding to the named region.
+ // Currently only the case where the function declaration consists of
+ // one named region and one anonymous region is handled.
+ // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
+ // Here, we would return the hir::Arg for y, we return the type &'a
+ // 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_region(&self,
+ anon_region: Region<'tcx>,
+ replace_region: Region<'tcx>)
+ -> Option<AnonymousArgInfo> {
+
+ let (id, bound_region) = match *anon_region {
+ ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
+ ty::ReEarlyBound(ref ebr) => {
+ (self.tcx.parent_def_id(ebr.def_id).unwrap(),
+ ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
+ }
+ _ => return None, // not a free region
+ };
+
+ let hir = &self.tcx.hir;
+ if let Some(node_id) = hir.as_local_node_id(id) {
+ if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
+ let body = hir.body(body_id);
+ if let Some(tables) = self.in_progress_tables {
+ body.arguments
+ .iter()
+ .enumerate()
+ .filter_map(|(index, arg)| {
+ // May return None; sometimes the tables are not yet populated.
+ let ty = tables.borrow().node_id_to_type_opt(arg.hir_id)?;
+ let mut found_anon_region = false;
+ let new_arg_ty = self.tcx
+ .fold_regions(&ty, &mut false, |r, _| if *r == *anon_region {
+ found_anon_region = true;
+ replace_region
+ } else {
+ r
+ });
+ if found_anon_region {
+ let is_first = index == 0;
+ Some(AnonymousArgInfo {
+ arg: arg,
+ arg_ty: new_arg_ty,
+ bound_region: bound_region,
+ is_first: is_first,
+ })
+ } else {
+ None
+ }
+ })
+ .next()
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+
+ // This method returns the DefId and the BoundRegion corresponding to the given region.
+ pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
+
+ let (suitable_region_binding_scope, bound_region) = match *region {
+ ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
+ ty::ReEarlyBound(ref ebr) => {
+ (self.tcx.parent_def_id(ebr.def_id).unwrap(),
+ ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
+ }
+ _ => return None, // not a free region
+ };
+
+ let node_id = self.tcx
+ .hir
+ .as_local_node_id(suitable_region_binding_scope)
+ .unwrap();
+ let is_impl_item = match self.tcx.hir.find(node_id) {
+
+ Some(hir_map::NodeItem(..)) |
+ Some(hir_map::NodeTraitItem(..)) => false,
+ Some(hir_map::NodeImplItem(..)) => {
+ self.is_bound_region_in_impl_item(suitable_region_binding_scope)
+ }
+ _ => return None,
+ };
+
+ return Some(FreeRegionInfo {
+ def_id: suitable_region_binding_scope,
+ boundregion: bound_region,
+ is_impl_item: is_impl_item,
+ });
+
+ }
+
+ // Here, we check for the case where the anonymous region
+ // 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,
+ decl: &hir::FnDecl)
+ -> Option<Span> {
+ 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 Some(decl.output.span());
+ }
+ }
+ _ => {}
+ }
+ None
+ }
+ // 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, suitable_region_binding_scope: DefId) -> bool {
+ let container_id = self.tcx
+ .associated_item(suitable_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
+ }
+
+ // This method returns whether the given Region is Named
+ pub fn is_named_region(&self, region: Region<'tcx>) -> bool {
+ match *region {
+ ty::ReFree(ref free_region) => {
+ match free_region.bound_region {
+ ty::BrNamed(..) => true,
+ _ => false,
+ }
+ }
+ ty::ReEarlyBound(_) => true,
+ _ => false,
+ }
+ }
+}
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Helper functions corresponding to lifetime errors due to
-//! anonymous regions.
-use hir;
-use infer::InferCtxt;
-use ty::{self, Region, Ty};
-use hir::def_id::DefId;
-use hir::map as hir_map;
-use syntax_pos::Span;
-
-macro_rules! or_false {
- ($v:expr) => {
- match $v {
- Some(v) => v,
- None => {
- debug!("or_false failed: {}", stringify!($v));
- return false;
- }
- }
- }
-}
-
-// The struct contains the information about the anonymous region
-// we are searching for.
-#[derive(Debug)]
-pub struct AnonymousArgInfo<'tcx> {
- // the argument corresponding to the anonymous region
- pub arg: &'tcx hir::Arg,
- // the type corresponding to the anonymopus region argument
- pub arg_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
-#[derive(Debug)]
-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
- // &hir::Arg of the function argument corresponding to the anonymous
- // region and the Ty corresponding to the named region.
- // Currently only the case where the function declaration consists of
- // one named region and one anonymous region is handled.
- // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
- // Here, we would return the hir::Arg for y, we return the type &'a
- // 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_region(&self,
- anon_region: Region<'tcx>,
- replace_region: Region<'tcx>)
- -> Option<AnonymousArgInfo> {
-
- let (id, bound_region) = match *anon_region {
- ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
- ty::ReEarlyBound(ref ebr) => {
- (self.tcx.parent_def_id(ebr.def_id).unwrap(),
- ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
- }
- _ => return None, // not a free region
- };
-
- let hir = &self.tcx.hir;
- if let Some(node_id) = hir.as_local_node_id(id) {
- if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
- let body = hir.body(body_id);
- if let Some(tables) = self.in_progress_tables {
- body.arguments
- .iter()
- .enumerate()
- .filter_map(|(index, arg)| {
- // May return None; sometimes the tables are not yet populated.
- let ty = tables.borrow().node_id_to_type_opt(arg.hir_id)?;
- let mut found_anon_region = false;
- let new_arg_ty = self.tcx
- .fold_regions(&ty, &mut false, |r, _| if *r == *anon_region {
- found_anon_region = true;
- replace_region
- } else {
- r
- });
- if found_anon_region {
- let is_first = index == 0;
- Some(AnonymousArgInfo {
- arg: arg,
- arg_ty: new_arg_ty,
- bound_region: bound_region,
- is_first: is_first,
- })
- } else {
- None
- }
- })
- .next()
- } else {
- None
- }
- } else {
- None
- }
- } else {
- None
- }
- }
-
- // This method returns the DefId and the BoundRegion corresponding to the given region.
- pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
-
- let (suitable_region_binding_scope, bound_region) = match *region {
- ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
- ty::ReEarlyBound(ref ebr) => {
- (self.tcx.parent_def_id(ebr.def_id).unwrap(),
- ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
- }
- _ => return None, // not a free region
- };
-
- let node_id = self.tcx
- .hir
- .as_local_node_id(suitable_region_binding_scope)
- .unwrap();
- let is_impl_item = match self.tcx.hir.find(node_id) {
-
- Some(hir_map::NodeItem(..)) |
- Some(hir_map::NodeTraitItem(..)) => false,
- Some(hir_map::NodeImplItem(..)) => {
- self.is_bound_region_in_impl_item(suitable_region_binding_scope)
- }
- _ => return None,
- };
-
- return Some(FreeRegionInfo {
- def_id: suitable_region_binding_scope,
- boundregion: bound_region,
- is_impl_item: is_impl_item,
- });
-
- }
-
- // Here, we check for the case where the anonymous region
- // 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,
- decl: &hir::FnDecl)
- -> Option<Span> {
- 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 Some(decl.output.span());
- }
- }
- _ => {}
- }
- None
- }
- // 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, suitable_region_binding_scope: DefId) -> bool {
- let container_id = self.tcx
- .associated_item(suitable_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
- }
-
- // This method returns whether the given Region is Named
- pub fn is_named_region(&self, region: Region<'tcx>) -> bool {
- match *region {
- ty::ReFree(ref free_region) => {
- match free_region.bound_region {
- ty::BrNamed(..) => true,
- _ => false,
- }
- }
- ty::ReEarlyBound(_) => true,
- _ => false,
- }
- }
-}