]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
Use assert_eq! in copy_from_slice
[rust.git] / src / librustc / infer / error_reporting / nice_region_error / named_anon_conflict.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 //! 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> {
21         let (span, sub, sup) = self.get_regions();
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     }
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     }
134 }