1
Fork 0

Port OutlivesContent, OutlivesBound, FUllfillReqLifetime, LfBoundNotSatisfied diagnostics

This commit is contained in:
Nikita Tomashevich 2023-01-18 16:34:08 +03:00 committed by IQuant
parent 9bb6e60d1f
commit 8fc5ba65e1
4 changed files with 131 additions and 76 deletions

View file

@ -140,6 +140,14 @@ infer_lifetime_param_suggestion_elided = each elided lifetime in input position
infer_region_explanation = {$pref_kind -> infer_region_explanation = {$pref_kind ->
*[should_not_happen] [{$pref_kind}] *[should_not_happen] [{$pref_kind}]
[ref_valid_for] ...the reference is valid for
[content_valid_for] ...but the borrowed content is only valid for
[type_valid_for] object type is valid for
[source_pointer_valid_for] source pointer is only valid for
[type_satisfy] type must satisfy
[type_outlive] type must outlive
[lf_instantiated_with] lifetime parameter instantiated with
[lf_must_outlive] but lifetime parameter must outlive
[empty] {""} [empty] {""}
}{$pref_kind -> }{$pref_kind ->
[empty] {""} [empty] {""}
@ -158,8 +166,14 @@ infer_region_explanation = {$pref_kind ->
*[should_not_happen] [{$suff_kind}] *[should_not_happen] [{$suff_kind}]
[empty]{""} [empty]{""}
[continues] ... [continues] ...
[req_by_binding] {" "}as required by this binding
} }
infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
infer_fullfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
infer_lf_bound_not_satisfied = lifetime bound not satisfied
infer_mismatched_static_lifetime = incompatible lifetime on type infer_mismatched_static_lifetime = incompatible lifetime on type
infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement

View file

@ -933,3 +933,40 @@ pub struct ButNeedsToSatisfy {
pub has_lifetime: bool, pub has_lifetime: bool,
pub lifetime: String, pub lifetime: String,
} }
#[derive(Diagnostic)]
#[diag(infer_outlives_content, code = "E0312")]
pub struct OutlivesContent<'a> {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
}
#[derive(Diagnostic)]
#[diag(infer_outlives_bound, code = "E0476")]
pub struct OutlivesBound<'a> {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
}
#[derive(Diagnostic)]
#[diag(infer_fullfill_req_lifetime, code = "E0477")]
pub struct FullfillReqLifetime<'a> {
#[primary_span]
pub span: Span,
pub ty: Ty<'a>,
#[subdiagnostic]
pub note: Option<note_and_explain::RegionExplanation<'a>>,
}
#[derive(Diagnostic)]
#[diag(infer_lf_bound_not_satisfied, code = "E0478")]
pub struct LfBoundNotSatisfied<'a> {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
}

View file

