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