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