@ -121,16 +121,34 @@ impl<'a> DescriptionCtx<'a> {
pub enum PrefixKind { pub enum PrefixKind {
Empty, Empty,
RefValidFor,
ContentValidFor,
TypeValidFor,
SourcePointerValidFor,
TypeSatisfy,
TypeOutlive,
LfInstantiatedWith,
LfMustOutlive,
} }
pub enum SuffixKind { pub enum SuffixKind {
Empty,
Continues, Continues,
ReqByBinding,
} }
impl IntoDiagnosticArg for PrefixKind { impl IntoDiagnosticArg for PrefixKind {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
let kind = match self { let kind = match self {
Self::Empty => "empty", Self::Empty => "empty",
Self::RefValidFor => "ref_valid_for",
Self::ContentValidFor => "content_valid_for",
Self::TypeValidFor => "type_valid_for",
Self::SourcePointerValidFor => "source_pointer_valid_for",
Self::TypeSatisfy => "type_satisfy",
Self::TypeOutlive => "type_outlive",
Self::LfInstantiatedWith => "lf_instantiated_with",
Self::LfMustOutlive => "lf_must_outlive",
} }
.into(); .into();
rustc_errors::DiagnosticArgValue::Str(kind) rustc_errors::DiagnosticArgValue::Str(kind)
@ -140,7 +158,9 @@ impl IntoDiagnosticArg for PrefixKind {
impl IntoDiagnosticArg for SuffixKind { impl IntoDiagnosticArg for SuffixKind {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
let kind = match self { let kind = match self {
Self::Empty => "empty",
Self::Continues => "continues", Self::Continues => "continues",
Self::ReqByBinding => "req_by_binding",
} }
.into(); .into();
rustc_errors::DiagnosticArgValue::Str(kind) rustc_errors::DiagnosticArgValue::Str(kind)
@ -166,17 +186,19 @@ impl RegionExplanation<'_> {
} }
impl AddToDiagnostic for RegionExplanation<'_> { impl AddToDiagnostic for RegionExplanation<'_> {
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
where where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{ {
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);
diag.set_arg("pref_kind", self.prefix); diag.set_arg("pref_kind", self.prefix);
diag.set_arg("suff_kind", self.suffix); diag.set_arg("suff_kind", self.suffix);
let desc_span = self.desc.span;
self.desc.add_to(diag);
let msg = f(diag, fluent::infer_region_explanation.into());
if let Some(span) = desc_span {
diag.span_note(span, msg);
} else {
diag.note(msg);
}
} }
} }

View file

@ -1,9 +1,12 @@
use crate::errors::RegionOriginNote; use crate::errors::{
note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
RegionOriginNote,
};
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
use crate::infer::{self, SubregionOrigin}; use crate::infer::{self, SubregionOrigin};
use rustc_errors::{ use rustc_errors::{
fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
ErrorGuaranteed, ErrorGuaranteed, IntoDiagnostic,
}; };
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::traits::ObligationCauseCode; use rustc_middle::traits::ObligationCauseCode;
@ -119,104 +122,83 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
err err
} }
infer::Reborrow(span) => { infer::Reborrow(span) => {
let mut err = struct_span_err!( let reference_valid = note_and_explain::RegionExplanation::new(
self.tcx.sess,
span,
E0312,
"lifetime of reference outlives lifetime of borrowed content..."
);
note_and_explain_region(
self.tcx, self.tcx,
&mut err,
"...the reference is valid for ",
sub, sub,
"...",
None, None,
note_and_explain::PrefixKind::RefValidFor,
note_and_explain::SuffixKind::Continues,
); );
note_and_explain_region( let content_valid = note_and_explain::RegionExplanation::new(
self.tcx, self.tcx,
&mut err,
"...but the borrowed content is only valid for ",
sup, sup,
"",
None, None,
note_and_explain::PrefixKind::ContentValidFor,
note_and_explain::SuffixKind::Empty,
); );
err OutlivesContent {
span,
notes: reference_valid.into_iter().chain(content_valid).collect(),
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
} }
infer::RelateObjectBound(span) => { infer::RelateObjectBound(span) => {
let mut err = struct_span_err!( let object_valid = note_and_explain::RegionExplanation::new(
self.tcx.sess,
span,
E0476,
"lifetime of the source pointer does not outlive lifetime bound of the \
object type"
);
note_and_explain_region(
self.tcx, self.tcx,
&mut err,
"object type is valid for ",
sub, sub,
"",
None, None,
note_and_explain::PrefixKind::TypeValidFor,
note_and_explain::SuffixKind::Empty,
); );
note_and_explain_region( let pointer_valid = note_and_explain::RegionExplanation::new(
self.tcx, self.tcx,
&mut err,
"source pointer is only valid for ",
sup, sup,
"",
None, None,
note_and_explain::PrefixKind::SourcePointerValidFor,
note_and_explain::SuffixKind::Empty,
); );
err OutlivesBound {
span,
notes: object_valid.into_iter().chain(pointer_valid).collect(),
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
} }
infer::RelateParamBound(span, ty, opt_span) => { infer::RelateParamBound(span, ty, opt_span) => {
let mut err = struct_span_err!( let prefix = match *sub {
self.tcx.sess, ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
span, _ => note_and_explain::PrefixKind::TypeOutlive,
E0477, };
"the type `{}` does not fulfill the required lifetime", let suffix = if opt_span.is_some() {
self.ty_to_string(ty) note_and_explain::SuffixKind::ReqByBinding
} else {
note_and_explain::SuffixKind::Empty
};
let note = note_and_explain::RegionExplanation::new(
self.tcx, sub, opt_span, prefix, suffix,
); );
match *sub { FullfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
ty::ReStatic => note_and_explain_region( .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
self.tcx,
&mut err,
"type must satisfy ",
sub,
if opt_span.is_some() { " as required by this binding" } else { "" },
opt_span,
),
_ => note_and_explain_region(
self.tcx,
&mut err,
"type must outlive ",
sub,
if opt_span.is_some() { " as required by this binding" } else { "" },
opt_span,
),
}
err
} }
infer::RelateRegionParamBound(span) => { infer::RelateRegionParamBound(span) => {
let mut err = let param_instantiated = note_and_explain::RegionExplanation::new(
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
note_and_explain_region(
self.tcx, self.tcx,
&mut err,
"lifetime parameter instantiated with ",
sup, sup,
"",
None, None,
note_and_explain::PrefixKind::LfInstantiatedWith,
note_and_explain::SuffixKind::Empty,
); );
note_and_explain_region( let param_must_outlive = note_and_explain::RegionExplanation::new(
self.tcx, self.tcx,
&mut err,
"but lifetime parameter must outlive ",
sub, sub,
"",
None, None,
note_and_explain::PrefixKind::LfMustOutlive,
note_and_explain::SuffixKind::Empty,
); );
err LfBoundNotSatisfied {
span,
notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
} }
infer::ReferenceOutlivesReferent(ty, span) => { infer::ReferenceOutlivesReferent(ty, span) => {
let mut err = struct_span_err!( let mut err = struct_span_err!(