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