]>
Commit | Line | Data |
---|---|---|
ff7c6d11 XL |
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 | //! Error Reporting for Anonymous Region Lifetime Errors | |
12 | //! where one region is named and the other is anonymous. | |
13 | use infer::error_reporting::nice_region_error::NiceRegionError; | |
14 | use ty; | |
15 | use util::common::ErrorReported; | |
16 | ||
17 | impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { | |
18 | /// When given a `ConcreteFailure` for a function with arguments containing a named region and | |
19 | /// an anonymous region, emit an descriptive diagnostic error. | |
20 | pub(super) fn try_report_named_anon_conflict(&self) -> Option<ErrorReported> { | |
2c00a5a8 | 21 | let (span, sub, sup) = self.get_regions(); |
ff7c6d11 XL |
22 | |
23 | debug!( | |
24 | "try_report_named_anon_conflict(sub={:?}, sup={:?})", | |
25 | sub, | |
26 | sup | |
27 | ); | |
28 | ||
29 | // Determine whether the sub and sup consist of one named region ('a) | |
30 | // and one anonymous (elided) region. If so, find the parameter arg | |
31 | // where the anonymous region appears (there must always be one; we | |
32 | // only introduced anonymous regions in parameters) as well as a | |
33 | // version new_ty of its type where the anonymous region is replaced | |
34 | // with the named one.//scope_def_id | |
35 | let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub) | |
36 | && self.is_suitable_region(sup).is_some() | |
37 | && self.find_arg_with_region(sup, sub).is_some() | |
38 | { | |
39 | ( | |
40 | sub, | |
41 | sup, | |
42 | self.find_arg_with_region(sup, sub).unwrap(), | |
43 | self.is_suitable_region(sup).unwrap(), | |
44 | ) | |
45 | } else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() | |
46 | && self.find_arg_with_region(sub, sup).is_some() | |
47 | { | |
48 | ( | |
49 | sup, | |
50 | sub, | |
51 | self.find_arg_with_region(sub, sup).unwrap(), | |
52 | self.is_suitable_region(sub).unwrap(), | |
53 | ) | |
54 | } else { | |
55 | return None; // inapplicable | |
56 | }; | |
57 | ||
58 | debug!("try_report_named_anon_conflict: named = {:?}", named); | |
59 | debug!( | |
60 | "try_report_named_anon_conflict: anon_arg_info = {:?}", | |
61 | anon_arg_info | |
62 | ); | |
63 | debug!( | |
64 | "try_report_named_anon_conflict: region_info = {:?}", | |
65 | region_info | |
66 | ); | |
67 | ||
68 | let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = ( | |
69 | anon_arg_info.arg, | |
70 | anon_arg_info.arg_ty, | |
71 | anon_arg_info.bound_region, | |
72 | anon_arg_info.is_first, | |
73 | region_info.def_id, | |
74 | region_info.is_impl_item, | |
75 | ); | |
76 | match br { | |
77 | ty::BrAnon(_) => {} | |
78 | _ => { | |
79 | /* not an anonymous region */ | |
80 | debug!("try_report_named_anon_conflict: not an anonymous region"); | |
81 | return None; | |
82 | } | |
83 | } | |
84 | ||
85 | if is_impl_item { | |
86 | debug!("try_report_named_anon_conflict: impl item, bail out"); | |
87 | return None; | |
88 | } | |
89 | ||
90 | if let Some((_, fndecl)) = self.find_anon_type(anon, &br) { | |
91 | if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() | |
92 | || self.is_self_anon(is_first, scope_def_id) | |
93 | { | |
94 | return None; | |
95 | } | |
96 | } | |
97 | ||
98 | let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() { | |
99 | ( | |
100 | format!("the type of `{}`", simple_name), | |
101 | format!("the type of `{}`", simple_name), | |
102 | ) | |
103 | } else { | |
104 | ("parameter type".to_owned(), "type".to_owned()) | |
105 | }; | |
106 | ||
107 | struct_span_err!( | |
108 | self.tcx.sess, | |
109 | span, | |
110 | E0621, | |
111 | "explicit lifetime required in {}", | |
112 | error_var | |
113 | ).span_label( | |
114 | arg.pat.span, | |
115 | format!("consider changing {} to `{}`", span_label_var, new_ty), | |
116 | ) | |
117 | .span_label(span, format!("lifetime `{}` required", named)) | |
118 | .emit(); | |
119 | return Some(ErrorReported); | |
120 | } | |
2c00a5a8 XL |
121 | |
122 | // This method returns whether the given Region is Named | |
123 | pub(super) fn is_named_region(&self, region: ty::Region<'tcx>) -> bool { | |
124 | match *region { | |
125 | ty::ReStatic => true, | |
126 | ty::ReFree(ref free_region) => match free_region.bound_region { | |
127 | ty::BrNamed(..) => true, | |
128 | _ => false, | |
129 | }, | |
130 | ty::ReEarlyBound(_) => true, | |
131 | _ => false, | |
132 | } | |
133 | } | |
ff7c6d11 | 134 | } |