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