mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Mugrate mismatched_static_lifetime.rs
This commit is contained in:
parent
af3343ae29
commit
e0e9b21c78
@ -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
|
||||
|
@ -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>,
|
||||
}
|
||||
}
|
176
compiler/rustc_infer/src/errors/note_and_explain.rs
Normal file
176
compiler/rustc_infer/src/errors/note_and_explain.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user