]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs
forward read_c_str method from Memory to Alloc
[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                         node: hir::TraitItemKind::Method(ref m, ..),
39                         ..
40                     })
41                     | Node::ImplItem(&hir::ImplItem {
42                         node: 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.node {
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!(
143                             "EarlyBound self.infcx.tcx.hir().local_def_id(id)={:?} \
144                              def_id={:?}",
145                             id,
146                             def_id
147                         );
148                         if id == def_id {
149                             self.found_type = Some(arg);
150                             return; // we can stop visiting now
151                         }
152                     }
153
154                     // Find the index of the named region that was part of the
155                     // error. We will then search the function parameters for a bound
156                     // region at the right depth with the same index
157                     (
158                         Some(rl::Region::LateBound(debruijn_index, id, _)),
159                         ty::BrNamed(def_id, _),
160                     ) => {
161                         debug!(
162                             "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
163                             debruijn_index
164                         );
165                         debug!("self.infcx.tcx.hir().local_def_id(id)={:?}", id);
166                         debug!("def_id={:?}", def_id);
167                         if debruijn_index == self.current_index && id == def_id {
168                             self.found_type = Some(arg);
169                             return; // we can stop visiting now
170                         }
171                     }
172
173                     (Some(rl::Region::Static), _)
174                     | (Some(rl::Region::Free(_, _)), _)
175                     | (Some(rl::Region::EarlyBound(_, _, _)), _)
176                     | (Some(rl::Region::LateBound(_, _, _)), _)
177                     | (Some(rl::Region::LateBoundAnon(_, _)), _)
178                     | (None, _) => {
179                         debug!("no arg found");
180                     }
181                 }
182             }
183             // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct.
184             hir::TyKind::Path(_) => {
185                 let subvisitor = &mut TyPathVisitor {
186                     tcx: self.tcx,
187                     found_it: false,
188                     bound_region: self.bound_region,
189                     current_index: self.current_index,
190                 };
191                 intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
192                                                       // this will visit only outermost type
193                 if subvisitor.found_it {
194                     self.found_type = Some(arg);
195                 }
196             }
197             _ => {}
198         }
199         // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
200         // go on to visit `&Foo`
201         intravisit::walk_ty(self, arg);
202     }
203 }
204
205 // The visitor captures the corresponding `hir::Ty` of the anonymous region
206 // in the case of structs ie. `hir::TyKind::Path`.
207 // This visitor would be invoked for each lifetime corresponding to a struct,
208 // and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
209 // where that lifetime appears. This allows us to highlight the
210 // specific part of the type in the error message.
211 struct TyPathVisitor<'tcx> {
212     tcx: TyCtxt<'tcx>,
213     found_it: bool,
214     bound_region: ty::BoundRegion,
215     current_index: ty::DebruijnIndex,
216 }
217
218 impl Visitor<'tcx> for TyPathVisitor<'tcx> {
219     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
220         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
221     }
222
223     fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
224         match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
225             // the lifetime of the TyPath!
226             (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => {
227                 if debruijn_index == self.current_index && anon_index == br_index {
228                     self.found_it = true;
229                     return;
230                 }
231             }
232
233             (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
234                 debug!(
235                     "EarlyBound self.infcx.tcx.hir().local_def_id(id)={:?} \
236                      def_id={:?}",
237                     id,
238                     def_id
239                 );
240                 if id == def_id {
241                     self.found_it = true;
242                     return; // we can stop visiting now
243                 }
244             }
245
246             (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => {
247                 debug!(
248                     "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
249                     debruijn_index,
250                 );
251                 debug!("id={:?}", id);
252                 debug!("def_id={:?}", def_id);
253                 if debruijn_index == self.current_index && id == def_id {
254                     self.found_it = true;
255                     return; // we can stop visiting now
256                 }
257             }
258
259             (Some(rl::Region::Static), _)
260             | (Some(rl::Region::EarlyBound(_, _, _)), _)
261             | (Some(rl::Region::LateBound(_, _, _)), _)
262             | (Some(rl::Region::LateBoundAnon(_, _)), _)
263             | (Some(rl::Region::Free(_, _)), _)
264             | (None, _) => {
265                 debug!("no arg found");
266             }
267         }
268     }
269
270     fn visit_ty(&mut self, arg: &'tcx hir::Ty) {
271         // ignore nested types
272         //
273         // If you have a type like `Foo<'a, &Ty>` we
274         // are only interested in the immediate lifetimes ('a).
275         //
276         // Making `visit_ty` empty will ignore the `&Ty` embedded
277         // inside, it will get reached by the outer visitor.
278         debug!("`Ty` corresponding to a struct is {:?}", arg);
279     }
280 }