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();
92 ty::BrAnon(idx, span) => {
93 me.kind = "anon_num_here";
95 me.span = match span {
97 None => Some(tcx.def_span(scope)),
101 me.kind = "defined_here_reg";
102 me.arg = region.to_string();
103 me.span = Some(tcx.def_span(scope));
113 fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
114 diag.set_arg("desc_kind", self.kind);
115 diag.set_arg("desc_arg", self.arg);
116 diag.set_arg("desc_num_arg", self.num_arg);
120 pub enum PrefixKind {
124 pub enum SuffixKind {
128 impl IntoDiagnosticArg for PrefixKind {
129 fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
130 let kind = match self {
131 Self::Empty => "empty",
134 rustc_errors::DiagnosticArgValue::Str(kind)
138 impl IntoDiagnosticArg for SuffixKind {
139 fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
140 let kind = match self {
141 Self::Continues => "continues",
144 rustc_errors::DiagnosticArgValue::Str(kind)
148 pub struct RegionExplanation<'a> {
149 desc: DescriptionCtx<'a>,
154 impl RegionExplanation<'_> {
157 region: ty::Region<'tcx>,
158 alt_span: Option<Span>,
162 Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
166 impl AddToDiagnostic for RegionExplanation<'_> {
167 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
169 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
171 if let Some(span) = self.desc.span {
172 diag.span_note(span, fluent::infer_region_explanation);
174 diag.note(fluent::infer_region_explanation);
176 self.desc.add_to(diag);
177 diag.set_arg("pref_kind", self.prefix);
178 diag.set_arg("suff_kind", self.suffix);