rustc_trait_selection/errors/
note_and_explain.rs

1use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic};
2use rustc_hir::def_id::LocalDefId;
3use rustc_middle::bug;
4use rustc_middle::ty::{self, TyCtxt};
5use rustc_span::{Span, kw};
6
7use crate::error_reporting::infer::nice_region_error::find_anon_type;
8use crate::fluent_generated as fluent;
9
10struct DescriptionCtx<'a> {
11    span: Option<Span>,
12    kind: &'a str,
13    arg: String,
14}
15
16impl<'a> DescriptionCtx<'a> {
17    fn new<'tcx>(
18        tcx: TyCtxt<'tcx>,
19        generic_param_scope: LocalDefId,
20        region: ty::Region<'tcx>,
21        alt_span: Option<Span>,
22    ) -> Option<Self> {
23        let (span, kind, arg) = match *region {
24            ty::ReEarlyParam(br) => {
25                let scope = tcx
26                    .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
27                    .expect_local();
28                let span = if let Some(param) =
29                    tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
30                {
31                    param.span
32                } else {
33                    tcx.def_span(scope)
34                };
35                if br.has_name() {
36                    (Some(span), "as_defined", br.name.to_string())
37                } else {
38                    (Some(span), "as_defined_anon", String::new())
39                }
40            }
41            ty::ReLateParam(ref fr) => {
42                if !fr.kind.is_named()
43                    && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region)
44                {
45                    (Some(ty.span), "defined_here", String::new())
46                } else {
47                    let scope = fr.scope.expect_local();
48                    match fr.kind {
49                        ty::LateParamRegionKind::Named(_, name) => {
50                            let span = if let Some(param) = tcx
51                                .hir()
52                                .get_generics(scope)
53                                .and_then(|generics| generics.get_named(name))
54                            {
55                                param.span
56                            } else {
57                                tcx.def_span(scope)
58                            };
59                            if name == kw::UnderscoreLifetime {
60                                (Some(span), "as_defined_anon", String::new())
61                            } else {
62                                (Some(span), "as_defined", name.to_string())
63                            }
64                        }
65                        ty::LateParamRegionKind::Anon(_) => {
66                            let span = Some(tcx.def_span(scope));
67                            (span, "defined_here", String::new())
68                        }
69                        _ => (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()),
70                    }
71                }
72            }
73
74            ty::ReStatic => (alt_span, "restatic", String::new()),
75
76            ty::RePlaceholder(_) | ty::ReError(_) => return None,
77
78            ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => {
79                bug!("unexpected region for DescriptionCtx: {:?}", region);
80            }
81        };
82        Some(DescriptionCtx { span, kind, arg })
83    }
84}
85
86pub enum PrefixKind {
87    Empty,
88    RefValidFor,
89    ContentValidFor,
90    TypeObjValidFor,
91    SourcePointerValidFor,
92    TypeSatisfy,
93    TypeOutlive,
94    LfParamInstantiatedWith,
95    LfParamMustOutlive,
96    LfInstantiatedWith,
97    LfMustOutlive,
98    PointerValidFor,
99    DataValidFor,
100}
101
102pub enum SuffixKind {
103    Empty,
104    Continues,
105    ReqByBinding,
106}
107
108impl IntoDiagArg for PrefixKind {
109    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
110        let kind = match self {
111            Self::Empty => "empty",
112            Self::RefValidFor => "ref_valid_for",
113            Self::ContentValidFor => "content_valid_for",
114            Self::TypeObjValidFor => "type_obj_valid_for",
115            Self::SourcePointerValidFor => "source_pointer_valid_for",
116            Self::TypeSatisfy => "type_satisfy",
117            Self::TypeOutlive => "type_outlive",
118            Self::LfParamInstantiatedWith => "lf_param_instantiated_with",
119            Self::LfParamMustOutlive => "lf_param_must_outlive",
120            Self::LfInstantiatedWith => "lf_instantiated_with",
121            Self::LfMustOutlive => "lf_must_outlive",
122            Self::PointerValidFor => "pointer_valid_for",
123            Self::DataValidFor => "data_valid_for",
124        }
125        .into();
126        rustc_errors::DiagArgValue::Str(kind)
127    }
128}
129
130impl IntoDiagArg for SuffixKind {
131    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
132        let kind = match self {
133            Self::Empty => "empty",
134            Self::Continues => "continues",
135            Self::ReqByBinding => "req_by_binding",
136        }
137        .into();
138        rustc_errors::DiagArgValue::Str(kind)
139    }
140}
141
142pub struct RegionExplanation<'a> {
143    desc: DescriptionCtx<'a>,
144    prefix: PrefixKind,
145    suffix: SuffixKind,
146}
147
148impl RegionExplanation<'_> {
149    pub fn new<'tcx>(
150        tcx: TyCtxt<'tcx>,
151        generic_param_scope: LocalDefId,
152        region: ty::Region<'tcx>,
153        alt_span: Option<Span>,
154        prefix: PrefixKind,
155        suffix: SuffixKind,
156    ) -> Option<Self> {
157        Some(Self {
158            desc: DescriptionCtx::new(tcx, generic_param_scope, region, alt_span)?,
159            prefix,
160            suffix,
161        })
162    }
163}
164
165impl Subdiagnostic for RegionExplanation<'_> {
166    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
167        self,
168        diag: &mut Diag<'_, G>,
169        f: &F,
170    ) {
171        diag.arg("pref_kind", self.prefix);
172        diag.arg("suff_kind", self.suffix);
173        diag.arg("desc_kind", self.desc.kind);
174        diag.arg("desc_arg", self.desc.arg);
175
176        let msg = f(diag, fluent::trait_selection_region_explanation.into());
177        if let Some(span) = self.desc.span {
178            diag.span_note(span, msg);
179        } else {
180            diag.note(msg);
181        }
182    }
183}