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}