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 ->
|
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_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] {""}
|
[empty] {""}
|
||||||
}{$pref_kind ->
|
}{$pref_kind ->
|
||||||
[empty] {""}
|
[empty] {""}
|
||||||
@ -148,7 +160,6 @@ infer_region_explanation = {$pref_kind ->
|
|||||||
*[should_not_happen] [{$desc_kind}]
|
*[should_not_happen] [{$desc_kind}]
|
||||||
[restatic] the static lifetime
|
[restatic] the static lifetime
|
||||||
[revar] lifetime {$desc_arg}
|
[revar] lifetime {$desc_arg}
|
||||||
|
|
||||||
[as_defined] the lifetime `{$desc_arg}` as defined here
|
[as_defined] the lifetime `{$desc_arg}` as defined here
|
||||||
[as_defined_anon] the anonymous lifetime as defined here
|
[as_defined_anon] the anonymous lifetime as defined here
|
||||||
[defined_here] the anonymous lifetime defined here
|
[defined_here] the anonymous lifetime defined here
|
||||||
@ -158,8 +169,16 @@ 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_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_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
|
||||||
@ -308,3 +327,21 @@ infer_ril_introduced_here = `'static` requirement introduced here
|
|||||||
infer_ril_introduced_by = requirement introduced by this return type
|
infer_ril_introduced_by = requirement introduced by this return type
|
||||||
infer_ril_because_of = because of this returned expression
|
infer_ril_because_of = because of this returned expression
|
||||||
infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
|
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 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>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 {
|
pub enum PrefixKind {
|
||||||
Empty,
|
Empty,
|
||||||
|
RefValidFor,
|
||||||
|
ContentValidFor,
|
||||||
|
TypeObjValidFor,
|
||||||
|
SourcePointerValidFor,
|
||||||
|
TypeSatisfy,
|
||||||
|
TypeOutlive,
|
||||||
|
LfParamInstantiatedWith,
|
||||||
|
LfParamMustOutlive,
|
||||||
|
LfInstantiatedWith,
|
||||||
|
LfMustOutlive,
|
||||||
|
PointerValidFor,
|
||||||
|
DataValidFor,
|
||||||
}
|
}
|
||||||
|
|
||||||
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::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();
|
.into();
|
||||||
rustc_errors::DiagnosticArgValue::Str(kind)
|
rustc_errors::DiagnosticArgValue::Str(kind)
|
||||||
@ -140,7 +166,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 +194,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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -751,15 +751,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
};
|
};
|
||||||
let msg = "`match` arms have incompatible types";
|
let msg = "`match` arms have incompatible types";
|
||||||
err.span_label(outer, msg);
|
err.span_label(outer, msg);
|
||||||
self.suggest_remove_semi_or_return_binding(
|
if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
|
||||||
err,
|
|
||||||
prior_arm_block_id,
|
prior_arm_block_id,
|
||||||
prior_arm_ty,
|
prior_arm_ty,
|
||||||
prior_arm_span,
|
prior_arm_span,
|
||||||
arm_block_id,
|
arm_block_id,
|
||||||
arm_ty,
|
arm_ty,
|
||||||
arm_span,
|
arm_span,
|
||||||
);
|
) {
|
||||||
|
err.subdiagnostic(subdiag);
|
||||||
|
}
|
||||||
if let Some(ret_sp) = opt_suggest_box_span {
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
// Get return type span and point to it.
|
// Get return type span and point to it.
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
@ -784,15 +785,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
if let Some(sp) = outer_span {
|
if let Some(sp) = outer_span {
|
||||||
err.span_label(sp, "`if` and `else` have incompatible types");
|
err.span_label(sp, "`if` and `else` have incompatible types");
|
||||||
}
|
}
|
||||||
self.suggest_remove_semi_or_return_binding(
|
if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
|
||||||
err,
|
|
||||||
Some(then_id),
|
Some(then_id),
|
||||||
then_ty,
|
then_ty,
|
||||||
then_span,
|
then_span,
|
||||||
Some(else_id),
|
Some(else_id),
|
||||||
else_ty,
|
else_ty,
|
||||||
else_span,
|
else_span,
|
||||||
);
|
) {
|
||||||
|
err.subdiagnostic(subdiag);
|
||||||
|
}
|
||||||
if let Some(ret_sp) = opt_suggest_box_span {
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
err,
|
err,
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use crate::infer::{
|
use crate::{
|
||||||
error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
|
errors::PlaceholderRelationLfNotSatisfied,
|
||||||
|
infer::{
|
||||||
|
error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use rustc_data_structures::intern::Interned;
|
use rustc_data_structures::intern::Interned;
|
||||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
|
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: sub_name, .. }), _)),
|
||||||
Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
|
Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
|
||||||
)) => {
|
)) => {
|
||||||
let msg = "lifetime bound not satisfied";
|
let span = *span;
|
||||||
let mut err = self.tcx().sess.struct_span_err(*span, msg);
|
|
||||||
let (sub_span, sub_symbol) = match sub_name {
|
let (sub_span, sub_symbol) = match sub_name {
|
||||||
ty::BrNamed(def_id, symbol) => {
|
ty::BrNamed(def_id, symbol) => {
|
||||||
(Some(self.tcx().def_span(def_id)), Some(symbol))
|
(Some(self.tcx().def_span(def_id)), Some(symbol))
|
||||||
@ -32,41 +34,47 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
|
|||||||
ty::BrAnon(_, span) => (*span, None),
|
ty::BrAnon(_, span) => (*span, None),
|
||||||
ty::BrEnv => (None, None),
|
ty::BrEnv => (None, None),
|
||||||
};
|
};
|
||||||
match (sub_span, sup_span, sub_symbol, sup_symbol) {
|
let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) {
|
||||||
(Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => {
|
(Some(sub_span), Some(sup_span), Some(&sub_symbol), Some(&sup_symbol)) => {
|
||||||
err.span_note(
|
PlaceholderRelationLfNotSatisfied::HasBoth {
|
||||||
|
span,
|
||||||
sub_span,
|
sub_span,
|
||||||
format!("the lifetime `{sub_symbol}` defined here..."),
|
|
||||||
);
|
|
||||||
err.span_note(
|
|
||||||
sup_span,
|
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)) => {
|
(Some(sub_span), Some(sup_span), _, Some(&sup_symbol)) => {
|
||||||
err.span_note(sub_span, "the lifetime defined here...");
|
PlaceholderRelationLfNotSatisfied::HasSup {
|
||||||
err.span_note(
|
span,
|
||||||
sup_span,
|
|
||||||
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(Some(sub_span), Some(sup_span), Some(sub_symbol), _) => {
|
|
||||||
err.span_note(
|
|
||||||
sub_span,
|
sub_span,
|
||||||
format!("the lifetime `{sub_symbol}` defined here..."),
|
sup_span,
|
||||||
);
|
sup_symbol,
|
||||||
err.span_note(sup_span, "...must outlive the lifetime defined here");
|
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), _, _) => {
|
(Some(sub_span), Some(sup_span), _, _) => {
|
||||||
err.span_note(sub_span, "the lifetime defined here...");
|
PlaceholderRelationLfNotSatisfied::HasNone {
|
||||||
err.span_note(sup_span, "...must outlive the lifetime defined here");
|
span,
|
||||||
|
sub_span,
|
||||||
|
sup_span,
|
||||||
|
note: (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => PlaceholderRelationLfNotSatisfied::OnlyPrimarySpan { 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(self.tcx().sess.create_err(diag))
|
||||||
Some(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => None,
|
_ => 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::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, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
|
||||||
ErrorGuaranteed,
|
|
||||||
};
|
};
|
||||||
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,130 +121,105 @@ 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::TypeObjValidFor,
|
||||||
|
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::LfParamInstantiatedWith,
|
||||||
|
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::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) => {
|
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||||
let mut err = struct_span_err!(
|
let pointer_valid = note_and_explain::RegionExplanation::new(
|
||||||
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(
|
|
||||||
self.tcx,
|
self.tcx,
|
||||||
&mut err,
|
|
||||||
"the pointer is valid for ",
|
|
||||||
sub,
|
sub,
|
||||||
"",
|
|
||||||
None,
|
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,
|
self.tcx,
|
||||||
&mut err,
|
|
||||||
"but the referenced data is only valid for ",
|
|
||||||
sup,
|
sup,
|
||||||
"",
|
|
||||||
None,
|
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 } => {
|
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
|
||||||
let mut err = self.report_extra_impl_obligation(
|
let mut err = self.report_extra_impl_obligation(
|
||||||
@ -279,25 +256,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
err
|
err
|
||||||
}
|
}
|
||||||
infer::AscribeUserTypeProvePredicate(span) => {
|
infer::AscribeUserTypeProvePredicate(span) => {
|
||||||
let mut err =
|
let 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 instantiated with ",
|
|
||||||
sup,
|
sup,
|
||||||
"",
|
|
||||||
None,
|
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,
|
self.tcx,
|
||||||
&mut err,
|
|
||||||
"but lifetime must outlive ",
|
|
||||||
sub,
|
sub,
|
||||||
"",
|
|
||||||
None,
|
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() {
|
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; };
|
let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; };
|
||||||
|
|
||||||
if trait_predicates.is_empty() {
|
let suggestion = if trait_predicates.is_empty() {
|
||||||
err.span_suggestion_verbose(
|
WhereClauseSuggestions::Remove { span: generics.where_clause_span }
|
||||||
generics.where_clause_span,
|
|
||||||
"remove the `where` clause",
|
|
||||||
String::new(),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
let space = if generics.where_clause_span.is_empty() { " " } else { "" };
|
let space = if generics.where_clause_span.is_empty() { " " } else { "" };
|
||||||
err.span_suggestion_verbose(
|
WhereClauseSuggestions::CopyPredicates {
|
||||||
generics.where_clause_span,
|
span: generics.where_clause_span,
|
||||||
"copy the `where` clause predicates from the trait",
|
space,
|
||||||
format!("{space}where {}", trait_predicates.join(", ")),
|
trait_predicates: trait_predicates.join(", "),
|
||||||
Applicability::MachineApplicable,
|
}
|
||||||
);
|
};
|
||||||
}
|
err.subdiagnostic(suggestion);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn report_placeholder_failure(
|
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_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitable};
|
||||||
use rustc_span::{sym, BytePos, Span};
|
use rustc_span::{sym, BytePos, Span};
|
||||||
|
|
||||||
use crate::errors::SuggAddLetForLetChains;
|
use crate::errors::{
|
||||||
|
ConsiderAddingAwait, SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding,
|
||||||
|
};
|
||||||
|
|
||||||
use super::TypeErrCtxt;
|
use super::TypeErrCtxt;
|
||||||
|
|
||||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
pub(super) fn suggest_remove_semi_or_return_binding(
|
pub(super) fn suggest_remove_semi_or_return_binding(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diagnostic,
|
|
||||||
first_id: Option<hir::HirId>,
|
first_id: Option<hir::HirId>,
|
||||||
first_ty: Ty<'tcx>,
|
first_ty: Ty<'tcx>,
|
||||||
first_span: Span,
|
first_span: Span,
|
||||||
second_id: Option<hir::HirId>,
|
second_id: Option<hir::HirId>,
|
||||||
second_ty: Ty<'tcx>,
|
second_ty: Ty<'tcx>,
|
||||||
second_span: Span,
|
second_span: Span,
|
||||||
) {
|
) -> Option<SuggestRemoveSemiOrReturnBinding> {
|
||||||
let remove_semicolon = [
|
let remove_semicolon = [
|
||||||
(first_id, self.resolve_vars_if_possible(second_ty)),
|
(first_id, self.resolve_vars_if_possible(second_ty)),
|
||||||
(second_id, self.resolve_vars_if_possible(first_ty)),
|
(second_id, self.resolve_vars_if_possible(first_ty)),
|
||||||
@ -37,35 +38,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
});
|
});
|
||||||
match remove_semicolon {
|
match remove_semicolon {
|
||||||
Some((sp, StatementAsExpression::NeedsBoxing)) => {
|
Some((sp, StatementAsExpression::NeedsBoxing)) => {
|
||||||
err.multipart_suggestion(
|
Some(SuggestRemoveSemiOrReturnBinding::RemoveAndBox {
|
||||||
"consider removing this semicolon and boxing the expressions",
|
first_lo: first_span.shrink_to_lo(),
|
||||||
vec![
|
first_hi: first_span.shrink_to_hi(),
|
||||||
(first_span.shrink_to_lo(), "Box::new(".to_string()),
|
second_lo: second_span.shrink_to_lo(),
|
||||||
(first_span.shrink_to_hi(), ")".to_string()),
|
second_hi: second_span.shrink_to_hi(),
|
||||||
(second_span.shrink_to_lo(), "Box::new(".to_string()),
|
sp,
|
||||||
(second_span.shrink_to_hi(), ")".to_string()),
|
})
|
||||||
(sp, String::new()),
|
|
||||||
],
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Some((sp, StatementAsExpression::CorrectType)) => {
|
Some((sp, StatementAsExpression::CorrectType)) => {
|
||||||
err.span_suggestion_short(
|
Some(SuggestRemoveSemiOrReturnBinding::Remove { sp })
|
||||||
sp,
|
|
||||||
"consider removing this semicolon",
|
|
||||||
"",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
let mut ret = None;
|
||||||
for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
|
for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
|
||||||
if let Some(id) = id
|
if let Some(id) = id
|
||||||
&& let hir::Node::Block(blk) = self.tcx.hir().get(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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,7 +193,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match (
|
let subdiag = match (
|
||||||
self.get_impl_future_output_ty(exp_found.expected),
|
self.get_impl_future_output_ty(exp_found.expected),
|
||||||
self.get_impl_future_output_ty(exp_found.found),
|
self.get_impl_future_output_ty(exp_found.found),
|
||||||
) {
|
) {
|
||||||
@ -207,65 +202,56 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
{
|
{
|
||||||
ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
|
ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
|
||||||
let then_span = self.find_block_span_from_hir_id(*then_id);
|
let then_span = self.find_block_span_from_hir_id(*then_id);
|
||||||
diag.multipart_suggestion(
|
Some(ConsiderAddingAwait::BothFuturesSugg {
|
||||||
"consider `await`ing on both `Future`s",
|
first: then_span.shrink_to_hi(),
|
||||||
vec![
|
second: exp_span.shrink_to_hi(),
|
||||||
(then_span.shrink_to_hi(), ".await".to_string()),
|
})
|
||||||
(exp_span.shrink_to_hi(), ".await".to_string()),
|
|
||||||
],
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||||
prior_arms,
|
prior_arms,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
if let [.., arm_span] = &prior_arms[..] {
|
if let [.., arm_span] = &prior_arms[..] {
|
||||||
diag.multipart_suggestion(
|
Some(ConsiderAddingAwait::BothFuturesSugg {
|
||||||
"consider `await`ing on both `Future`s",
|
first: arm_span.shrink_to_hi(),
|
||||||
vec![
|
second: exp_span.shrink_to_hi(),
|
||||||
(arm_span.shrink_to_hi(), ".await".to_string()),
|
})
|
||||||
(exp_span.shrink_to_hi(), ".await".to_string()),
|
|
||||||
],
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
diag.help("consider `await`ing on both `Future`s");
|
Some(ConsiderAddingAwait::BothFuturesHelp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => Some(ConsiderAddingAwait::BothFuturesHelp),
|
||||||
diag.help("consider `await`ing on both `Future`s");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
(_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
|
(_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
|
||||||
self.suggest_await_on_future(diag, exp_span);
|
// FIXME: Seems like we can't have a suggestion and a note with different spans in a single subdiagnostic
|
||||||
diag.span_note(exp_span, "calling an async function returns a future");
|
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()
|
(Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
|
||||||
{
|
{
|
||||||
ObligationCauseCode::Pattern { span: Some(then_span), .. } => {
|
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, .. }) => {
|
ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
|
||||||
let then_span = self.find_block_span_from_hir_id(*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 {
|
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||||
ref prior_arms,
|
ref prior_arms,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => Some({
|
||||||
diag.multipart_suggestion_verbose(
|
ConsiderAddingAwait::FutureSuggMultiple {
|
||||||
"consider `await`ing on the `Future`",
|
spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(),
|
||||||
prior_arms
|
}
|
||||||
.iter()
|
}),
|
||||||
.map(|arm| (arm.shrink_to_hi(), ".await".to_string()))
|
_ => None,
|
||||||
.collect(),
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => 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
|
/// Suggest returning a local binding with a compatible type if the block
|
||||||
/// has no return expression.
|
/// has no return expression.
|
||||||
pub fn consider_returning_binding(
|
pub fn consider_returning_binding_diag(
|
||||||
&self,
|
&self,
|
||||||
blk: &'tcx hir::Block<'tcx>,
|
blk: &'tcx hir::Block<'tcx>,
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
err: &mut Diagnostic,
|
) -> Option<SuggestRemoveSemiOrReturnBinding> {
|
||||||
) -> bool {
|
|
||||||
let blk = blk.innermost_block();
|
let blk = blk.innermost_block();
|
||||||
// Do not suggest if we have a tail expr.
|
// Do not suggest if we have a tail expr.
|
||||||
if blk.expr.is_some() {
|
if blk.expr.is_some() {
|
||||||
return false;
|
return None;
|
||||||
}
|
}
|
||||||
let mut shadowed = FxIndexSet::default();
|
let mut shadowed = FxIndexSet::default();
|
||||||
let mut candidate_idents = vec![];
|
let mut candidate_idents = vec![];
|
||||||
@ -733,7 +718,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
match &candidate_idents[..] {
|
match &candidate_idents[..] {
|
||||||
[(ident, _ty)] => {
|
[(ident, _ty)] => {
|
||||||
let sm = self.tcx.sess.source_map();
|
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 stmt_span = sm.stmt_span(stmt.span, blk.span);
|
||||||
let sugg = if sm.is_multiline(blk.span)
|
let sugg = if sm.is_multiline(blk.span)
|
||||||
&& let Some(spacing) = sm.indentation_before(stmt_span)
|
&& let Some(spacing) = sm.indentation_before(stmt_span)
|
||||||
@ -742,12 +727,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
format!(" {ident}")
|
format!(" {ident}")
|
||||||
};
|
};
|
||||||
err.span_suggestion_verbose(
|
(stmt_span.shrink_to_hi(), sugg)
|
||||||
stmt_span.shrink_to_hi(),
|
|
||||||
format!("consider returning the local binding `{ident}`"),
|
|
||||||
sugg,
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
let sugg = if sm.is_multiline(blk.span)
|
let sugg = if sm.is_multiline(blk.span)
|
||||||
&& let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
|
&& let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
|
||||||
@ -757,21 +737,34 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
format!(" {ident} ")
|
format!(" {ident} ")
|
||||||
};
|
};
|
||||||
let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
|
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),
|
sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
|
||||||
format!("consider returning the local binding `{ident}`"),
|
|
||||||
sugg,
|
sugg,
|
||||||
Applicability::MaybeIncorrect,
|
)
|
||||||
);
|
};
|
||||||
}
|
Some(SuggestRemoveSemiOrReturnBinding::Add { sp: span, code: sugg, ident: *ident })
|
||||||
true
|
|
||||||
}
|
}
|
||||||
values if (1..3).contains(&values.len()) => {
|
values if (1..3).contains(&values.len()) => {
|
||||||
let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
|
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
|
true
|
||||||
}
|
}
|
||||||
_ => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user