]> git.lizzy.rs Git - rust.git/blob - src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs
Rollup merge of #69929 - cuviper:unicode-13.0.0, r=Mark-Simulacrum
[rust.git] / src / librustc_infer / infer / error_reporting / nice_region_error / different_lifetimes.rs
1 //! Error Reporting for Anonymous Region Lifetime Errors
2 //! where both the regions are anonymous.
3
4 use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
5 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
6 use crate::infer::lexical_region_resolve::RegionResolutionError;
7 use crate::infer::SubregionOrigin;
8 use rustc::util::common::ErrorReported;
9
10 use rustc_errors::struct_span_err;
11
12 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
13     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
14     ///
15     /// Consider a case where we have
16     ///
17     /// ```no_run
18     /// fn foo(x: &mut Vec<&u8>, y: &u8) {
19     ///     x.push(y);
20     /// }
21     /// ```
22     ///
23     /// The example gives
24     ///
25     /// ```text
26     /// fn foo(x: &mut Vec<&u8>, y: &u8) {
27     ///                    ---      --- these references are declared with different lifetimes...
28     ///     x.push(y);
29     ///     ^ ...but data from `y` flows into `x` here
30     /// ```
31     ///
32     /// It has been extended for the case of structs too.
33     ///
34     /// Consider the example
35     ///
36     /// ```no_run
37     /// struct Ref<'a> { x: &'a u32 }
38     /// ```
39     ///
40     /// ```text
41     /// fn foo(mut x: Vec<Ref>, y: Ref) {
42     ///                   ---      --- these structs are declared with different lifetimes...
43     ///     x.push(y);
44     ///     ^ ...but data from `y` flows into `x` here
45     /// }
46     /// ```
47     ///
48     /// It will later be extended to trait objects.
49     pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
50         let (span, sub, sup) = self.regions()?;
51
52         if let Some(RegionResolutionError::ConcreteFailure(
53             SubregionOrigin::ReferenceOutlivesReferent(..),
54             ..,
55         )) = self.error
56         {
57             // This error doesn't make much sense in this case.
58             return None;
59         }
60
61         // Determine whether the sub and sup consist of both anonymous (elided) regions.
62         let anon_reg_sup = self.tcx().is_suitable_region(sup)?;
63
64         let anon_reg_sub = self.tcx().is_suitable_region(sub)?;
65         let scope_def_id_sup = anon_reg_sup.def_id;
66         let bregion_sup = anon_reg_sup.boundregion;
67         let scope_def_id_sub = anon_reg_sub.def_id;
68         let bregion_sub = anon_reg_sub.boundregion;
69
70         let ty_sup = self.find_anon_type(sup, &bregion_sup)?;
71
72         let ty_sub = self.find_anon_type(sub, &bregion_sub)?;
73
74         debug!(
75             "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}",
76             ty_sub, sup, bregion_sup
77         );
78         debug!(
79             "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}",
80             ty_sup, sub, bregion_sub
81         );
82
83         let (ty_sup, ty_fndecl_sup) = ty_sup;
84         let (ty_sub, ty_fndecl_sub) = ty_sub;
85
86         let AnonymousParamInfo { param: anon_param_sup, .. } =
87             self.find_param_with_region(sup, sup)?;
88         let AnonymousParamInfo { param: anon_param_sub, .. } =
89             self.find_param_with_region(sub, sub)?;
90
91         let sup_is_ret_type =
92             self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
93         let sub_is_ret_type =
94             self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
95
96         let span_label_var1 = match anon_param_sup.pat.simple_ident() {
97             Some(simple_ident) => format!(" from `{}`", simple_ident),
98             None => String::new(),
99         };
100
101         let span_label_var2 = match anon_param_sub.pat.simple_ident() {
102             Some(simple_ident) => format!(" into `{}`", simple_ident),
103             None => String::new(),
104         };
105
106         let (span_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) {
107             (None, None) => {
108                 let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id {
109                     (
110                         "this type is declared with multiple lifetimes...".to_owned(),
111                         "...but data with one lifetime flows into the other here".to_owned(),
112                     )
113                 } else {
114                     (
115                         "these two types are declared with different lifetimes...".to_owned(),
116                         format!("...but data{} flows{} here", span_label_var1, span_label_var2),
117                     )
118                 };
119                 (ty_sup.span, ty_sub.span, main_label_1, span_label_1)
120             }
121
122             (Some(ret_span), _) => (
123                 ty_sub.span,
124                 ret_span,
125                 "this parameter and the return type are declared \
126                  with different lifetimes..."
127                     .to_owned(),
128                 format!("...but data{} is returned here", span_label_var1),
129             ),
130             (_, Some(ret_span)) => (
131                 ty_sup.span,
132                 ret_span,
133                 "this parameter and the return type are declared \
134                  with different lifetimes..."
135                     .to_owned(),
136                 format!("...but data{} is returned here", span_label_var1),
137             ),
138         };
139
140         struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch")
141             .span_label(span_1, main_label)
142             .span_label(span_2, String::new())
143             .span_label(span, span_label)
144             .emit();
145         return Some(ErrorReported);
146     }
147 }