1 use crate::infer::error_reporting::nice_region_error::find_anon_type;
3 self, fluent, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage,
5 use rustc_middle::ty::{self, TyCtxt};
6 use rustc_span::{symbol::kw, Span};
9 struct DescriptionCtx<'a> {
16 impl<'a> DescriptionCtx<'a> {
19 region: ty::Region<'tcx>,
20 alt_span: Option<Span>,
22 let mut me = DescriptionCtx::default();
25 ty::ReEarlyBound(_) | ty::ReFree(_) => {
26 return Self::from_early_bound_and_free_regions(tcx, region);
32 ty::RePlaceholder(_) => return None,
34 // FIXME(#13998) RePlaceholder should probably print like
35 // ReFree rather than dumping Debug output on the user.
37 // We shouldn't really be having unification failures with ReVar
38 // and ReLateBound though.
39 ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
41 me.arg = format!("{:?}", region);
47 fn from_early_bound_and_free_regions<'tcx>(
49 region: ty::Region<'tcx>,
51 let mut me = DescriptionCtx::default();
52 let scope = region.free_region_binding_scope(tcx).expect_local();
54 ty::ReEarlyBound(ref br) => {
55 let mut sp = tcx.def_span(scope);
57 tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
62 me.kind = "as_defined";
63 me.arg = br.name.to_string();
65 me.kind = "as_defined_anon";
69 ty::ReFree(ref fr) => {
70 if !fr.bound_region.is_named()
71 && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
73 me.kind = "defined_here";
74 me.span = Some(ty.span);
76 match fr.bound_region {
77 ty::BoundRegionKind::BrNamed(_, name) => {
78 let mut sp = tcx.def_span(scope);
80 tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
84 if name == kw::UnderscoreLifetime {
85 me.kind = "as_defined_anon";
87 me.kind = "as_defined";
88 me.arg = name.to_string();
93 me.kind = "anon_num_here";
95 me.span = Some(tcx.def_span(scope));
98 me.kind = "defined_here_reg";
99 me.arg = region.to_string();
100 me.span = Some(tcx.def_span(scope));
110 fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
111 diag.set_arg("desc_kind", self.kind);
112 diag.set_arg("desc_arg", self.arg);
113 diag.set_arg("desc_num_arg", self.num_arg);
117 pub enum PrefixKind {
121 pub enum SuffixKind {
125 impl IntoDiagnosticArg for PrefixKind {
126 fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
127 let kind = match self {
128 Self::Empty => "empty",
131 rustc_errors::DiagnosticArgValue::Str(kind)
135 impl IntoDiagnosticArg for SuffixKind {
136 fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
137 let kind = match self {
138 Self::Continues => "continues",
141 rustc_errors::DiagnosticArgValue::Str(kind)
145 pub struct RegionExplanation<'a> {
146 desc: DescriptionCtx<'a>,
151 impl RegionExplanation<'_> {
154 region: ty::Region<'tcx>,
155 alt_span: Option<Span>,
159 Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
163 impl AddToDiagnostic for RegionExplanation<'_> {
164 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
166 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
168 if let Some(span) = self.desc.span {
169 diag.span_note(span, fluent::infer::region_explanation);
171 diag.note(fluent::infer::region_explanation);
173 self.desc.add_to(diag);
174 diag.set_arg("pref_kind", self.prefix);
175 diag.set_arg("suff_kind", self.suffix);