diff options
| author | Nikita Tomashevich <quant3234@gmail.com> | 2022-08-30 18:28:50 +0300 |
|---|---|---|
| committer | Nikita Tomashevich <quant3234@gmail.com> | 2022-09-06 18:41:08 +0300 |
| commit | e0e9b21c78e4e6a7a5515944ace4cb0c1f2f9253 (patch) | |
| tree | b5c48ad2c67b6c4ee0078a6985190b0a3be17892 | |
| parent | af3343ae299c81a019d9d62d15c10cb99d7ceb89 (diff) | |
| download | rust-e0e9b21c78e4e6a7a5515944ace4cb0c1f2f9253.tar.gz rust-e0e9b21c78e4e6a7a5515944ace4cb0c1f2f9253.zip | |
Mugrate mismatched_static_lifetime.rs
| -rw-r--r-- | compiler/rustc_error_messages/locales/en-US/infer.ftl | 31 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/errors/mod.rs (renamed from compiler/rustc_infer/src/errors.rs) | 68 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/errors/note_and_explain.rs | 176 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs | 48 |
4 files changed, 303 insertions, 20 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 478a4bdf8a9..2899b8304bc 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -137,3 +137,34 @@ infer_lifetime_param_suggestion = consider introducing a named lifetime paramete *[false] {""} } infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime + +infer_region_explanation = {$pref_kind -> + *[should_not_happen] [{$pref_kind}] + [empty] {""} +}{$pref_kind -> + [empty] {""} + *[other] {" "} +}{$desc_kind -> + *[should_not_happen] [{$desc_kind}] + [restatic] the static lifetime + [reempty] the empty lifetime + [reemptyuni] the empty lifetime in universe {$desc_arg} + [revar] lifetime {$desc_arg} + + [as_defined] the lifetime `{$desc_arg}` as defined here + [as_defined_anon] the anonymous lifetime as defined here + [defined_here] the anonymous lifetime defined here + [anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here + [defined_here_reg] the lifetime `{$desc_arg}` as defined here +}{$suff_kind -> + *[should_not_happen] [{$suff_kind}] + [empty]{""} + [continues] ... +} + +infer_mismatched_static_lifetime = incompatible lifetime on type +infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +infer_msl_introduces_static = introduces a `'static` lifetime requirement +infer_msl_unmet_req = because this has an unmet lifetime requirement +infer_msl_trait_note = this has an implicit `'static` lifetime requirement +infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors/mod.rs index 932ba1f35af..ad8eb2945fa 100644 --- a/compiler/rustc_infer/src/errors.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -14,6 +14,8 @@ use crate::infer::error_reporting::{ ObligationCauseAsDiagArg, }; +pub mod note_and_explain; + #[derive(SessionDiagnostic)] #[diag(infer::opaque_hidden_type)] pub struct OpaqueHiddenTypeDiag { @@ -419,3 +421,69 @@ pub struct LifetimeMismatch<'a> { #[subdiagnostic] pub suggestion: AddLifetimeParamsSuggestion<'a>, } + +pub mod mismatched_static_lifetime { + use rustc_errors::{self, fluent, AddSubdiagnostic, MultiSpan}; + use rustc_span::Span; + + use super::note_and_explain; + + pub struct LabeledMultiSpan { + pub multi_span: MultiSpan, + pub binding_span: Span, + } + + impl AddSubdiagnostic for LabeledMultiSpan { + fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) { + self.multi_span + .push_span_label(self.binding_span, fluent::infer::msl_introduces_static); + diag.span_note(self.multi_span, fluent::infer::msl_unmet_req); + } + } + + pub struct ImplNote { + pub impl_span: Option<Span>, + } + + impl AddSubdiagnostic for ImplNote { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self.impl_span { + Some(span) => diag.span_note(span, fluent::infer::msl_impl_note), + None => diag.note(fluent::infer::msl_impl_note), + }; + } + } + + #[derive(SessionSubdiagnostic)] + pub enum TraitSubdiag { + #[note(infer::msl_trait_note)] + Note { + #[primary_span] + span: Span, + }, + #[suggestion_verbose( + infer::msl_trait_sugg, + code = " + '_", + applicability = "maybe-incorrect" + )] + Sugg { + #[primary_span] + span: Span, + }, + } + + #[derive(SessionDiagnostic)] + #[diag(infer::mismatched_static_lifetime)] + pub struct MismatchedStaticLifetime<'a> { + #[primary_span] + pub cause_span: Span, + #[subdiagnostic] + pub multispan_subdiag: LabeledMultiSpan, + #[subdiagnostic] + pub expl: Option<note_and_explain::RegionExplanation<'a>>, + #[subdiagnostic] + pub impl_note: ImplNote, + #[subdiagnostic] + pub trait_subdiags: Vec<TraitSubdiag>, + } +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs new file mode 100644 index 00000000000..92bf3ecd131 --- /dev/null +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -0,0 +1,176 @@ +use crate::infer::error_reporting::nice_region_error::find_anon_type; +use rustc_errors::{self, fluent, AddSubdiagnostic}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{symbol::kw, Span}; + +#[derive(Default)] +struct DescriptionCtx<'a> { + span: Option<Span>, + kind: &'a str, + arg: String, + num_arg: u32, +} + +impl<'a> DescriptionCtx<'a> { + fn new<'tcx>( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + alt_span: Option<Span>, + ) -> Option<Self> { + let mut me = DescriptionCtx::default(); + me.span = alt_span; + match *region { + ty::ReEarlyBound(_) | ty::ReFree(_) => { + return Self::from_early_bound_and_free_regions(tcx, region); + } + ty::ReStatic => { + me.kind = "restatic"; + } + + ty::ReEmpty(ty::UniverseIndex::ROOT) => me.kind = "reempty", + + // uh oh, hope no user ever sees THIS + ty::ReEmpty(ui) => { + me.kind = "reemptyuni"; + me.arg = format!("{:?}", ui); + } + + ty::RePlaceholder(_) => return None, + + // FIXME(#13998) RePlaceholder should probably print like + // ReFree rather than dumping Debug output on the user. + // + // We shouldn't really be having unification failures with ReVar + // and ReLateBound though. + ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { + me.kind = "revar"; + me.arg = format!("{:?}", region); + } + }; + Some(me) + } + + fn from_early_bound_and_free_regions<'tcx>( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + ) -> Option<Self> { + let mut me = DescriptionCtx::default(); + let scope = region.free_region_binding_scope(tcx).expect_local(); + match *region { + ty::ReEarlyBound(ref br) => { + let mut sp = tcx.def_span(scope); + if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) + { + sp = param.span; + } + if br.has_name() { + me.kind = "as_defined"; + me.arg = br.name.to_string(); + } else { + me.kind = "as_defined_anon"; + }; + me.span = Some(sp) + } + ty::ReFree(ref fr) => { + if !fr.bound_region.is_named() + && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) + { + me.kind = "defined_here"; + me.span = Some(ty.span); + } else { + match fr.bound_region { + ty::BoundRegionKind::BrNamed(_, name) => { + let mut sp = tcx.def_span(scope); + if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) + { + sp = param.span; + } + if name == kw::UnderscoreLifetime { + me.kind = "as_defined_anon"; + } else { + me.kind = "as_defined"; + me.arg = name.to_string(); + }; + me.span = Some(sp); + } + ty::BrAnon(idx) => { + me.kind = "anon_num_here"; + me.num_arg = idx+1; + me.span = Some(tcx.def_span(scope)); + }, + _ => { + me.kind = "defined_here_reg"; + me.arg = region.to_string(); + me.span = Some(tcx.def_span(scope)); + }, + } + } + } + _ => bug!(), + } + Some(me) + } + + fn add_to(self, diag: &mut rustc_errors::Diagnostic) { + diag.set_arg("desc_kind", self.kind); + diag.set_arg("desc_arg", self.arg); + diag.set_arg("desc_num_arg", self.num_arg); + } +} + +pub enum PrefixKind { + Empty, +} + +pub enum SuffixKind { + Continues, +} + +impl PrefixKind { + fn add_to(self, diag: &mut rustc_errors::Diagnostic) { + match self { + Self::Empty => diag.set_arg("pref_kind", "empty"), + }; + } +} + +impl SuffixKind { + fn add_to(self, diag: &mut rustc_errors::Diagnostic) { + match self { + Self::Continues => diag.set_arg("suff_kind", "continues"), + }; + } +} + +pub struct RegionExplanation<'a> { + desc: DescriptionCtx<'a>, + prefix: PrefixKind, + suffix: SuffixKind, +} + +impl RegionExplanation<'_> { + pub fn new<'tcx>( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + alt_span: Option<Span>, + prefix: PrefixKind, + suffix: SuffixKind, + ) -> Option<Self> { + Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix }) + } +} + +impl AddSubdiagnostic for RegionExplanation<'_> { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + if let Some(span) = self.desc.span { + diag.span_note(span, fluent::infer::region_explanation); + } else { + diag.note(fluent::infer::region_explanation); + } + self.desc.add_to(diag); + self.prefix.add_to(diag); + self.suffix.add_to(diag); + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index c20b96cae2e..832a0eaba3b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -1,13 +1,14 @@ //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate //! to hold. +use crate::errors::mismatched_static_lifetime::{ImplNote, MismatchedStaticLifetime, TraitSubdiag}; +use crate::errors::{mismatched_static_lifetime::LabeledMultiSpan, note_and_explain}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::error_reporting::note_and_explain_region; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::ObligationCauseCode; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_middle::ty::TypeVisitor; @@ -39,12 +40,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { = *parent.code() else { return None; }; - let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type"); + // FIXME: we should point at the lifetime - let mut multi_span: MultiSpan = vec![binding_span].into(); - multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement"); - err.span_note(multi_span, "because this has an unmet lifetime requirement"); - note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span)); + let multi_span: MultiSpan = vec![binding_span].into(); + let multispan_subdiag = LabeledMultiSpan { multi_span, binding_span }; + + let expl = note_and_explain::RegionExplanation::new( + self.tcx(), + sup, + Some(binding_span), + note_and_explain::PrefixKind::Empty, + note_and_explain::SuffixKind::Continues, + ); + let mut impl_span = None; + let mut trait_subdiags = Vec::new(); if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) { // If an impl is local, then maybe this isn't what they want. Try to // be as helpful as possible with implicit lifetimes. @@ -73,31 +82,30 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // there aren't trait objects or because none are implicit, then just // write a single note on the impl itself. - let impl_span = self.tcx().def_span(*impl_def_id); - err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); + impl_span = Some(self.tcx().def_span(*impl_def_id)); } else { // Otherwise, point at all implicit static lifetimes - err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); for span in &traits { - err.span_note(*span, "this has an implicit `'static` lifetime requirement"); + trait_subdiags.push(TraitSubdiag::Note { span: *span }); // It would be nice to put this immediately under the above note, but they get // pushed to the end. - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider relaxing the implicit `'static` requirement", - " + '_", - Applicability::MaybeIncorrect, - ); + trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() }); } } } else { // Otherwise just point out the impl. - let impl_span = self.tcx().def_span(*impl_def_id); - err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); + impl_span = Some(self.tcx().def_span(*impl_def_id)); } - let reported = err.emit(); + let err = MismatchedStaticLifetime { + cause_span: cause.span, + multispan_subdiag, + expl, + impl_note: ImplNote { impl_span }, + trait_subdiags, + }; + let reported = self.tcx().sess.emit_err(err); Some(reported) } } |
