]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | use crate::hir; |
2 | use crate::ty::{self, Region, TyCtxt}; | |
3 | use crate::hir::Node; | |
4 | use crate::middle::resolve_lifetime as rl; | |
5 | use crate::hir::intravisit::{self, NestedVisitorMap, Visitor}; | |
6 | use crate::infer::error_reporting::nice_region_error::NiceRegionError; | |
ff7c6d11 | 7 | |
dc9dc135 | 8 | impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { |
ff7c6d11 XL |
9 | /// This function calls the `visit_ty` method for the parameters |
10 | /// corresponding to the anonymous regions. The `nested_visitor.found_type` | |
11 | /// contains the anonymous type. | |
12 | /// | |
13 | /// # Arguments | |
14 | /// region - the anonymous region corresponding to the anon_anon conflict | |
15 | /// br - the bound region corresponding to the above region which is of type `BrAnon(_)` | |
16 | /// | |
17 | /// # Example | |
18 | /// ``` | |
19 | /// fn foo(x: &mut Vec<&u8>, y: &u8) | |
20 | /// { x.push(y); } | |
21 | /// ``` | |
22 | /// The function returns the nested type corresponding to the anonymous region | |
0731742a | 23 | /// for e.g., `&u8` and Vec<`&u8`. |
ff7c6d11 XL |
24 | pub(super) fn find_anon_type( |
25 | &self, | |
26 | region: Region<'tcx>, | |
27 | br: &ty::BoundRegion, | |
28 | ) -> Option<(&hir::Ty, &hir::FnDecl)> { | |
9fa01778 | 29 | if let Some(anon_reg) = self.tcx().is_suitable_region(region) { |
ff7c6d11 | 30 | let def_id = anon_reg.def_id; |
dc9dc135 XL |
31 | if let Some(hir_id) = self.tcx().hir().as_local_hir_id(def_id) { |
32 | let fndecl = match self.tcx().hir().get(hir_id) { | |
b7449926 | 33 | Node::Item(&hir::Item { |
60c5eb7d | 34 | kind: hir::ItemKind::Fn(ref m, ..), |
ff7c6d11 | 35 | .. |
60c5eb7d XL |
36 | }) |
37 | | Node::TraitItem(&hir::TraitItem { | |
e74abb32 | 38 | kind: hir::TraitItemKind::Method(ref m, ..), |
ff7c6d11 XL |
39 | .. |
40 | }) | |
b7449926 | 41 | | Node::ImplItem(&hir::ImplItem { |
e74abb32 | 42 | kind: hir::ImplItemKind::Method(ref m, ..), |
ff7c6d11 XL |
43 | .. |
44 | }) => &m.decl, | |
45 | _ => return None, | |
46 | }; | |
47 | ||
48 | return fndecl | |
49 | .inputs | |
50 | .iter() | |
51 | .filter_map(|arg| self.find_component_for_bound_region(arg, br)) | |
52 | .next() | |
53 | .map(|ty| (ty, &**fndecl)); | |
54 | } | |
55 | } | |
56 | None | |
57 | } | |
58 | ||
59 | // This method creates a FindNestedTypeVisitor which returns the type corresponding | |
60 | // to the anonymous region. | |
61 | fn find_component_for_bound_region( | |
62 | &self, | |
dc9dc135 | 63 | arg: &'tcx hir::Ty, |
ff7c6d11 | 64 | br: &ty::BoundRegion, |
e74abb32 | 65 | ) -> Option<&'tcx hir::Ty> { |
ff7c6d11 | 66 | let mut nested_visitor = FindNestedTypeVisitor { |
9fa01778 | 67 | tcx: self.tcx(), |
ff7c6d11 XL |
68 | bound_region: *br, |
69 | found_type: None, | |
94b46f34 | 70 | current_index: ty::INNERMOST, |
ff7c6d11 XL |
71 | }; |
72 | nested_visitor.visit_ty(arg); | |
73 | nested_visitor.found_type | |
74 | } | |
75 | } | |
76 | ||
77 | // The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the | |
78 | // anonymous region. The example above would lead to a conflict between | |
79 | // the two anonymous lifetimes for &u8 in x and y respectively. This visitor | |
80 | // would be invoked twice, once for each lifetime, and would | |
81 | // walk the types like &mut Vec<&u8> and &u8 looking for the HIR | |
82 | // where that lifetime appears. This allows us to highlight the | |
83 | // specific part of the type in the error message. | |
dc9dc135 XL |
84 | struct FindNestedTypeVisitor<'tcx> { |
85 | tcx: TyCtxt<'tcx>, | |
ff7c6d11 XL |
86 | // The bound_region corresponding to the Refree(freeregion) |
87 | // associated with the anonymous region we are looking for. | |
88 | bound_region: ty::BoundRegion, | |
89 | // The type where the anonymous lifetime appears | |
0731742a | 90 | // for e.g., Vec<`&u8`> and <`&u8`> |
dc9dc135 | 91 | found_type: Option<&'tcx hir::Ty>, |
94b46f34 | 92 | current_index: ty::DebruijnIndex, |
ff7c6d11 XL |
93 | } |
94 | ||
dc9dc135 XL |
95 | impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { |
96 | fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { | |
0731742a | 97 | NestedVisitorMap::OnlyBodies(&self.tcx.hir()) |
ff7c6d11 XL |
98 | } |
99 | ||
dc9dc135 | 100 | fn visit_ty(&mut self, arg: &'tcx hir::Ty) { |
e74abb32 | 101 | match arg.kind { |
8faf50e0 | 102 | hir::TyKind::BareFn(_) => { |
94b46f34 | 103 | self.current_index.shift_in(1); |
ff7c6d11 | 104 | intravisit::walk_ty(self, arg); |
94b46f34 | 105 | self.current_index.shift_out(1); |
ff7c6d11 XL |
106 | return; |
107 | } | |
108 | ||
8faf50e0 | 109 | hir::TyKind::TraitObject(ref bounds, _) => for bound in bounds { |
94b46f34 | 110 | self.current_index.shift_in(1); |
ff7c6d11 | 111 | self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); |
94b46f34 | 112 | self.current_index.shift_out(1); |
ff7c6d11 XL |
113 | }, |
114 | ||
8faf50e0 | 115 | hir::TyKind::Rptr(ref lifetime, _) => { |
ff7c6d11 | 116 | // the lifetime of the TyRptr |
9fa01778 | 117 | let hir_id = lifetime.hir_id; |
ff7c6d11 XL |
118 | match (self.tcx.named_region(hir_id), self.bound_region) { |
119 | // Find the index of the anonymous region that was part of the | |
120 | // error. We will then search the function parameters for a bound | |
121 | // region at the right depth with the same index | |
122 | ( | |
123 | Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), | |
124 | ty::BrAnon(br_index), | |
125 | ) => { | |
126 | debug!( | |
127 | "LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}", | |
94b46f34 | 128 | debruijn_index, |
ff7c6d11 XL |
129 | anon_index, |
130 | br_index | |
131 | ); | |
94b46f34 | 132 | if debruijn_index == self.current_index && anon_index == br_index { |
ff7c6d11 XL |
133 | self.found_type = Some(arg); |
134 | return; // we can stop visiting now | |
135 | } | |
136 | } | |
137 | ||
138 | // Find the index of the named region that was part of the | |
139 | // error. We will then search the function parameters for a bound | |
140 | // region at the right depth with the same index | |
141 | (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { | |
416331ca | 142 | debug!("EarlyBound id={:?} def_id={:?}", id, def_id); |
ff7c6d11 XL |
143 | if id == def_id { |
144 | self.found_type = Some(arg); | |
145 | return; // we can stop visiting now | |
146 | } | |
147 | } | |
148 | ||
149 | // Find the index of the named region that was part of the | |
150 | // error. We will then search the function parameters for a bound | |
151 | // region at the right depth with the same index | |
152 | ( | |
153 | Some(rl::Region::LateBound(debruijn_index, id, _)), | |
154 | ty::BrNamed(def_id, _), | |
155 | ) => { | |
156 | debug!( | |
157 | "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", | |
94b46f34 | 158 | debruijn_index |
ff7c6d11 | 159 | ); |
416331ca | 160 | debug!("LateBound id={:?} def_id={:?}", id, def_id); |
94b46f34 | 161 | if debruijn_index == self.current_index && id == def_id { |
ff7c6d11 XL |
162 | self.found_type = Some(arg); |
163 | return; // we can stop visiting now | |
164 | } | |
165 | } | |
166 | ||
167 | (Some(rl::Region::Static), _) | |
168 | | (Some(rl::Region::Free(_, _)), _) | |
169 | | (Some(rl::Region::EarlyBound(_, _, _)), _) | |
170 | | (Some(rl::Region::LateBound(_, _, _)), _) | |
171 | | (Some(rl::Region::LateBoundAnon(_, _)), _) | |
172 | | (None, _) => { | |
173 | debug!("no arg found"); | |
174 | } | |
175 | } | |
176 | } | |
8faf50e0 XL |
177 | // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct. |
178 | hir::TyKind::Path(_) => { | |
ff7c6d11 XL |
179 | let subvisitor = &mut TyPathVisitor { |
180 | tcx: self.tcx, | |
181 | found_it: false, | |
182 | bound_region: self.bound_region, | |
94b46f34 | 183 | current_index: self.current_index, |
ff7c6d11 XL |
184 | }; |
185 | intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty, | |
186 | // this will visit only outermost type | |
187 | if subvisitor.found_it { | |
188 | self.found_type = Some(arg); | |
189 | } | |
190 | } | |
191 | _ => {} | |
192 | } | |
193 | // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`, | |
194 | // go on to visit `&Foo` | |
195 | intravisit::walk_ty(self, arg); | |
196 | } | |
197 | } | |
198 | ||
199 | // The visitor captures the corresponding `hir::Ty` of the anonymous region | |
8faf50e0 | 200 | // in the case of structs ie. `hir::TyKind::Path`. |
ff7c6d11 XL |
201 | // This visitor would be invoked for each lifetime corresponding to a struct, |
202 | // and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR | |
203 | // where that lifetime appears. This allows us to highlight the | |
204 | // specific part of the type in the error message. | |
dc9dc135 XL |
205 | struct TyPathVisitor<'tcx> { |
206 | tcx: TyCtxt<'tcx>, | |
ff7c6d11 XL |
207 | found_it: bool, |
208 | bound_region: ty::BoundRegion, | |
94b46f34 | 209 | current_index: ty::DebruijnIndex, |
ff7c6d11 XL |
210 | } |
211 | ||
dc9dc135 XL |
212 | impl Visitor<'tcx> for TyPathVisitor<'tcx> { |
213 | fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { | |
0731742a | 214 | NestedVisitorMap::OnlyBodies(&self.tcx.hir()) |
ff7c6d11 XL |
215 | } |
216 | ||
217 | fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) { | |
9fa01778 | 218 | match (self.tcx.named_region(lifetime.hir_id), self.bound_region) { |
ff7c6d11 XL |
219 | // the lifetime of the TyPath! |
220 | (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => { | |
94b46f34 | 221 | if debruijn_index == self.current_index && anon_index == br_index { |
ff7c6d11 XL |
222 | self.found_it = true; |
223 | return; | |
224 | } | |
225 | } | |
226 | ||
227 | (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { | |
416331ca | 228 | debug!("EarlyBound id={:?} def_id={:?}", id, def_id); |
ff7c6d11 XL |
229 | if id == def_id { |
230 | self.found_it = true; | |
231 | return; // we can stop visiting now | |
232 | } | |
233 | } | |
234 | ||
235 | (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => { | |
236 | debug!( | |
237 | "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", | |
94b46f34 | 238 | debruijn_index, |
ff7c6d11 XL |
239 | ); |
240 | debug!("id={:?}", id); | |
241 | debug!("def_id={:?}", def_id); | |
94b46f34 | 242 | if debruijn_index == self.current_index && id == def_id { |
ff7c6d11 XL |
243 | self.found_it = true; |
244 | return; // we can stop visiting now | |
245 | } | |
246 | } | |
247 | ||
248 | (Some(rl::Region::Static), _) | |
249 | | (Some(rl::Region::EarlyBound(_, _, _)), _) | |
250 | | (Some(rl::Region::LateBound(_, _, _)), _) | |
251 | | (Some(rl::Region::LateBoundAnon(_, _)), _) | |
252 | | (Some(rl::Region::Free(_, _)), _) | |
253 | | (None, _) => { | |
254 | debug!("no arg found"); | |
255 | } | |
256 | } | |
257 | } | |
258 | ||
dc9dc135 | 259 | fn visit_ty(&mut self, arg: &'tcx hir::Ty) { |
ff7c6d11 XL |
260 | // ignore nested types |
261 | // | |
262 | // If you have a type like `Foo<'a, &Ty>` we | |
263 | // are only interested in the immediate lifetimes ('a). | |
264 | // | |
265 | // Making `visit_ty` empty will ignore the `&Ty` embedded | |
266 | // inside, it will get reached by the outer visitor. | |
267 | debug!("`Ty` corresponding to a struct is {:?}", arg); | |
268 | } | |
269 | } |