Skip to main content

rustc_trait_selection/errors/
note_and_explain.rs

1use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic, inline_fluent};
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;
8
9struct DescriptionCtx<'a> {
10    span: Option<Span>,
11    kind: &'a str,
12    arg: String,
13}
14
15impl<'a> DescriptionCtx<'a> {
16    fn new<'tcx>(
17        tcx: TyCtxt<'tcx>,
18        generic_param_scope: LocalDefId,
19        region: ty::Region<'tcx>,
20        alt_span: Option<Span>,
21    ) -> Option<Self> {
22        let (span, kind, arg) = match region.kind() {
23            ty::ReEarlyParam(br) => {
24                let scope = tcx
25                    .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
26                    .expect_local();
27                let span = if let Some(param) =
28                    tcx.hir_get_generics(scope).and_then(|generics| generics.get_named(br.name))
29                {
30                    param.span
31                } else {
32                    tcx.def_span(scope)
33                };
34                if br.is_named() {
35                    (Some(span), "as_defined", br.name.to_string())
36                } else {
37                    (Some(span), "as_defined_anon", String::new())
38                }
39            }
40            ty::ReLateParam(ref fr) => {
41                if !fr.kind.is_named(tcx)
42                    && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region)
43                {
44                    (Some(ty.span), "defined_here", String::new())
45                } else {
46                    let scope = fr.scope.expect_local();
47                    match fr.kind {
48                        ty::LateParamRegionKind::Named(def_id) => {
49                            let name = tcx.item_name(def_id);
50                            let span = if let Some(param) = tcx
51                                .hir_get_generics(scope)
52                                .and_then(|generics| generics.get_named(name))
53                            {
54                                param.span
55                            } else {
56                                tcx.def_span(scope)
57                            };
58                            if name == kw::UnderscoreLifetime {
59                                (Some(span), "as_defined_anon", String::new())
60                            } else {
61                                (Some(span), "as_defined", name.to_string())
62                            }
63                        }
64                        ty::LateParamRegionKind::Anon(_) => {
65                            let span = Some(tcx.def_span(scope));
66                            (span, "defined_here", String::new())
67                        }
68                        _ => (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()),
69                    }
70                }
71            }
72
73            ty::ReStatic => (alt_span, "restatic", String::new()),
74
75            ty::RePlaceholder(_) | ty::ReError(_) => return None,
76
77            ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => {
78                ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected region for DescriptionCtx: {0:?}",
        region));bug!("unexpected region for DescriptionCtx: {:?}", region);
