]>
Commit | Line | Data |
---|---|---|
3b2f2976 XL |
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. | |
4 | // | |
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. | |
10 | ||
11 | //! Helper functions corresponding to lifetime errors due to | |
12 | //! anonymous regions. | |
b7449926 | 13 | |
3b2f2976 | 14 | use hir; |
ff7c6d11 | 15 | use infer::error_reporting::nice_region_error::NiceRegionError; |
ea8adc8c | 16 | use ty::{self, Region, Ty}; |
3b2f2976 | 17 | use hir::def_id::DefId; |
b7449926 | 18 | use hir::Node; |
ea8adc8c | 19 | use syntax_pos::Span; |
3b2f2976 | 20 | |
3b2f2976 XL |
21 | // The struct contains the information about the anonymous region |
22 | // we are searching for. | |
ea8adc8c | 23 | #[derive(Debug)] |
ff7c6d11 | 24 | pub(super) struct AnonymousArgInfo<'tcx> { |
3b2f2976 XL |
25 | // the argument corresponding to the anonymous region |
26 | pub arg: &'tcx hir::Arg, | |
27 | // the type corresponding to the anonymopus region argument | |
ea8adc8c | 28 | pub arg_ty: Ty<'tcx>, |
3b2f2976 XL |
29 | // the ty::BoundRegion corresponding to the anonymous region |
30 | pub bound_region: ty::BoundRegion, | |
b7449926 XL |
31 | // arg_ty_span contains span of argument type |
32 | pub arg_ty_span : Span, | |
3b2f2976 XL |
33 | // corresponds to id the argument is the first parameter |
34 | // in the declaration | |
35 | pub is_first: bool, | |
36 | } | |
37 | ||
38 | // This struct contains information regarding the | |
39 | // Refree((FreeRegion) corresponding to lifetime conflict | |
ea8adc8c | 40 | #[derive(Debug)] |
ff7c6d11 | 41 | pub(super) struct FreeRegionInfo { |
3b2f2976 XL |
42 | // def id corresponding to FreeRegion |
43 | pub def_id: DefId, | |
44 | // the bound region corresponding to FreeRegion | |
45 | pub boundregion: ty::BoundRegion, | |
46 | // checks if bound region is in Impl Item | |
47 | pub is_impl_item: bool, | |
48 | } | |
49 | ||
ff7c6d11 | 50 | impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { |
3b2f2976 XL |
51 | // This method walks the Type of the function body arguments using |
52 | // `fold_regions()` function and returns the | |
53 | // &hir::Arg of the function argument corresponding to the anonymous | |
54 | // region and the Ty corresponding to the named region. | |
55 | // Currently only the case where the function declaration consists of | |
56 | // one named region and one anonymous region is handled. | |
57 | // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32` | |
58 | // Here, we would return the hir::Arg for y, we return the type &'a | |
59 | // i32, which is the type of y but with the anonymous region replaced | |
60 | // with 'a, the corresponding bound region and is_first which is true if | |
61 | // the hir::Arg is the first argument in the function declaration. | |
ff7c6d11 XL |
62 | pub(super) fn find_arg_with_region( |
63 | &self, | |
64 | anon_region: Region<'tcx>, | |
65 | replace_region: Region<'tcx>, | |
66 | ) -> Option<AnonymousArgInfo> { | |
ea8adc8c XL |
67 | let (id, bound_region) = match *anon_region { |
68 | ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), | |
ff7c6d11 XL |
69 | ty::ReEarlyBound(ref ebr) => ( |
70 | self.tcx.parent_def_id(ebr.def_id).unwrap(), | |
71 | ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), | |
72 | ), | |
ea8adc8c XL |
73 | _ => return None, // not a free region |
74 | }; | |
75 | ||
76 | let hir = &self.tcx.hir; | |
77 | if let Some(node_id) = hir.as_local_node_id(id) { | |
78 | if let Some(body_id) = hir.maybe_body_owned_by(node_id) { | |
79 | let body = hir.body(body_id); | |
b7449926 XL |
80 | let owner_id = hir.body_owner(body_id); |
81 | let fn_decl = hir.fn_decl(owner_id).unwrap(); | |
ff7c6d11 | 82 | if let Some(tables) = self.tables { |
ea8adc8c XL |
83 | body.arguments |
84 | .iter() | |
85 | .enumerate() | |
86 | .filter_map(|(index, arg)| { | |
ff7c6d11 | 87 | // May return None; sometimes the tables are not yet populated. |
b7449926 XL |
88 | let ty_hir_id = fn_decl.inputs[index].hir_id; |
89 | let arg_ty_span = hir.span(hir.hir_to_node_id(ty_hir_id)); | |
ff7c6d11 | 90 | let ty = tables.node_id_to_type_opt(arg.hir_id)?; |
ea8adc8c | 91 | let mut found_anon_region = false; |
ff7c6d11 XL |
92 | let new_arg_ty = self.tcx.fold_regions(&ty, &mut false, |r, _| { |
93 | if *r == *anon_region { | |
ea8adc8c XL |
94 | found_anon_region = true; |
95 | replace_region | |
3b2f2976 | 96 | } else { |
ea8adc8c | 97 | r |
ff7c6d11 XL |
98 | } |
99 | }); | |
ea8adc8c XL |
100 | if found_anon_region { |
101 | let is_first = index == 0; | |
102 | Some(AnonymousArgInfo { | |
ff7c6d11 XL |
103 | arg: arg, |
104 | arg_ty: new_arg_ty, | |
b7449926 | 105 | arg_ty_span : arg_ty_span, |
ff7c6d11 XL |
106 | bound_region: bound_region, |
107 | is_first: is_first, | |
108 | }) | |
ea8adc8c XL |
109 | } else { |
110 | None | |
111 | } | |
112 | }) | |
113 | .next() | |
3b2f2976 XL |
114 | } else { |
115 | None | |
116 | } | |
117 | } else { | |
118 | None | |
119 | } | |
120 | } else { | |
121 | None | |
122 | } | |
123 | } | |
124 | ||
ea8adc8c | 125 | // This method returns the DefId and the BoundRegion corresponding to the given region. |
ff7c6d11 | 126 | pub(super) fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> { |
ea8adc8c XL |
127 | let (suitable_region_binding_scope, bound_region) = match *region { |
128 | ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), | |
ff7c6d11 XL |
129 | ty::ReEarlyBound(ref ebr) => ( |
130 | self.tcx.parent_def_id(ebr.def_id).unwrap(), | |
131 | ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), | |
132 | ), | |
ea8adc8c XL |
133 | _ => return None, // not a free region |
134 | }; | |
135 | ||
136 | let node_id = self.tcx | |
137 | .hir | |
138 | .as_local_node_id(suitable_region_binding_scope) | |
139 | .unwrap(); | |
140 | let is_impl_item = match self.tcx.hir.find(node_id) { | |
b7449926 XL |
141 | Some(Node::Item(..)) | Some(Node::TraitItem(..)) => false, |
142 | Some(Node::ImplItem(..)) => { | |
ea8adc8c XL |
143 | self.is_bound_region_in_impl_item(suitable_region_binding_scope) |
144 | } | |
145 | _ => return None, | |
146 | }; | |
147 | ||
148 | return Some(FreeRegionInfo { | |
ff7c6d11 XL |
149 | def_id: suitable_region_binding_scope, |
150 | boundregion: bound_region, | |
151 | is_impl_item: is_impl_item, | |
152 | }); | |
3b2f2976 XL |
153 | } |
154 | ||
155 | // Here, we check for the case where the anonymous region | |
156 | // is in the return type. | |
157 | // FIXME(#42703) - Need to handle certain cases here. | |
ff7c6d11 XL |
158 | pub(super) fn is_return_type_anon( |
159 | &self, | |
160 | scope_def_id: DefId, | |
161 | br: ty::BoundRegion, | |
162 | decl: &hir::FnDecl, | |
163 | ) -> Option<Span> { | |
3b2f2976 XL |
164 | let ret_ty = self.tcx.type_of(scope_def_id); |
165 | match ret_ty.sty { | |
b7449926 | 166 | ty::FnDef(_, _) => { |
3b2f2976 XL |
167 | let sig = ret_ty.fn_sig(self.tcx); |
168 | let late_bound_regions = self.tcx | |
169 | .collect_referenced_late_bound_regions(&sig.output()); | |
170 | if late_bound_regions.iter().any(|r| *r == br) { | |
ea8adc8c | 171 | return Some(decl.output.span()); |
3b2f2976 XL |
172 | } |
173 | } | |
174 | _ => {} | |
175 | } | |
ea8adc8c | 176 | None |
3b2f2976 | 177 | } |
8faf50e0 XL |
178 | |
179 | pub(super) fn is_return_type_impl_trait( | |
180 | &self, | |
181 | scope_def_id: DefId, | |
182 | ) -> bool { | |
183 | let ret_ty = self.tcx.type_of(scope_def_id); | |
184 | match ret_ty.sty { | |
b7449926 | 185 | ty::FnDef(_, _) => { |
8faf50e0 XL |
186 | let sig = ret_ty.fn_sig(self.tcx); |
187 | let output = self.tcx.erase_late_bound_regions(&sig.output()); | |
188 | return output.is_impl_trait(); | |
189 | } | |
190 | _ => {} | |
191 | } | |
192 | false | |
193 | } | |
194 | ||
3b2f2976 XL |
195 | // Here we check for the case where anonymous region |
196 | // corresponds to self and if yes, we display E0312. | |
197 | // FIXME(#42700) - Need to format self properly to | |
198 | // enable E0621 for it. | |
ff7c6d11 XL |
199 | pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool { |
200 | is_first | |
201 | && self.tcx | |
202 | .opt_associated_item(scope_def_id) | |
203 | .map(|i| i.method_has_self_argument) == Some(true) | |
3b2f2976 XL |
204 | } |
205 | ||
206 | // Here we check if the bound region is in Impl Item. | |
ff7c6d11 XL |
207 | pub(super) fn is_bound_region_in_impl_item( |
208 | &self, | |
209 | suitable_region_binding_scope: DefId, | |
210 | ) -> bool { | |
3b2f2976 | 211 | let container_id = self.tcx |
ea8adc8c | 212 | .associated_item(suitable_region_binding_scope) |
3b2f2976 XL |
213 | .container |
214 | .id(); | |
215 | if self.tcx.impl_trait_ref(container_id).is_some() { | |
216 | // For now, we do not try to target impls of traits. This is | |
217 | // because this message is going to suggest that the user | |
218 | // change the fn signature, but they may not be free to do so, | |
219 | // since the signature must match the trait. | |
220 | // | |
221 | // FIXME(#42706) -- in some cases, we could do better here. | |
222 | return true; | |
223 | } | |
224 | false | |
225 | } | |
226 | } |