]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs
Rename `Stmt.node` to `Stmt.kind`
[rust.git] / src / librustc / infer / error_reporting / nice_region_error / find_anon_type.rs
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;
7
8 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
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
23     /// for e.g., `&u8` and Vec<`&u8`.
24     pub(super) fn find_anon_type(
25         &self,
26         region: Region<'tcx>,
27         br: &ty::BoundRegion,
28     ) -> Option<(&hir::Ty, &hir::FnDecl)> {
29         if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
30             let def_id = anon_reg.def_id;
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) {
33                     Node::Item(&hir::Item {
34                         node: hir::ItemKind::Fn(ref fndecl, ..),
35                         ..
36                     }) => &fndecl,
37                     Node::TraitItem(&hir::TraitItem {
38                         kind: hir::TraitItemKind::Method(ref m, ..),
39                         ..
40                     })
41                     | Node::ImplItem(&hir::ImplItem {
42                         kind: hir::ImplItemKind::Method(ref m, ..),
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,
63         arg: &'tcx hir::Ty,
64         br: &ty::BoundRegion,
65     ) -> Option<(&'tcx hir::Ty)> {
66         let mut nested_visitor = FindNestedTypeVisitor {
67             tcx: self.tcx(),
68             bound_region: *br,
69             found_type: None,
70             current_index: ty::INNERMOST,
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.
84 struct FindNestedTypeVisitor<'tcx> {
85     tcx: TyCtxt<'tcx>,
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
90     // for e.g., Vec<`&u8`> and <`&u8`>
91     found_type: Option<&'tcx hir::Ty>,
92     current_index: ty::DebruijnIndex,
93 }
94
95 impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
96     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
97         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
98     }
99
100     fn visit_ty(&mut self, arg: &'tcx hir::Ty) {
101         match arg.kind {
102             hir::TyKind::BareFn(_) => {
103                 self.current_index.shift_in(1);
104                 intravisit::walk_ty(self, arg);
105                 self.current_index.shift_out(1);
106                 return;
107             }
108
109             hir::TyKind::TraitObject(ref bounds, _) => for bound in bounds {
110                 self.current_index.shift_in(1);
111                 self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
112                 self.current_index.shift_out(1);
113             },
114
115             hir::TyKind::Rptr(ref lifetime, _) => {
116                 // the lifetime of the TyRptr
117                 let hir_id = lifetime.hir_id;
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={:?}",
128                             debruijn_index,
129                             anon_index,
130                             br_index
131                         );
132                         if debruijn_index == self.current_index && anon_index == br_index {
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, _)) => {
142                         debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
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 = {:?}",
158                             debruijn_index
159                         );
160                         debug!("LateBound id={:?} def_id={:?}", id, def_id);
161                         if debruijn_index == self.current_index && id == def_id {
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             }
177             // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct.
178             hir::TyKind::Path(_) => {
179                 let subvisitor = &mut TyPathVisitor {
180                     tcx: self.tcx,
181                     found_it: false,
182                     bound_region: self.bound_region,
183                     current_index: self.current_index,
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
200 // in the case of structs ie. `hir::TyKind::Path`.
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.
205 struct TyPathVisitor<'tcx> {
206     tcx: TyCtxt<'tcx>,
207     found_it: bool,
208     bound_region: ty::BoundRegion,
209     current_index: ty::DebruijnIndex,
210 }
211
212 impl Visitor<'tcx> for TyPathVisitor<'tcx> {
213     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
214         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
215     }
216
217     fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
218         match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
219             // the lifetime of the TyPath!
220             (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => {
221                 if debruijn_index == self.current_index && anon_index == br_index {
222                     self.found_it = true;
223                     return;
224                 }
225             }
226
227             (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
228                 debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
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 = {:?}",
238                     debruijn_index,
239                 );
240                 debug!("id={:?}", id);
241                 debug!("def_id={:?}", def_id);
242                 if debruijn_index == self.current_index && id == def_id {
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
259     fn visit_ty(&mut self, arg: &'tcx hir::Ty) {
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 }