diff options
| author | Michael Goulet <michael@errs.io> | 2024-07-21 15:20:41 -0400 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2024-07-21 22:34:35 -0400 |
| commit | ce8a625092fa48c2be475f659aa2a91b5591108f (patch) | |
| tree | 00970ec2be7f2197edb9a9ab419d5fe94eb266d6 /compiler/rustc_trait_selection/src/errors | |
| parent | f49738ba6c904b75de8b342d4a4fb9664819b2a1 (diff) | |
| download | rust-ce8a625092fa48c2be475f659aa2a91b5591108f.tar.gz rust-ce8a625092fa48c2be475f659aa2a91b5591108f.zip | |
Move all error reporting into rustc_trait_selection
Diffstat (limited to 'compiler/rustc_trait_selection/src/errors')
| -rw-r--r-- | compiler/rustc_trait_selection/src/errors/note_and_explain.rs | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs new file mode 100644 index 00000000000..1f18cd8c8d8 --- /dev/null +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -0,0 +1,183 @@ +use crate::error_reporting::infer::nice_region_error::find_anon_type; +use crate::fluent_generated as fluent; +use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic}; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::bug; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{symbol::kw, Span}; + +struct DescriptionCtx<'a> { + span: Option<Span>, + kind: &'a str, + arg: String, +} + +impl<'a> DescriptionCtx<'a> { + fn new<'tcx>( + tcx: TyCtxt<'tcx>, + generic_param_scope: LocalDefId, + region: ty::Region<'tcx>, + alt_span: Option<Span>, + ) -> Option<Self> { + let (span, kind, arg) = match *region { + ty::ReEarlyParam(br) => { + let scope = tcx + .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id) + .expect_local(); + let span = if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) + { + param.span + } else { + tcx.def_span(scope) + }; + if br.has_name() { + (Some(span), "as_defined", br.name.to_string()) + } else { + (Some(span), "as_defined_anon", String::new()) + } + } + ty::ReLateParam(ref fr) => { + if !fr.bound_region.is_named() + && let Some((ty, _)) = + find_anon_type(tcx, generic_param_scope, region, &fr.bound_region) + { + (Some(ty.span), "defined_here", String::new()) + } else { + let scope = fr.scope.expect_local(); + match fr.bound_region { + ty::BoundRegionKind::BrNamed(_, name) => { + let span = if let Some(param) = tcx + .hir() + .get_generics(scope) + .and_then(|generics| generics.get_named(name)) + { + param.span + } else { + tcx.def_span(scope) + }; + if name == kw::UnderscoreLifetime { + (Some(span), "as_defined_anon", String::new()) + } else { + (Some(span), "as_defined", name.to_string()) + } + } + ty::BrAnon => { + let span = Some(tcx.def_span(scope)); + (span, "defined_here", String::new()) + } + _ => (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()), + } + } + } + + ty::ReStatic => (alt_span, "restatic", String::new()), + + ty::RePlaceholder(_) | ty::ReError(_) => return None, + + ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => { + bug!("unexpected region for DescriptionCtx: {:?}", region); + } + }; + Some(DescriptionCtx { span, kind, arg }) + } +} + +pub enum PrefixKind { + Empty, + RefValidFor, + ContentValidFor, + TypeObjValidFor, + SourcePointerValidFor, + TypeSatisfy, + TypeOutlive, + LfParamInstantiatedWith, + LfParamMustOutlive, + LfInstantiatedWith, + LfMustOutlive, + PointerValidFor, + DataValidFor, +} + +pub enum SuffixKind { + Empty, + Continues, + ReqByBinding, +} + +impl IntoDiagArg for PrefixKind { + fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + let kind = match self { + Self::Empty => "empty", + Self::RefValidFor => "ref_valid_for", + Self::ContentValidFor => "content_valid_for", + Self::TypeObjValidFor => "type_obj_valid_for", + Self::SourcePointerValidFor => "source_pointer_valid_for", + Self::TypeSatisfy => "type_satisfy", + Self::TypeOutlive => "type_outlive", + Self::LfParamInstantiatedWith => "lf_param_instantiated_with", + Self::LfParamMustOutlive => "lf_param_must_outlive", + Self::LfInstantiatedWith => "lf_instantiated_with", + Self::LfMustOutlive => "lf_must_outlive", + Self::PointerValidFor => "pointer_valid_for", + Self::DataValidFor => "data_valid_for", + } + .into(); + rustc_errors::DiagArgValue::Str(kind) + } +} + +impl IntoDiagArg for SuffixKind { + fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + let kind = match self { + Self::Empty => "empty", + Self::Continues => "continues", + Self::ReqByBinding => "req_by_binding", + } + .into(); + rustc_errors::DiagArgValue::Str(kind) + } +} + +pub struct RegionExplanation<'a> { + desc: DescriptionCtx<'a>, + prefix: PrefixKind, + suffix: SuffixKind, +} + +impl RegionExplanation<'_> { + pub fn new<'tcx>( + tcx: TyCtxt<'tcx>, + generic_param_scope: LocalDefId, + region: ty::Region<'tcx>, + alt_span: Option<Span>, + prefix: PrefixKind, + suffix: SuffixKind, + ) -> Option<Self> { + Some(Self { + desc: DescriptionCtx::new(tcx, generic_param_scope, region, alt_span)?, + prefix, + suffix, + }) + } +} + +impl Subdiagnostic for RegionExplanation<'_> { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + diag.arg("pref_kind", self.prefix); + diag.arg("suff_kind", self.suffix); + diag.arg("desc_kind", self.desc.kind); + diag.arg("desc_arg", self.desc.arg); + + let msg = f(diag, fluent::trait_selection_region_explanation.into()); + if let Some(span) = self.desc.span { + diag.span_note(span, msg); + } else { + diag.note(msg); + } + } +} |
