1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//! Error Reporting for Anonymous Region Lifetime Errors
//! where one region is named and the other is anonymous.
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::{
    errors::ExplicitLifetimeRequired,
    infer::error_reporting::nice_region_error::find_anon_type::find_anon_type,
};
use rustc_errors::Diag;
use rustc_middle::ty;
use rustc_span::symbol::kw;

impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
    /// When given a `ConcreteFailure` for a function with parameters containing a named region and
    /// an anonymous region, emit an descriptive diagnostic error.
    pub(super) fn try_report_named_anon_conflict(&self) -> Option<Diag<'tcx>> {
        let (span, sub, sup) = self.regions()?;

        debug!(
            "try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",
            sub, sup, self.error,
        );

        // Determine whether the sub and sup consist of one named region ('a)
        // and one anonymous (elided) region. If so, find the parameter arg
        // where the anonymous region appears (there must always be one; we
        // only introduced anonymous regions in parameters) as well as a
        // version new_ty of its type where the anonymous region is replaced
        // with the named one.
        let (named, anon, anon_param_info, region_info) = if sub.has_name()
            && let Some(region_info) = self.tcx().is_suitable_region(sup)
            && let Some(anon_param_info) = self.find_param_with_region(sup, sub)
        {
            (sub, sup, anon_param_info, region_info)
        } else if sup.has_name()
            && let Some(region_info) = self.tcx().is_suitable_region(sub)
            && let Some(anon_param_info) = self.find_param_with_region(sub, sup)
        {
            (sup, sub, anon_param_info, region_info)
        } else {
            return None; // inapplicable
        };

        // Suggesting to add a `'static` lifetime to a parameter is nearly always incorrect,
        // and can steer users down the wrong path.
        if named.is_static() {
            return None;
        }

        debug!("try_report_named_anon_conflict: named = {:?}", named);
        debug!("try_report_named_anon_conflict: anon_param_info = {:?}", anon_param_info);
        debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);

        let param = anon_param_info.param;
        let new_ty = anon_param_info.param_ty;
        let new_ty_span = anon_param_info.param_ty_span;
        let br = anon_param_info.bound_region;
        let is_first = anon_param_info.is_first;
        let scope_def_id = region_info.def_id;
        let is_impl_item = region_info.is_impl_item;

        match br {
            ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon => {}
            _ => {
                /* not an anonymous region */
                debug!("try_report_named_anon_conflict: not an anonymous region");
                return None;
            }
        }

        if is_impl_item {
            debug!("try_report_named_anon_conflict: impl item, bail out");
            return None;
        }

        if find_anon_type(self.tcx(), anon, &br).is_some()
            && self.is_self_anon(is_first, scope_def_id)
        {
            return None;
        }
        let named = named.to_string();
        let err = match param.pat.simple_ident() {
            Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
                span,
                simple_ident,
                named,
                new_ty_span,
                new_ty,
            },
            None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
        };
        Some(self.tcx().sess.dcx().create_err(err))
    }
}