]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
rustc: async fn drop order lowering in HIR
[rust.git] / src / librustc / 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::NiceRegionError;
5 use crate::infer::error_reporting::nice_region_error::util::AnonymousArgInfo;
6 use crate::util::common::ErrorReported;
7
8 impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
9     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
10     ///
11     /// Consider a case where we have
12     ///
13     /// ```no_run
14     /// fn foo(x: &mut Vec<&u8>, y: &u8) {
15     ///     x.push(y);
16     /// }
17     /// ```
18     ///
19     /// The example gives
20     ///
21     /// ```text
22     /// fn foo(x: &mut Vec<&u8>, y: &u8) {
23     ///                    ---      --- these references are declared with different lifetimes...
24     ///     x.push(y);
25     ///     ^ ...but data from `y` flows into `x` here
26     /// ```
27     ///
28     /// It has been extended for the case of structs too.
29     ///
30     /// Consider the example
31     ///
32     /// ```no_run
33     /// struct Ref<'a> { x: &'a u32 }
34     /// ```
35     ///
36     /// ```text
37     /// fn foo(mut x: Vec<Ref>, y: Ref) {
38     ///                   ---      --- these structs are declared with different lifetimes...
39     ///     x.push(y);
40     ///     ^ ...but data from `y` flows into `x` here
41     /// }
42     /// ```
43     ///
44     /// It will later be extended to trait objects.
45     pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
46         let (span, sub, sup) = self.get_regions();
47
48         // Determine whether the sub and sup consist of both anonymous (elided) regions.
49         let anon_reg_sup = self.tcx().is_suitable_region(sup)?;
50
51         let anon_reg_sub = self.tcx().is_suitable_region(sub)?;
52         let scope_def_id_sup = anon_reg_sup.def_id;
53         let bregion_sup = anon_reg_sup.boundregion;
54         let scope_def_id_sub = anon_reg_sub.def_id;
55         let bregion_sub = anon_reg_sub.boundregion;
56
57         let ty_sup = self.find_anon_type(sup, &bregion_sup)?;
58
59         let ty_sub = self.find_anon_type(sub, &bregion_sub)?;
60
61         debug!(
62             "try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}",
63             ty_sub,
64             sup,
65             bregion_sup
66         );
67         debug!(
68             "try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}",
69             ty_sup,
70             sub,
71             bregion_sub
72         );
73
74         let (ty_sup, ty_fndecl_sup) = ty_sup;
75         let (ty_sub, ty_fndecl_sub) = ty_sub;
76
77         let AnonymousArgInfo {
78             arg: anon_arg_sup, ..
79         } = self.find_arg_with_region(sup, sup)?;
80         let AnonymousArgInfo {
81             arg: anon_arg_sub, ..
82         } = self.find_arg_with_region(sub, sub)?;
83
84         let sup_is_ret_type =
85             self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
86         let sub_is_ret_type =
87             self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
88
89         let arg_sup_pat = self.tcx().hir().original_pat_of_argument(anon_arg_sup);
90         let span_label_var1 = match arg_sup_pat.simple_ident() {
91             Some(simple_ident) => format!(" from `{}`", simple_ident),
92             None => String::new(),
93         };
94
95         let arg_sub_pat = self.tcx().hir().original_pat_of_argument(anon_arg_sub);
96         let span_label_var2 = match arg_sub_pat.simple_ident() {
97             Some(simple_ident) => format!(" into `{}`", simple_ident),
98             None => String::new(),
99         };
100
101         let (span_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) {
102             (None, None) => {
103                 let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id {
104                     (
105                         "this type is declared with multiple lifetimes...".to_owned(),
106                         "...but data with one lifetime flows into the other here".to_owned()
107                     )
108                 } else {
109                     (
110                         "these two types are declared with different lifetimes...".to_owned(),
111                         format!(
112                             "...but data{} flows{} here",
113                             span_label_var1,
114                             span_label_var2
115                         ),
116                     )
117                 };
118                 (ty_sup.span, ty_sub.span, main_label_1, span_label_1)
119             }
120
121             (Some(ret_span), _) => (
122                 ty_sub.span,
123                 ret_span,
124                 "this parameter and the return type are declared \
125                  with different lifetimes...".to_owned()
126                 ,
127                 format!("...but data{} is returned here", span_label_var1),
128             ),
129             (_, Some(ret_span)) => (
130                 ty_sup.span,
131                 ret_span,
132                 "this parameter and the return type are declared \
133                  with different lifetimes...".to_owned()
134                 ,
135                 format!("...but data{} is returned here", span_label_var1),
136             ),
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 }