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