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