Mugrate mismatched_static_lifetime.rs

This commit is contained in:
Nikita Tomashevich 2022-08-30 18:28:50 +03:00
parent af3343ae29
commit e0e9b21c78
No known key found for this signature in database
GPG Key ID: B29791D4D878E345
4 changed files with 303 additions and 20 deletions

View File

@ -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

View File

@ -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>,
}
}

View File

@ -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);
}
}

View File

@ -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)
}
}