rustc_trait_selection/errors/
note_and_explain.rs1use rustc_errors::formatting::DiagMessageAddArg;
2use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic, msg};
3use rustc_hir::def_id::LocalDefId;
4use rustc_middle::bug;
5use rustc_middle::ty::{self, TyCtxt};
6use rustc_span::{Span, kw};
7
8use crate::error_reporting::infer::nice_region_error::find_anon_type;
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.kind() {
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.is_named() {
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(tcx)
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(def_id) => {
50 let name = tcx.item_name(def_id);
51 let span = if let Some(param) = tcx
52 .hir_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 ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected region for DescriptionCtx: {0:?}",
region));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, _: &mut Option<std::path::PathBuf>) -> 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, _: &mut Option<std::path::PathBuf>) -> 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<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
167 let msg = rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("{$pref_kind ->\n *[should_not_happen] [{$pref_kind}]\n [ref_valid_for] ...the reference is valid for\n [content_valid_for] ...but the borrowed content is only valid for\n [type_obj_valid_for] object type is valid for\n [source_pointer_valid_for] source pointer is only valid for\n [type_satisfy] type must satisfy\n [type_outlive] type must outlive\n [lf_param_instantiated_with] lifetime parameter instantiated with\n [lf_param_must_outlive] but lifetime parameter must outlive\n [lf_instantiated_with] lifetime instantiated with\n [lf_must_outlive] but lifetime must outlive\n [pointer_valid_for] the pointer is valid for\n [data_valid_for] but the referenced data is only valid for\n [empty] {\"\"}\n }{$pref_kind ->\n [empty] {\"\"}\n *[other] {\" \"}\n }{$desc_kind ->\n *[should_not_happen] [{$desc_kind}]\n [restatic] the static lifetime\n [revar] lifetime {$desc_arg}\n [as_defined] the lifetime `{$desc_arg}` as defined here\n [as_defined_anon] the anonymous lifetime as defined here\n [defined_here] the anonymous lifetime defined here\n [defined_here_reg] the lifetime `{$desc_arg}` as defined here\n }{$suff_kind ->\n *[should_not_happen] [{$suff_kind}]\n [empty]{\"\"}\n [continues] ...\n [req_by_binding] {\" \"}as required by this binding\n }"))msg!(
168 "{$pref_kind ->
169 *[should_not_happen] [{$pref_kind}]
170 [ref_valid_for] ...the reference is valid for
171 [content_valid_for] ...but the borrowed content is only valid for
172 [type_obj_valid_for] object type is valid for
173 [source_pointer_valid_for] source pointer is only valid for
174 [type_satisfy] type must satisfy
175 [type_outlive] type must outlive
176 [lf_param_instantiated_with] lifetime parameter instantiated with
177 [lf_param_must_outlive] but lifetime parameter must outlive
178 [lf_instantiated_with] lifetime instantiated with
179 [lf_must_outlive] but lifetime must outlive
180 [pointer_valid_for] the pointer is valid for
181 [data_valid_for] but the referenced data is only valid for
182 [empty] {\"\"}
183 }{$pref_kind ->
184 [empty] {\"\"}
185 *[other] {\" \"}
186 }{$desc_kind ->
187 *[should_not_happen] [{$desc_kind}]
188 [restatic] the static lifetime
189 [revar] lifetime {$desc_arg}
190 [as_defined] the lifetime `{$desc_arg}` as defined here
191 [as_defined_anon] the anonymous lifetime as defined here
192 [defined_here] the anonymous lifetime defined here
193 [defined_here_reg] the lifetime `{$desc_arg}` as defined here
194 }{$suff_kind ->
195 *[should_not_happen] [{$suff_kind}]
196 [empty]{\"\"}
197 [continues] ...
198 [req_by_binding] {\" \"}as required by this binding
199 }"
200 )
201 .arg("pref_kind", self.prefix)
202 .arg("suff_kind", self.suffix)
203 .arg("desc_kind", self.desc.kind)
204 .arg("desc_arg", self.desc.arg)
205 .format();
206
207 if let Some(span) = self.desc.span {
209 diag.span_note(span, msg);
210 } else {
211 diag.note(msg);
212 }
213 }
214}