]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
Rollup merge of #98368 - sunfishcode:sunfishcode/std-os-fd, r=joshtriplett
[rust.git] / compiler / rustc_infer / src / 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::errors::AddLifetimeParamsSuggestion;
5 use crate::errors::LifetimeMismatch;
6 use crate::errors::LifetimeMismatchLabels;
7 use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
8 use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
9 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
10 use crate::infer::lexical_region_resolve::RegionResolutionError;
11 use crate::infer::SubregionOrigin;
12 use crate::infer::TyCtxt;
13
14 use rustc_errors::AddToDiagnostic;
15 use rustc_errors::{Diagnostic, ErrorGuaranteed};
16 use rustc_hir::Ty;
17 use rustc_middle::ty::Region;
18
19 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
20     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
21     ///
22     /// Consider a case where we have
23     ///
24     /// ```compile_fail,E0623
25     /// fn foo(x: &mut Vec<&u8>, y: &u8) {
26     ///     x.push(y);
27     /// }
28     /// ```
29     ///
30     /// The example gives
31     ///
32     /// ```text
33     /// fn foo(x: &mut Vec<&u8>, y: &u8) {
34     ///                    ---      --- these references are declared with different lifetimes...
35     ///     x.push(y);
36     ///     ^ ...but data from `y` flows into `x` here
37     /// ```
38     ///
39     /// It has been extended for the case of structs too.
40     ///
41     /// Consider the example
42     ///
43     /// ```no_run
44     /// struct Ref<'a> { x: &'a u32 }
45     /// ```
46     ///
47     /// ```text
48     /// fn foo(mut x: Vec<Ref>, y: Ref) {
49     ///                   ---      --- these structs are declared with different lifetimes...
50     ///     x.push(y);
51     ///     ^ ...but data from `y` flows into `x` here
52     /// }
53     /// ```
54     ///
55     /// It will later be extended to trait objects.
56     pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorGuaranteed> {
57         let (span, sub, sup) = self.regions()?;
58
59         if let Some(RegionResolutionError::ConcreteFailure(
60             SubregionOrigin::ReferenceOutlivesReferent(..),
61             ..,
62         )) = self.error
63         {
64             // This error doesn't make much sense in this case.
65             return None;
66         }
67
68         // Determine whether the sub and sup consist of both anonymous (elided) regions.
69         let anon_reg_sup = self.tcx().is_suitable_region(sup)?;
70
71         let anon_reg_sub = self.tcx().is_suitable_region(sub)?;
72         let scope_def_id_sup = anon_reg_sup.def_id;
73         let bregion_sup = anon_reg_sup.boundregion;
74         let scope_def_id_sub = anon_reg_sub.def_id;
75         let bregion_sub = anon_reg_sub.boundregion;
76
77         let ty_sup = find_anon_type(self.tcx(), sup, &bregion_sup)?;
78
79         let ty_sub = find_anon_type(self.tcx(), sub, &bregion_sub)?;
80
81         debug!(
82             "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}",
83             ty_sub, sup, bregion_sup
84         );
85         debug!(
86             "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}",
87             ty_sup, sub, bregion_sub
88         );
89
90         let (ty_sup, ty_fndecl_sup) = ty_sup;
91         let (ty_sub, ty_fndecl_sub) = ty_sub;
92
93         let AnonymousParamInfo { param: anon_param_sup, .. } =
94             self.find_param_with_region(sup, sup)?;
95         let AnonymousParamInfo { param: anon_param_sub, .. } =
96             self.find_param_with_region(sub, sub)?;
97
98         let sup_is_ret_type =
99             self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
100         let sub_is_ret_type =
101             self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
102
103         debug!(
104             "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
105             sub_is_ret_type, sup_is_ret_type
106         );
107
108         let labels = match (sup_is_ret_type, sub_is_ret_type) {
109             (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
110                 let param_span =
111                     if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
112                 LifetimeMismatchLabels::InRet {
113                     param_span,
114                     ret_span,
115                     span,
116                     label_var1: anon_param_sup.pat.simple_ident(),
117                 }
118             }
119
120             (None, None) => LifetimeMismatchLabels::Normal {
121                 hir_equal: ty_sup.hir_id == ty_sub.hir_id,
122                 ty_sup: ty_sup.span,
123                 ty_sub: ty_sub.span,
124                 span,
125                 sup: anon_param_sup.pat.simple_ident(),
126                 sub: anon_param_sub.pat.simple_ident(),
127             },
128         };
129
130         let suggestion =
131             AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true };
132         let err = LifetimeMismatch { span, labels, suggestion };
133         let reported = self.tcx().sess.emit_err(err);
134         Some(reported)
135     }
136 }
137
138 /// Currently only used in rustc_borrowck, probably should be
139 /// removed in favour of public_errors::AddLifetimeParamsSuggestion
140 pub fn suggest_adding_lifetime_params<'tcx>(
141     tcx: TyCtxt<'tcx>,
142     sub: Region<'tcx>,
143     ty_sup: &'tcx Ty<'_>,
144     ty_sub: &'tcx Ty<'_>,
145     err: &mut Diagnostic,
146 ) {
147     let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false };
148     suggestion.add_to_diagnostic(err);
149 }