mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 00:03:43 +00:00
Rollup merge of #107034 - IntQuant:issue-100717-infer-5, r=oli-obk
Migrating rustc_infer to session diagnostics (part 4) `@rustbot` label +A-translation r? rust-lang/diagnostics cc https://github.com/rust-lang/rust/issues/100717
This commit is contained in:
commit
1fdf0e1334
@ -140,6 +140,18 @@ infer_lifetime_param_suggestion_elided = each elided lifetime in input position
|
||||
|
||||
infer_region_explanation = {$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_obj_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_param_instantiated_with] lifetime parameter instantiated with
|
||||
[lf_param_must_outlive] but lifetime parameter must outlive
|
||||
[lf_instantiated_with] lifetime instantiated with
|
||||
[lf_must_outlive] but lifetime must outlive
|
||||
[pointer_valid_for] the pointer is valid for
|
||||
[data_valid_for] but the referenced data is only valid for
|
||||
[empty] {""}
|
||||
}{$pref_kind ->
|
||||
[empty] {""}
|
||||
@ -148,7 +160,6 @@ infer_region_explanation = {$pref_kind ->
|
||||
*[should_not_happen] [{$desc_kind}]
|
||||
[restatic] the static lifetime
|
||||
[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
|
||||
@ -158,8 +169,16 @@ infer_region_explanation = {$pref_kind ->
|
||||
*[should_not_happen] [{$suff_kind}]
|
||||
[empty]{""}
|
||||
[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_borrowed_too_long = a value of type `{$ty}` is borrowed for too long
|
||||
infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
|
||||
|
||||
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_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
|
||||
@ -308,3 +327,21 @@ infer_ril_introduced_here = `'static` requirement introduced here
|
||||
infer_ril_introduced_by = requirement introduced by this return type
|
||||
infer_ril_because_of = because of this returned expression
|
||||
infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
|
||||
|
||||
infer_where_remove = remove the `where` clause
|
||||
infer_where_copy_predicates = copy the `where` clause predicates from the trait
|
||||
|
||||
infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions
|
||||
infer_srs_remove = consider removing this semicolon
|
||||
infer_srs_add = consider returning the local binding `{$ident}`
|
||||
infer_srs_add_one = consider returning one of these bindings
|
||||
|
||||
infer_await_both_futures = consider `await`ing on both `Future`s
|
||||
infer_await_future = consider `await`ing on the `Future`
|
||||
infer_await_note = calling an async function returns a future
|
||||
|
||||
infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
|
||||
infer_prlf_defined_without_sub = the lifetime defined here...
|
||||
infer_prlf_must_oultive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
|
||||
infer_prlf_must_oultive_without_sup = ...must outlive the lifetime defined here
|
||||
infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
|
||||
|
@ -933,3 +933,216 @@ pub struct ButNeedsToSatisfy {
|
||||
pub has_lifetime: bool,
|
||||
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>>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(infer_ref_longer_than_data, code = "E0491")]
|
||||
pub struct RefLongerThanData<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
#[subdiagnostic]
|
||||
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum WhereClauseSuggestions {
|
||||
#[suggestion(
|
||||
infer_where_remove,
|
||||
code = "",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
Remove {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_where_copy_predicates,
|
||||
code = "{space}where {trait_predicates}",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
CopyPredicates {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
space: &'static str,
|
||||
trait_predicates: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum SuggestRemoveSemiOrReturnBinding {
|
||||
#[multipart_suggestion(infer_srs_remove_and_box, applicability = "machine-applicable")]
|
||||
RemoveAndBox {
|
||||
#[suggestion_part(code = "Box::new(")]
|
||||
first_lo: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
first_hi: Span,
|
||||
#[suggestion_part(code = "Box::new(")]
|
||||
second_lo: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
second_hi: Span,
|
||||
#[suggestion_part(code = "")]
|
||||
sp: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_srs_remove,
|
||||
style = "short",
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
Remove {
|
||||
#[primary_span]
|
||||
sp: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_srs_add,
|
||||
style = "verbose",
|
||||
code = "{code}",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Add {
|
||||
#[primary_span]
|
||||
sp: Span,
|
||||
code: String,
|
||||
ident: Ident,
|
||||
},
|
||||
#[note(infer_srs_add_one)]
|
||||
AddOne {
|
||||
#[primary_span]
|
||||
spans: MultiSpan,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum ConsiderAddingAwait {
|
||||
#[help(infer_await_both_futures)]
|
||||
BothFuturesHelp,
|
||||
#[multipart_suggestion(infer_await_both_futures, applicability = "maybe-incorrect")]
|
||||
BothFuturesSugg {
|
||||
#[suggestion_part(code = ".await")]
|
||||
first: Span,
|
||||
#[suggestion_part(code = ".await")]
|
||||
second: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_await_future,
|
||||
code = ".await",
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
FutureSugg {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(infer_await_note)]
|
||||
FutureSuggNote {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[multipart_suggestion(
|
||||
infer_await_future,
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
FutureSuggMultiple {
|
||||
#[suggestion_part(code = ".await")]
|
||||
spans: Vec<Span>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub enum PlaceholderRelationLfNotSatisfied {
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
HasBoth {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_defined_with_sub)]
|
||||
sub_span: Span,
|
||||
#[note(infer_prlf_must_oultive_with_sup)]
|
||||
sup_span: Span,
|
||||
sub_symbol: Symbol,
|
||||
sup_symbol: Symbol,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
HasSub {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_defined_with_sub)]
|
||||
sub_span: Span,
|
||||
#[note(infer_prlf_must_oultive_without_sup)]
|
||||
sup_span: Span,
|
||||
sub_symbol: Symbol,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
HasSup {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_defined_without_sub)]
|
||||
sub_span: Span,
|
||||
#[note(infer_prlf_must_oultive_with_sup)]
|
||||
sup_span: Span,
|
||||
sup_symbol: Symbol,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
HasNone {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_defined_without_sub)]
|
||||
sub_span: Span,
|
||||
#[note(infer_prlf_must_oultive_without_sup)]
|
||||
sup_span: Span,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
OnlyPrimarySpan {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
}
|
||||
|
@ -121,16 +121,42 @@ impl<'a> DescriptionCtx<'a> {
|
||||
|
||||
pub enum PrefixKind {
|
||||
Empty,
|
||||
RefValidFor,
|
||||
ContentValidFor,
|
||||
TypeObjValidFor,
|
||||
SourcePointerValidFor,
|
||||
TypeSatisfy,
|
||||
TypeOutlive,
|
||||
LfParamInstantiatedWith,
|
||||
LfParamMustOutlive,
|
||||
LfInstantiatedWith,
|
||||
LfMustOutlive,
|
||||
PointerValidFor,
|
||||
DataValidFor,
|
||||
}
|
||||
|
||||
pub enum SuffixKind {
|
||||
Empty,
|
||||
Continues,
|
||||
ReqByBinding,
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for PrefixKind {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
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::DiagnosticArgValue::Str(kind)
|
||||
@ -140,7 +166,9 @@ impl IntoDiagnosticArg for PrefixKind {
|
||||
impl IntoDiagnosticArg for SuffixKind {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
let kind = match self {
|
||||
Self::Empty => "empty",
|
||||
Self::Continues => "continues",
|
||||
Self::ReqByBinding => "req_by_binding",
|
||||
}
|
||||
.into();
|
||||
rustc_errors::DiagnosticArgValue::Str(kind)
|
||||
@ -166,17 +194,19 @@ impl 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
|
||||
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("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -751,15 +751,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
};
|
||||
let msg = "`match` arms have incompatible types";
|
||||
err.span_label(outer, msg);
|
||||
self.suggest_remove_semi_or_return_binding(
|
||||
err,
|
||||
if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
|
||||
prior_arm_block_id,
|
||||
prior_arm_ty,
|
||||
prior_arm_span,
|
||||
arm_block_id,
|
||||
arm_ty,
|
||||
arm_span,
|
||||
);
|
||||
) {
|
||||
err.subdiagnostic(subdiag);
|
||||
}
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
// Get return type span and point to it.
|
||||
self.suggest_boxing_for_return_impl_trait(
|
||||
@ -784,15 +785,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
if let Some(sp) = outer_span {
|
||||
err.span_label(sp, "`if` and `else` have incompatible types");
|
||||
}
|
||||
self.suggest_remove_semi_or_return_binding(
|
||||
err,
|
||||
if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
|
||||
Some(then_id),
|
||||
then_ty,
|
||||
then_span,
|
||||
Some(else_id),
|
||||
else_ty,
|
||||
else_span,
|
||||
);
|
||||
) {
|
||||
err.subdiagnostic(subdiag);
|
||||
}
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
self.suggest_boxing_for_return_impl_trait(
|
||||
err,
|
||||
|
@ -1,5 +1,8 @@
|
||||
use crate::infer::{
|
||||
error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
|
||||
use crate::{
|
||||
errors::PlaceholderRelationLfNotSatisfied,
|
||||
infer::{
|
||||
error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
|
||||
},
|
||||
};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
|
||||
@ -16,8 +19,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
|
||||
Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)),
|
||||
Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
|
||||
)) => {
|
||||
let msg = "lifetime bound not satisfied";
|
||||
let mut err = self.tcx().sess.struct_span_err(*span, msg);
|
||||
let span = *span;
|
||||
let (sub_span, sub_symbol) = match sub_name {
|
||||
ty::BrNamed(def_id, symbol) => {
|
||||
(Some(self.tcx().def_span(def_id)), Some(symbol))
|
||||
@ -32,41 +34,47 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
|
||||
ty::BrAnon(_, span) => (*span, None),
|
||||
ty::BrEnv => (None, None),
|
||||
};
|
||||
match (sub_span, sup_span, sub_symbol, sup_symbol) {
|
||||
(Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => {
|
||||
err.span_note(
|
||||
let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) {
|
||||
(Some(sub_span), Some(sup_span), Some(&sub_symbol), Some(&sup_symbol)) => {
|
||||
PlaceholderRelationLfNotSatisfied::HasBoth {
|
||||
span,
|
||||
sub_span,
|
||||
format!("the lifetime `{sub_symbol}` defined here..."),
|
||||
);
|
||||
err.span_note(
|
||||
sup_span,
|
||||
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
|
||||
);
|
||||
sub_symbol,
|
||||
sup_symbol,
|
||||
note: (),
|
||||
}
|
||||
}
|
||||
(Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
|
||||
err.span_note(sub_span, "the lifetime defined here...");
|
||||
err.span_note(
|
||||
sup_span,
|
||||
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
|
||||
);
|
||||
}
|
||||
(Some(sub_span), Some(sup_span), Some(sub_symbol), _) => {
|
||||
err.span_note(
|
||||
(Some(sub_span), Some(sup_span), _, Some(&sup_symbol)) => {
|
||||
PlaceholderRelationLfNotSatisfied::HasSup {
|
||||
span,
|
||||
sub_span,
|
||||
format!("the lifetime `{sub_symbol}` defined here..."),
|
||||
);
|
||||
err.span_note(sup_span, "...must outlive the lifetime defined here");
|
||||
sup_span,
|
||||
sup_symbol,
|
||||
note: (),
|
||||
}
|
||||
}
|
||||
(Some(sub_span), Some(sup_span), Some(&sub_symbol), _) => {
|
||||
PlaceholderRelationLfNotSatisfied::HasSub {
|
||||
span,
|
||||
sub_span,
|
||||
sup_span,
|
||||
sub_symbol,
|
||||
note: (),
|
||||
}
|
||||
}
|
||||
(Some(sub_span), Some(sup_span), _, _) => {
|
||||
err.span_note(sub_span, "the lifetime defined here...");
|
||||
err.span_note(sup_span, "...must outlive the lifetime defined here");
|
||||
PlaceholderRelationLfNotSatisfied::HasNone {
|
||||
span,
|
||||
sub_span,
|
||||
sup_span,
|
||||
note: (),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
err.note("this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)");
|
||||
Some(err)
|
||||
_ => PlaceholderRelationLfNotSatisfied::OnlyPrimarySpan { span, note: () },
|
||||
};
|
||||
Some(self.tcx().sess.create_err(diag))
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
use crate::errors::RegionOriginNote;
|
||||
use crate::errors::{
|
||||
note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
|
||||
RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
|
||||
};
|
||||
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
|
||||
use crate::infer::{self, SubregionOrigin};
|
||||
use rustc_errors::{
|
||||
fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
|
||||
ErrorGuaranteed,
|
||||
fluent, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
|
||||
};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
@ -119,130 +121,105 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
err
|
||||
}
|
||||
infer::Reborrow(span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0312,
|
||||
"lifetime of reference outlives lifetime of borrowed content..."
|
||||
);
|
||||
note_and_explain_region(
|
||||
let reference_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"...the reference is valid for ",
|
||||
sub,
|
||||
"...",
|
||||
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,
|
||||
&mut err,
|
||||
"...but the borrowed content is only valid for ",
|
||||
sup,
|
||||
"",
|
||||
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) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0476,
|
||||
"lifetime of the source pointer does not outlive lifetime bound of the \
|
||||
object type"
|
||||
);
|
||||
note_and_explain_region(
|
||||
let object_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"object type is valid for ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::TypeObjValidFor,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
note_and_explain_region(
|
||||
let pointer_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"source pointer is only valid for ",
|
||||
sup,
|
||||
"",
|
||||
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) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0477,
|
||||
"the type `{}` does not fulfill the required lifetime",
|
||||
self.ty_to_string(ty)
|
||||
let prefix = match *sub {
|
||||
ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
|
||||
_ => note_and_explain::PrefixKind::TypeOutlive,
|
||||
};
|
||||
let suffix = if opt_span.is_some() {
|
||||
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 {
|
||||
ty::ReStatic => note_and_explain_region(
|
||||
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
|
||||
FullfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
|
||||
note_and_explain_region(
|
||||
let param_instantiated = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"lifetime parameter instantiated with ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::LfParamInstantiatedWith,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
note_and_explain_region(
|
||||
let param_must_outlive = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but lifetime parameter must outlive ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::LfParamMustOutlive,
|
||||
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) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0491,
|
||||
"in type `{}`, reference has a longer lifetime than the data it references",
|
||||
self.ty_to_string(ty)
|
||||
);
|
||||
note_and_explain_region(
|
||||
let pointer_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"the pointer is valid for ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::PointerValidFor,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
note_and_explain_region(
|
||||
let data_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but the referenced data is only valid for ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::DataValidFor,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
err
|
||||
RefLongerThanData {
|
||||
span,
|
||||
ty: self.resolve_vars_if_possible(ty),
|
||||
notes: pointer_valid.into_iter().chain(data_valid).collect(),
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
|
||||
let mut err = self.report_extra_impl_obligation(
|
||||
@ -279,25 +256,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
err
|
||||
}
|
||||
infer::AscribeUserTypeProvePredicate(span) => {
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
|
||||
note_and_explain_region(
|
||||
let instantiated = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"lifetime instantiated with ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::LfInstantiatedWith,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
note_and_explain_region(
|
||||
let must_outlive = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but lifetime must outlive ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::LfMustOutlive,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
err
|
||||
LfBoundNotSatisfied {
|
||||
span,
|
||||
notes: instantiated.into_iter().chain(must_outlive).collect(),
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
};
|
||||
if sub.is_error() || sup.is_error() {
|
||||
@ -347,22 +324,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; };
|
||||
|
||||
if trait_predicates.is_empty() {
|
||||
err.span_suggestion_verbose(
|
||||
generics.where_clause_span,
|
||||
"remove the `where` clause",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let suggestion = if trait_predicates.is_empty() {
|
||||
WhereClauseSuggestions::Remove { span: generics.where_clause_span }
|
||||
} else {
|
||||
let space = if generics.where_clause_span.is_empty() { " " } else { "" };
|
||||
err.span_suggestion_verbose(
|
||||
generics.where_clause_span,
|
||||
"copy the `where` clause predicates from the trait",
|
||||
format!("{space}where {}", trait_predicates.join(", ")),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
WhereClauseSuggestions::CopyPredicates {
|
||||
span: generics.where_clause_span,
|
||||
space,
|
||||
trait_predicates: trait_predicates.join(", "),
|
||||
}
|
||||
};
|
||||
err.subdiagnostic(suggestion);
|
||||
}
|
||||
|
||||
pub(super) fn report_placeholder_failure(
|
||||
|
@ -11,21 +11,22 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitable};
|
||||
use rustc_span::{sym, BytePos, Span};
|
||||
|
||||
use crate::errors::SuggAddLetForLetChains;
|
||||
use crate::errors::{
|
||||
ConsiderAddingAwait, SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding,
|
||||
};
|
||||
|
||||
use super::TypeErrCtxt;
|
||||
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
pub(super) fn suggest_remove_semi_or_return_binding(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
first_id: Option<hir::HirId>,
|
||||
first_ty: Ty<'tcx>,
|
||||
first_span: Span,
|
||||
second_id: Option<hir::HirId>,
|
||||
second_ty: Ty<'tcx>,
|
||||
second_span: Span,
|
||||
) {
|
||||
) -> Option<SuggestRemoveSemiOrReturnBinding> {
|
||||
let remove_semicolon = [
|
||||
(first_id, self.resolve_vars_if_possible(second_ty)),
|
||||
(second_id, self.resolve_vars_if_possible(first_ty)),
|
||||
@ -37,35 +38,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
});
|
||||
match remove_semicolon {
|
||||
Some((sp, StatementAsExpression::NeedsBoxing)) => {
|
||||
err.multipart_suggestion(
|
||||
"consider removing this semicolon and boxing the expressions",
|
||||
vec![
|
||||
(first_span.shrink_to_lo(), "Box::new(".to_string()),
|
||||
(first_span.shrink_to_hi(), ")".to_string()),
|
||||
(second_span.shrink_to_lo(), "Box::new(".to_string()),
|
||||
(second_span.shrink_to_hi(), ")".to_string()),
|
||||
(sp, String::new()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
Some(SuggestRemoveSemiOrReturnBinding::RemoveAndBox {
|
||||
first_lo: first_span.shrink_to_lo(),
|
||||
first_hi: first_span.shrink_to_hi(),
|
||||
second_lo: second_span.shrink_to_lo(),
|
||||
second_hi: second_span.shrink_to_hi(),
|
||||
sp,
|
||||
})
|
||||
}
|
||||
Some((sp, StatementAsExpression::CorrectType)) => {
|
||||
err.span_suggestion_short(
|
||||
sp,
|
||||
"consider removing this semicolon",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
Some(SuggestRemoveSemiOrReturnBinding::Remove { sp })
|
||||
}
|
||||
None => {
|
||||
let mut ret = None;
|
||||
for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
|
||||
if let Some(id) = id
|
||||
&& let hir::Node::Block(blk) = self.tcx.hir().get(id)
|
||||
&& self.consider_returning_binding(blk, ty, err)
|
||||
&& let Some(diag) = self.consider_returning_binding_diag(blk, ty)
|
||||
{
|
||||
ret = Some(diag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,7 +193,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
match (
|
||||
let subdiag = match (
|
||||
self.get_impl_future_output_ty(exp_found.expected),
|
||||
self.get_impl_future_output_ty(exp_found.found),
|
||||
) {
|
||||
@ -207,65 +202,56 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
{
|
||||
ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
|
||||
let then_span = self.find_block_span_from_hir_id(*then_id);
|
||||
diag.multipart_suggestion(
|
||||
"consider `await`ing on both `Future`s",
|
||||
vec![
|
||||
(then_span.shrink_to_hi(), ".await".to_string()),
|
||||
(exp_span.shrink_to_hi(), ".await".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
Some(ConsiderAddingAwait::BothFuturesSugg {
|
||||
first: then_span.shrink_to_hi(),
|
||||
second: exp_span.shrink_to_hi(),
|
||||
})
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
prior_arms,
|
||||
..
|
||||
}) => {
|
||||
if let [.., arm_span] = &prior_arms[..] {
|
||||
diag.multipart_suggestion(
|
||||
"consider `await`ing on both `Future`s",
|
||||
vec![
|
||||
(arm_span.shrink_to_hi(), ".await".to_string()),
|
||||
(exp_span.shrink_to_hi(), ".await".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
Some(ConsiderAddingAwait::BothFuturesSugg {
|
||||
first: arm_span.shrink_to_hi(),
|
||||
second: exp_span.shrink_to_hi(),
|
||||
})
|
||||
} else {
|
||||
diag.help("consider `await`ing on both `Future`s");
|
||||
Some(ConsiderAddingAwait::BothFuturesHelp)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
diag.help("consider `await`ing on both `Future`s");
|
||||
}
|
||||
_ => Some(ConsiderAddingAwait::BothFuturesHelp),
|
||||
},
|
||||
(_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
|
||||
self.suggest_await_on_future(diag, exp_span);
|
||||
diag.span_note(exp_span, "calling an async function returns a future");
|
||||
// FIXME: Seems like we can't have a suggestion and a note with different spans in a single subdiagnostic
|
||||
diag.subdiagnostic(ConsiderAddingAwait::FutureSugg {
|
||||
span: exp_span.shrink_to_hi(),
|
||||
});
|
||||
Some(ConsiderAddingAwait::FutureSuggNote { span: exp_span })
|
||||
}
|
||||
(Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
|
||||
{
|
||||
ObligationCauseCode::Pattern { span: Some(then_span), .. } => {
|
||||
self.suggest_await_on_future(diag, then_span.shrink_to_hi());
|
||||
Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
|
||||
}
|
||||
ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
|
||||
let then_span = self.find_block_span_from_hir_id(*then_id);
|
||||
self.suggest_await_on_future(diag, then_span.shrink_to_hi());
|
||||
Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
ref prior_arms,
|
||||
..
|
||||
}) => {
|
||||
diag.multipart_suggestion_verbose(
|
||||
"consider `await`ing on the `Future`",
|
||||
prior_arms
|
||||
.iter()
|
||||
.map(|arm| (arm.shrink_to_hi(), ".await".to_string()))
|
||||
.collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}) => Some({
|
||||
ConsiderAddingAwait::FutureSuggMultiple {
|
||||
spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(),
|
||||
}
|
||||
}),
|
||||
_ => None,
|
||||
},
|
||||
_ => {}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(subdiag) = subdiag {
|
||||
diag.subdiagnostic(subdiag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -655,16 +641,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
/// Suggest returning a local binding with a compatible type if the block
|
||||
/// has no return expression.
|
||||
pub fn consider_returning_binding(
|
||||
pub fn consider_returning_binding_diag(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
) -> bool {
|
||||
) -> Option<SuggestRemoveSemiOrReturnBinding> {
|
||||
let blk = blk.innermost_block();
|
||||
// Do not suggest if we have a tail expr.
|
||||
if blk.expr.is_some() {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
let mut shadowed = FxIndexSet::default();
|
||||
let mut candidate_idents = vec![];
|
||||
@ -733,7 +718,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
match &candidate_idents[..] {
|
||||
[(ident, _ty)] => {
|
||||
let sm = self.tcx.sess.source_map();
|
||||
if let Some(stmt) = blk.stmts.last() {
|
||||
let (span, sugg) = if let Some(stmt) = blk.stmts.last() {
|
||||
let stmt_span = sm.stmt_span(stmt.span, blk.span);
|
||||
let sugg = if sm.is_multiline(blk.span)
|
||||
&& let Some(spacing) = sm.indentation_before(stmt_span)
|
||||
@ -742,12 +727,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
} else {
|
||||
format!(" {ident}")
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
stmt_span.shrink_to_hi(),
|
||||
format!("consider returning the local binding `{ident}`"),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
(stmt_span.shrink_to_hi(), sugg)
|
||||
} else {
|
||||
let sugg = if sm.is_multiline(blk.span)
|
||||
&& let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
|
||||
@ -757,21 +737,34 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
format!(" {ident} ")
|
||||
};
|
||||
let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
|
||||
err.span_suggestion_verbose(
|
||||
(
|
||||
sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
|
||||
format!("consider returning the local binding `{ident}`"),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
true
|
||||
)
|
||||
};
|
||||
Some(SuggestRemoveSemiOrReturnBinding::Add { sp: span, code: sugg, ident: *ident })
|
||||
}
|
||||
values if (1..3).contains(&values.len()) => {
|
||||
let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
|
||||
err.span_note(spans, "consider returning one of these bindings");
|
||||
Some(SuggestRemoveSemiOrReturnBinding::AddOne { spans: spans.into() })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consider_returning_binding(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
) -> bool {
|
||||
let diag = self.consider_returning_binding_diag(blk, expected_ty);
|
||||
match diag {
|
||||
Some(diag) => {
|
||||
err.subdiagnostic(diag);
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user