79            }
80        };
81        Some(DescriptionCtx { span, kind, arg })
82    }
83}
84
85pub enum PrefixKind {
86    Empty,
87    RefValidFor,
88    ContentValidFor,
89    TypeObjValidFor,
90    SourcePointerValidFor,
91    TypeSatisfy,
92    TypeOutlive,
93    LfParamInstantiatedWith,
94    LfParamMustOutlive,
95    LfInstantiatedWith,
96    LfMustOutlive,
97    PointerValidFor,
98    DataValidFor,
99}
100
101pub enum SuffixKind {
102    Empty,
103    Continues,
104    ReqByBinding,
105}
106
107impl IntoDiagArg for PrefixKind {
108    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
109        let kind = match self {
110            Self::Empty => "empty",
111            Self::RefValidFor => "ref_valid_for",
112            Self::ContentValidFor => "content_valid_for",
113            Self::TypeObjValidFor => "type_obj_valid_for",
114            Self::SourcePointerValidFor => "source_pointer_valid_for",
115            Self::TypeSatisfy => "type_satisfy",
116            Self::TypeOutlive => "type_outlive",
117            Self::LfParamInstantiatedWith => "lf_param_instantiated_with",
118            Self::LfParamMustOutlive => "lf_param_must_outlive",
119            Self::LfInstantiatedWith => "lf_instantiated_with",
120            Self::LfMustOutlive => "lf_must_outlive",
121            Self::PointerValidFor => "pointer_valid_for",
122            Self::DataValidFor => "data_valid_for",
123        }
124        .into();
125        rustc_errors::DiagArgValue::Str(kind)
126    }
127}
128
129impl IntoDiagArg for SuffixKind {
130    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
131        let kind = match self {
132            Self::Empty => "empty",
133            Self::Continues => "continues",
134            Self::ReqByBinding => "req_by_binding",
135        }
136        .into();
137        rustc_errors::DiagArgValue::Str(kind)
138    }
139}
140
141pub struct RegionExplanation<'a> {
142    desc: DescriptionCtx<'a>,
143    prefix: PrefixKind,
144    suffix: SuffixKind,
145}
146
147impl RegionExplanation<'_> {
148    pub fn new<'tcx>(
149        tcx: TyCtxt<'tcx>,
150        generic_param_scope: LocalDefId,
151        region: ty::Region<'tcx>,
152        alt_span: Option<Span>,
153        prefix: PrefixKind,
154        suffix: SuffixKind,
155    ) -> Option<Self> {
156        Some(Self {
157            desc: DescriptionCtx::new(tcx, generic_param_scope, region, alt_span)?,
158            prefix,
159            suffix,
160        })
161    }
162}
163
164impl Subdiagnostic for RegionExplanation<'_> {
165    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
166        diag.store_args();
167        diag.arg("pref_kind", self.prefix);
168        diag.arg("suff_kind", self.suffix);
169        diag.arg("desc_kind", self.desc.kind);
170        diag.arg("desc_arg", self.desc.arg);
171
172        let msg = diag.eagerly_translate(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("{$pref_kind ->
*[should_not_happen] [{$pref_kind}]
[ref_valid_for] ...the reference is valid for
[content_valid_for] ...but the borrowed content is only valid for
[type_obj_valid_for] object type is valid for
[source_pointer_valid_for] source pointer is only valid for
[type_satisfy] type must satisfy
[type_outlive] type must outlive
[lf_param_instantiated_with] lifetime parameter instantiated with
[lf_param_must_outlive] but lifetime parameter must outlive
[lf_instantiated_with] lifetime instantiated with
[lf_must_outlive] but lifetime must outlive
[pointer_valid_for] the pointer is valid for
[data_valid_for] but the referenced data is only valid for
[empty] {\"\"}
}{$pref_kind ->
[empty] {\"\"}
*[other] {\" \"}
}{$desc_kind ->
*[should_not_happen] [{$desc_kind}]
[restatic] the static lifetime
[revar] lifetime {$desc_arg}
[as_defined] the lifetime `{$desc_arg}` as defined here
[as_defined_anon] the anonymous lifetime as defined here
[defined_here] the anonymous lifetime defined here
[defined_here_reg] the lifetime `{$desc_arg}` as defined here
}{$suff_kind ->
*[should_not_happen] [{$suff_kind}]
[empty]{\"\"}
[continues] ...
[req_by_binding] {\" \"}as required by this binding
}"))inline_fluent!(
173            "{$pref_kind ->
174*[should_not_happen] [{$pref_kind}]
175[ref_valid_for] ...the reference is valid for
176[content_valid_for] ...but the borrowed content is only valid for
177[type_obj_valid_for] object type is valid for
178[source_pointer_valid_for] source pointer is only valid for
179[type_satisfy] type must satisfy
180[type_outlive] type must outlive
181[lf_param_instantiated_with] lifetime parameter instantiated with
182[lf_param_must_outlive] but lifetime parameter must outlive
183[lf_instantiated_with] lifetime instantiated with
184[lf_must_outlive] but lifetime must outlive
185[pointer_valid_for] the pointer is valid for
186[data_valid_for] but the referenced data is only valid for
187[empty] {\"\"}
188}{$pref_kind ->
189[empty] {\"\"}
190*[other] {\" \"}
191}{$desc_kind ->
192*[should_not_happen] [{$desc_kind}]
193[restatic] the static lifetime
194[revar] lifetime {$desc_arg}
195[as_defined] the lifetime `{$desc_arg}` as defined here
196[as_defined_anon] the anonymous lifetime as defined here
197[defined_here] the anonymous lifetime defined here
198[defined_here_reg] the lifetime `{$desc_arg}` as defined here
199}{$suff_kind ->
200*[should_not_happen] [{$suff_kind}]
201[empty]{\"\"}
202[continues] ...
203[req_by_binding] {\" \"}as required by this binding
204}"
205        ));
206        diag.restore_args();
207        if let Some(span) = self.desc.span {
208            diag.span_note(span, msg);
209        } else {
210            diag.note(msg);
211        }
212    }
213}