]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/error_reporting/util.rs
Auto merge of #43540 - petrochenkov:pathrelax, r=nikomatsakis
[rust.git] / src / librustc / infer / error_reporting / util.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Helper functions corresponding to lifetime errors due to
12 //! anonymous regions.
13 use hir;
14 use infer::InferCtxt;
15 use ty::{self, Region};
16 use hir::def_id::DefId;
17 use hir::map as hir_map;
18
19 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
20     // This method walks the Type of the function body arguments using
21     // `fold_regions()` function and returns the
22     // &hir::Arg of the function argument corresponding to the anonymous
23     // region and the Ty corresponding to the named region.
24     // Currently only the case where the function declaration consists of
25     // one named region and one anonymous region is handled.
26     // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
27     // Here, we would return the hir::Arg for y, we return the type &'a
28     // i32, which is the type of y but with the anonymous region replaced
29     // with 'a, the corresponding bound region and is_first which is true if
30     // the hir::Arg is the first argument in the function declaration.
31     pub fn find_arg_with_anonymous_region
32         (&self,
33          anon_region: Region<'tcx>,
34          replace_region: Region<'tcx>)
35          -> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion, bool)> {
36
37         if let ty::ReFree(ref free_region) = *anon_region {
38
39             let id = free_region.scope;
40             let hir = &self.tcx.hir;
41             if let Some(node_id) = hir.as_local_node_id(id) {
42                 if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
43                     let body = hir.body(body_id);
44                     if let Some(tables) = self.in_progress_tables {
45                         body.arguments
46                             .iter()
47                             .enumerate()
48                             .filter_map(|(index, arg)| {
49                                 let ty = tables.borrow().node_id_to_type(arg.hir_id);
50                                 let mut found_anon_region = false;
51                                 let new_arg_ty = self.tcx
52                                     .fold_regions(&ty, &mut false, |r, _| if *r == *anon_region {
53                                         found_anon_region = true;
54                                         replace_region
55                                     } else {
56                                         r
57                                     });
58                                 if found_anon_region {
59                                     let is_first = index == 0;
60                                     Some((arg, new_arg_ty, free_region.bound_region, is_first))
61                                 } else {
62                                     None
63                                 }
64                             })
65                             .next()
66                     } else {
67                         None
68                     }
69                 } else {
70                     None
71                 }
72             } else {
73                 None
74             }
75         } else {
76             None
77         }
78     }
79
80     // This method returns whether the given Region is Anonymous
81     // and returns the DefId and the BoundRegion corresponding to the given region.
82     pub fn is_suitable_anonymous_region(&self,
83                                         region: Region<'tcx>)
84                                         -> Option<(DefId, ty::BoundRegion)> {
85         if let ty::ReFree(ref free_region) = *region {
86             if let ty::BrAnon(..) = free_region.bound_region{
87                     let anonymous_region_binding_scope = free_region.scope;
88                     let node_id = self.tcx
89                         .hir
90                         .as_local_node_id(anonymous_region_binding_scope)
91                         .unwrap();
92                     match self.tcx.hir.find(node_id) {
93                         Some(hir_map::NodeItem(..)) |
94                         Some(hir_map::NodeTraitItem(..)) => {
95                             // Success -- proceed to return Some below
96                         }
97                         Some(hir_map::NodeImplItem(..)) => {
98                             let container_id = self.tcx
99                                 .associated_item(anonymous_region_binding_scope)
100                                 .container
101                                 .id();
102                             if self.tcx.impl_trait_ref(container_id).is_some() {
103                                 // For now, we do not try to target impls of traits. This is
104                                 // because this message is going to suggest that the user
105                                 // change the fn signature, but they may not be free to do so,
106                                 // since the signature must match the trait.
107                                 //
108                                 // FIXME(#42706) -- in some cases, we could do better here.
109                                 return None;
110                             }
111                         }
112                         _ => return None, // inapplicable
113                         // we target only top-level functions
114                     }
115                     return Some((anonymous_region_binding_scope, free_region.bound_region));
116                 }
117             }
118             None
119         }
120 }