1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Helper functions corresponding to lifetime errors due to
12 //! anonymous regions.
15 use ty::{self, Region};
16 use hir::def_id::DefId;
17 use hir::map as hir_map;
19 macro_rules! or_false {
28 // The struct contains the information about the anonymous region
29 // we are searching for.
30 pub struct AnonymousArgInfo<'tcx> {
31 // the argument corresponding to the anonymous region
32 pub arg: &'tcx hir::Arg,
33 // the type corresponding to the anonymopus region argument
34 pub arg_ty: ty::Ty<'tcx>,
35 // the ty::BoundRegion corresponding to the anonymous region
36 pub bound_region: ty::BoundRegion,
37 // corresponds to id the argument is the first parameter
42 // This struct contains information regarding the
43 // Refree((FreeRegion) corresponding to lifetime conflict
44 pub struct FreeRegionInfo {
45 // def id corresponding to FreeRegion
47 // the bound region corresponding to FreeRegion
48 pub boundregion: ty::BoundRegion,
49 // checks if bound region is in Impl Item
50 pub is_impl_item: bool,
53 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
54 // This method walks the Type of the function body arguments using
55 // `fold_regions()` function and returns the
56 // &hir::Arg of the function argument corresponding to the anonymous
57 // region and the Ty corresponding to the named region.
58 // Currently only the case where the function declaration consists of
59 // one named region and one anonymous region is handled.
60 // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
61 // Here, we would return the hir::Arg for y, we return the type &'a
62 // i32, which is the type of y but with the anonymous region replaced
63 // with 'a, the corresponding bound region and is_first which is true if
64 // the hir::Arg is the first argument in the function declaration.
65 pub fn find_arg_with_anonymous_region(&self,
66 anon_region: Region<'tcx>,
67 replace_region: Region<'tcx>)
68 -> Option<AnonymousArgInfo> {
70 if let ty::ReFree(ref free_region) = *anon_region {
71 let id = free_region.scope;
72 let hir = &self.tcx.hir;
73 if let Some(node_id) = hir.as_local_node_id(id) {
74 if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
75 let body = hir.body(body_id);
76 if let Some(tables) = self.in_progress_tables {
80 .filter_map(|(index, arg)| {
81 let ty = tables.borrow().node_id_to_type(arg.hir_id);
82 let mut found_anon_region = false;
83 let new_arg_ty = self.tcx
84 .fold_regions(&ty, &mut false, |r, _| if *r == *anon_region {
85 found_anon_region = true;
90 if found_anon_region {
91 let is_first = index == 0;
92 Some(AnonymousArgInfo {
95 bound_region: free_region.bound_region,
117 // This method returns whether the given Region is Anonymous
118 // and returns the DefId and the BoundRegion corresponding to the given region.
119 pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
120 if let ty::ReFree(ref free_region) = *region {
121 if let ty::BrAnon(..) = free_region.bound_region {
122 let anonymous_region_binding_scope = free_region.scope;
123 let node_id = self.tcx
125 .as_local_node_id(anonymous_region_binding_scope)
127 let mut is_impl_item = false;
128 match self.tcx.hir.find(node_id) {
130 Some(hir_map::NodeItem(..)) |
131 Some(hir_map::NodeTraitItem(..)) => {
132 // Success -- proceed to return Some below
134 Some(hir_map::NodeImplItem(..)) => {
136 self.is_bound_region_in_impl_item(anonymous_region_binding_scope);
140 return Some(FreeRegionInfo {
141 def_id: anonymous_region_binding_scope,
142 boundregion: free_region.bound_region,
143 is_impl_item: is_impl_item,
150 // Here, we check for the case where the anonymous region
151 // is in the return type.
152 // FIXME(#42703) - Need to handle certain cases here.
153 pub fn is_return_type_anon(&self, scope_def_id: DefId, br: ty::BoundRegion) -> bool {
154 let ret_ty = self.tcx.type_of(scope_def_id);
156 ty::TyFnDef(_, _) => {
157 let sig = ret_ty.fn_sig(self.tcx);
158 let late_bound_regions = self.tcx
159 .collect_referenced_late_bound_regions(&sig.output());
160 if late_bound_regions.iter().any(|r| *r == br) {
168 // Here we check for the case where anonymous region
169 // corresponds to self and if yes, we display E0312.
170 // FIXME(#42700) - Need to format self properly to
171 // enable E0621 for it.
172 pub fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool {
175 .opt_associated_item(scope_def_id)
176 .map(|i| i.method_has_self_argument) == Some(true)
179 // Here we check if the bound region is in Impl Item.
180 pub fn is_bound_region_in_impl_item(&self, anonymous_region_binding_scope: DefId) -> bool {
181 let container_id = self.tcx
182 .associated_item(anonymous_region_binding_scope)
185 if self.tcx.impl_trait_ref(container_id).is_some() {
186 // For now, we do not try to target impls of traits. This is
187 // because this message is going to suggest that the user
188 // change the fn signature, but they may not be free to do so,
189 // since the signature must match the trait.
191 // FIXME(#42706) -- in some cases, we could do better here.