• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::fluent_generated as fluent;
2 use crate::infer::error_reporting::nice_region_error::find_anon_type;
3 use rustc_errors::{self, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage};
4 use rustc_middle::ty::{self, TyCtxt};
5 use rustc_span::{symbol::kw, Span};
6 
7 struct DescriptionCtx<'a> {
8     span: Option<Span>,
9     kind: &'a str,
10     arg: String,
11 }
12 
13 impl<'a> DescriptionCtx<'a> {
new<'tcx>( tcx: TyCtxt<'tcx>, region: ty::Region<'tcx>, alt_span: Option<Span>, ) -> Option<Self>14     fn new<'tcx>(
15         tcx: TyCtxt<'tcx>,
16         region: ty::Region<'tcx>,
17         alt_span: Option<Span>,
18     ) -> Option<Self> {
19         let (span, kind, arg) = match *region {
20             ty::ReEarlyBound(ref br) => {
21                 let scope = region.free_region_binding_scope(tcx).expect_local();
22                 let span = if let Some(param) =
23                     tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
24                 {
25                     param.span
26                 } else {
27                     tcx.def_span(scope)
28                 };
29                 if br.has_name() {
30                     (Some(span), "as_defined", br.name.to_string())
31                 } else {
32                     (Some(span), "as_defined_anon", String::new())
33                 }
34             }
35             ty::ReFree(ref fr) => {
36                 if !fr.bound_region.is_named()
37                     && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
38                 {
39                     (Some(ty.span), "defined_here", String::new())
40                 } else {
41                     let scope = region.free_region_binding_scope(tcx).expect_local();
42                     match fr.bound_region {
43                         ty::BoundRegionKind::BrNamed(_, name) => {
44                             let span = if let Some(param) = tcx
45                                 .hir()
46                                 .get_generics(scope)
47                                 .and_then(|generics| generics.get_named(name))
48                             {
49                                 param.span
50                             } else {
51                                 tcx.def_span(scope)
52                             };
53                             if name == kw::UnderscoreLifetime {
54                                 (Some(span), "as_defined_anon", String::new())
55                             } else {
56                                 (Some(span), "as_defined", name.to_string())
57                             }
58                         }
59                         ty::BrAnon(span) => {
60                             let span = match span {
61                                 Some(_) => span,
62                                 None => Some(tcx.def_span(scope)),
63                             };
64                             (span, "defined_here", String::new())
65                         }
66                         _ => {
67                             (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string())
68                         }
69                     }
70                 }
71             }
72 
73             ty::ReStatic => (alt_span, "restatic", String::new()),
74 
75             ty::RePlaceholder(_) | ty::ReError(_) => return None,
76 
77             // FIXME(#13998) RePlaceholder should probably print like
78             // ReFree rather than dumping Debug output on the user.
79             //
80             // We shouldn't really be having unification failures with ReVar
81             // and ReLateBound though.
82             ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
83                 (alt_span, "revar", format!("{:?}", region))
84             }
85         };
86         Some(DescriptionCtx { span, kind, arg })
87     }
88 }
89 
90 pub enum PrefixKind {
91     Empty,
92     RefValidFor,
93     ContentValidFor,
94     TypeObjValidFor,
95     SourcePointerValidFor,
96     TypeSatisfy,
97     TypeOutlive,
98     LfParamInstantiatedWith,
99     LfParamMustOutlive,
100     LfInstantiatedWith,
101     LfMustOutlive,
102     PointerValidFor,
103     DataValidFor,
104 }
105 
106 pub enum SuffixKind {
107     Empty,
108     Continues,
109     ReqByBinding,
110 }
111 
112 impl IntoDiagnosticArg for PrefixKind {
into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static>113     fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
114         let kind = match self {
115             Self::Empty => "empty",
116             Self::RefValidFor => "ref_valid_for",
117             Self::ContentValidFor => "content_valid_for",
118             Self::TypeObjValidFor => "type_obj_valid_for",
119             Self::SourcePointerValidFor => "source_pointer_valid_for",
120             Self::TypeSatisfy => "type_satisfy",
121             Self::TypeOutlive => "type_outlive",
122             Self::LfParamInstantiatedWith => "lf_param_instantiated_with",
123             Self::LfParamMustOutlive => "lf_param_must_outlive",
124             Self::LfInstantiatedWith => "lf_instantiated_with",
125             Self::LfMustOutlive => "lf_must_outlive",
126             Self::PointerValidFor => "pointer_valid_for",
127             Self::DataValidFor => "data_valid_for",
128         }
129         .into();
130         rustc_errors::DiagnosticArgValue::Str(kind)
131     }
132 }
133 
134 impl IntoDiagnosticArg for SuffixKind {
into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static>135     fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
136         let kind = match self {
137             Self::Empty => "empty",
138             Self::Continues => "continues",
139             Self::ReqByBinding => "req_by_binding",
140         }
141         .into();
142         rustc_errors::DiagnosticArgValue::Str(kind)
143     }
144 }
145 
146 pub struct RegionExplanation<'a> {
147     desc: DescriptionCtx<'a>,
148     prefix: PrefixKind,
149     suffix: SuffixKind,
150 }
151 
152 impl RegionExplanation<'_> {
new<'tcx>( tcx: TyCtxt<'tcx>, region: ty::Region<'tcx>, alt_span: Option<Span>, prefix: PrefixKind, suffix: SuffixKind, ) -> Option<Self>153     pub fn new<'tcx>(
154         tcx: TyCtxt<'tcx>,
155         region: ty::Region<'tcx>,
156         alt_span: Option<Span>,
157         prefix: PrefixKind,
158         suffix: SuffixKind,
159     ) -> Option<Self> {
160         Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
161     }
162 }
163 
164 impl AddToDiagnostic for RegionExplanation<'_> {
add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F) where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,165     fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
166     where
167         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
168     {
169         diag.set_arg("pref_kind", self.prefix);
170         diag.set_arg("suff_kind", self.suffix);
171         diag.set_arg("desc_kind", self.desc.kind);
172         diag.set_arg("desc_arg", self.desc.arg);
173 
174         let msg = f(diag, fluent::infer_region_explanation.into());
175         if let Some(span) = self.desc.span {
176             diag.span_note(span, msg);
177         } else {
178             diag.note(msg);
179         }
180     }
181 }
182