rustc_trait_selection/error_reporting/infer/nice_region_error/
named_anon_conflict.rs

1//! Error Reporting for Anonymous Region Lifetime Errors
2//! where one region is named and the other is anonymous.
3
4use rustc_errors::Diag;
5use tracing::debug;
6
7use crate::error_reporting::infer::nice_region_error::NiceRegionError;
8use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type;
9use crate::errors::ExplicitLifetimeRequired;
10
11impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
12    /// When given a `ConcreteFailure` for a function with parameters containing a named region and
13    /// an anonymous region, emit an descriptive diagnostic error.
14    pub(super) fn try_report_named_anon_conflict(&self) -> Option<Diag<'tcx>> {
15        let (span, sub, sup) = self.regions()?;
16
17        debug!(
18            "try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",
19            sub, sup, self.error,
20        );
21
22        // Determine whether the sub and sup consist of one named region ('a)
23        // and one anonymous (elided) region. If so, find the parameter arg
24        // where the anonymous region appears (there must always be one; we
25        // only introduced anonymous regions in parameters) as well as a
26        // version new_ty of its type where the anonymous region is replaced
27        // with the named one.
28        let (named, anon, anon_param_info, region_info) = if sub.is_named(self.tcx())
29            && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sup)
30            && let Some(anon_param_info) = self.find_param_with_region(sup, sub)
31        {
32            (sub, sup, anon_param_info, region_info)
33        } else if sup.is_named(self.tcx())
34            && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sub)
35            && let Some(anon_param_info) = self.find_param_with_region(sub, sup)
36        {
37            (sup, sub, anon_param_info, region_info)
38        } else {
39            return None; // inapplicable
40        };
41
42        // Suggesting to add a `'static` lifetime to a parameter is nearly always incorrect,
43        // and can steer users down the wrong path.
44        if named.is_static() {
45            return None;
46        }
47
48        debug!("try_report_named_anon_conflict: named = {:?}", named);
49        debug!("try_report_named_anon_conflict: anon_param_info = {:?}", anon_param_info);
50        debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);
51
52        let param = anon_param_info.param;
53        let new_ty = anon_param_info.param_ty;
54        let new_ty_span = anon_param_info.param_ty_span;
55        let is_first = anon_param_info.is_first;
56        let scope_def_id = region_info.scope;
57        let is_impl_item = region_info.is_impl_item;
58
59        if anon_param_info.kind.is_named(self.tcx()) {
60            /* not an anonymous region */
61            debug!("try_report_named_anon_conflict: not an anonymous region");
62            return None;
63        }
64
65        if is_impl_item {
66            debug!("try_report_named_anon_conflict: impl item, bail out");
67            return None;
68        }
69
70        if find_anon_type(self.tcx(), self.generic_param_scope, anon).is_some()
71            && self.is_self_anon(is_first, scope_def_id)
72        {
73            return None;
74        }
75        let named = named.to_string();
76        let err = match param.pat.simple_ident() {
77            Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
78                span,
79                simple_ident,
80                named,
81                new_ty_span,
82                new_ty,
83            },
84            None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
85        };
86        Some(self.tcx().sess.dcx().create_err(err))
87    }
88}