rustc_trait_selection/error_reporting/infer/nice_region_error/
different_lifetimes.rs

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