rustc_trait_selection/errors/
note_and_explain.rs1use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic, msg};
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 ->\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!(
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}