summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer/error_reporting
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_infer/src/infer/error_reporting
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_infer/src/infer/error_reporting')
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs36
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs12
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs15
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs21
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs32
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs83
9 files changed, 147 insertions, 60 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 9e5f6d107..35c05e80b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -74,7 +74,6 @@ use rustc_middle::ty::{
self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt,
};
-use rustc_span::DUMMY_SP;
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::ops::{ControlFlow, Deref};
@@ -138,7 +137,7 @@ impl Drop for TypeErrCtxt<'_, '_> {
self.infcx
.tcx
.sess
- .delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation");
+ .delay_good_path_bug("used a `TypeErrCtxt` without raising an error or lint");
}
}
}
@@ -283,9 +282,9 @@ fn emit_msg_span(
let message = format!("{}{}{}", prefix, description, suffix);
if let Some(span) = span {
- err.span_note(span, &message);
+ err.span_note(span, message);
} else {
- err.note(&message);
+ err.note(message);
}
}
@@ -299,9 +298,9 @@ fn label_msg_span(
let message = format!("{}{}{}", prefix, description, suffix);
if let Some(span) = span {
- err.span_label(span, &message);
+ err.span_label(span, message);
} else {
- err.note(&message);
+ err.note(message);
}
}
@@ -403,7 +402,7 @@ impl<'tcx> InferCtxt<'tcx> {
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
- self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map(
+ self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map(
|(predicate, _)| {
predicate
.kind()
@@ -1826,7 +1825,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
s
};
if !(values.expected.is_simple_text() && values.found.is_simple_text())
- || (exp_found.map_or(false, |ef| {
+ || (exp_found.is_some_and(|ef| {
// This happens when the type error is a subset of the expectation,
// like when you have two references but one is `usize` and the other
// is `f32`. In those cases we still want to show the `note`. If the
@@ -1878,7 +1877,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let exp_found = match terr {
// `terr` has more accurate type information than `exp_found` in match expressions.
ty::error::TypeError::Sorts(terr)
- if exp_found.map_or(false, |ef| terr.found == ef.found) =>
+ if exp_found.is_some_and(|ef| terr.found == ef.found) =>
{
Some(terr)
}
@@ -1927,6 +1926,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
{
let span = self.tcx.def_span(def_id);
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
+ self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag);
}
// It reads better to have the error origin as the final
@@ -1961,7 +1961,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
&& let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
&& !code.starts_with("\\u") // forbid all Unicode escapes
- && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
+ && code.chars().next().is_some_and(|c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
{
suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral { span, code: escape_literal(code) })
}
@@ -2329,7 +2329,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.source_map()
.span_to_prev_source(p.span.shrink_to_hi())
.ok()
- .map_or(false, |s| *s.as_bytes().last().unwrap() == b'&')
+ .is_some_and(|s| *s.as_bytes().last().unwrap() == b'&')
{
add_lt_suggs
.push(Some(
@@ -2354,7 +2354,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
- ty::AliasKind::Projection => format!("the associated type `{}`", p),
+ ty::AliasKind::Projection | ty::AliasKind::Inherent => {
+ format!("the associated type `{}`", p)
+ }
ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
},
};
@@ -2395,7 +2397,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
} else {
let consider = format!("{} `{}: {}`...", msg, bound_kind, sub);
- err.help(&consider);
+ err.help(consider);
}
}
@@ -2625,7 +2627,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
err.span_note(
sup_trace.cause.span,
- &format!("...so that the {}", sup_trace.cause.as_requirement_str()),
+ format!("...so that the {}", sup_trace.cause.as_requirement_str()),
);
err.note_expected_found(&"", sup_expected, &"", sup_found);
@@ -2721,7 +2723,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
| (ty::Infer(ty::InferTy::TyVar(_)), _)
| (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a),
(ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch),
- _ => relate::super_relate_tys(self, a, b),
+ _ => relate::structurally_relate_tys(self, a, b),
}
}
@@ -2885,7 +2887,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags },
MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span },
StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags },
- IntrinsicType => ObligationCauseFailureCode::IntristicCorrectType { span, subdiags },
+ IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags },
MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags },
// In the case where we have no more specific thing to
@@ -2942,7 +2944,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> {
IfExpressionWithNoElse => "no_else",
MainFunctionType => "fn_main_correct_type",
StartFunctionType => "fn_start_correct_type",
- IntrinsicType => "intristic_correct_type",
+ IntrinsicType => "intrinsic_correct_type",
MethodReceiver => "method_correct_type",
_ => "other",
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 75cc4e257..f3b2ec4c5 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -1,5 +1,5 @@
use crate::errors::{
- AmbigousReturn, AmbiguousImpl, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
+ AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
SourceKindMultiSuggestion, SourceKindSubdiag,
};
use crate::infer::error_reporting::TypeErrCtxt;
@@ -31,7 +31,7 @@ pub enum TypeAnnotationNeeded {
/// ```
E0282,
/// An implementation cannot be chosen unambiguously because of lack of information.
- /// ```compile_fail,E0283
+ /// ```compile_fail,E0790
/// let _ = Default::default();
/// ```
E0283,
@@ -368,7 +368,7 @@ impl<'tcx> InferCtxt<'tcx> {
bad_label,
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
- TypeAnnotationNeeded::E0284 => AmbigousReturn {
+ TypeAnnotationNeeded::E0284 => AmbiguousReturn {
span,
source_kind,
source_name,
@@ -573,7 +573,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
bad_label: None,
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
- TypeAnnotationNeeded::E0284 => AmbigousReturn {
+ TypeAnnotationNeeded::E0284 => AmbiguousReturn {
span,
source_kind,
source_name: &name,
@@ -671,7 +671,7 @@ impl<'tcx> InferSource<'tcx> {
receiver.span.from_expansion()
}
InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => {
- data.span().from_expansion() || should_wrap_expr.map_or(false, Span::from_expansion)
+ data.span().from_expansion() || should_wrap_expr.is_some_and(Span::from_expansion)
}
};
source_from_expansion || self.span.from_expansion()
@@ -984,7 +984,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
let tcx = self.infcx.tcx;
let have_turbofish = path.segments.iter().any(|segment| {
- segment.args.map_or(false, |args| args.args.iter().any(|arg| arg.is_ty_or_const()))
+ segment.args.is_some_and(|args| args.args.iter().any(|arg| arg.is_ty_or_const()))
});
// The last segment of a path often has `Res::Err` and the
// correct `Res` is the one of the whole path.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index da0271a34..1a60bab18 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -21,7 +21,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
///
/// Consider a case where we have
///
- /// ```compile_fail,E0623
+ /// ```compile_fail
/// fn foo(x: &mut Vec<&u8>, y: &u8) {
/// x.push(y);
/// }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index fec04af23..0df417d09 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Region, TyCtxt};
/// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
///
/// # Example
-/// ```compile_fail,E0623
+/// ```compile_fail
/// fn foo(x: &mut Vec<&u8>, y: &u8)
/// { x.push(y); }
/// ```
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index c1ea0a0d9..c9c1f0aea 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -261,11 +261,16 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
(false, None, None, Some(span), String::new())
};
- let expected_trait_ref = self
- .cx
- .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs));
- let actual_trait_ref =
- self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs));
+ let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new(
+ self.cx.tcx,
+ trait_def_id,
+ expected_substs,
+ ));
+ let actual_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new(
+ self.cx.tcx,
+ trait_def_id,
+ actual_substs,
+ ));
// Search the expected and actual trait references to see (a)
// whether the sub/sup placeholders appear in them (sometimes
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 22c1e3871..aad988582 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -299,7 +299,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
span,
- &format!("{consider} `{ty}`'s {explicit_static}"),
+ format!("{consider} `{ty}`'s {explicit_static}"),
&lifetime_name,
Applicability::MaybeIncorrect,
);
@@ -312,13 +312,10 @@ pub fn suggest_new_region_bound(
Applicability::MaybeIncorrect,
);
}
- } else if opaque.bounds.iter().any(|arg| match arg {
- GenericBound::Outlives(Lifetime { ident, .. })
- if ident.name.to_string() == lifetime_name =>
- {
- true
- }
- _ => false,
+ } else if opaque.bounds.iter().any(|arg| {
+ matches!(arg,
+ GenericBound::Outlives(Lifetime { ident, .. })
+ if ident.name.to_string() == lifetime_name )
}) {
} else {
// get a lifetime name of existing named lifetimes if any
@@ -370,7 +367,7 @@ pub fn suggest_new_region_bound(
spans_suggs
.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{declare} `{ty}` {captures}, {use_lt}",
),
spans_suggs,
@@ -379,7 +376,7 @@ pub fn suggest_new_region_bound(
} else {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
- &format!("{declare} `{ty}` {captures}, {explicit}",),
+ format!("{declare} `{ty}` {captures}, {explicit}",),
&plus_lt,
Applicability::MaybeIncorrect,
);
@@ -390,7 +387,7 @@ pub fn suggest_new_region_bound(
if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
- &format!(
+ format!(
"{declare} the trait object {captures}, {explicit}",
declare = declare,
captures = captures,
@@ -407,7 +404,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
lt.ident.span,
- &format!("{} the trait object's {}", consider, explicit_static),
+ format!("{} the trait object's {}", consider, explicit_static),
&lifetime_name,
Applicability::MaybeIncorrect,
);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 2875448ee..ce70bcc5c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -13,7 +13,7 @@ use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::RegionHighlightMode;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
use rustc_span::Span;
use std::ops::ControlFlow;
@@ -81,7 +81,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
self.highlight.highlighting_region(r, self.counter);
self.counter += 1;
}
- r.super_visit_with(self)
+ ControlFlow::Continue(())
}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index b38bbdfe7..421eb807a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -2,6 +2,7 @@ use super::TypeErrCtxt;
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::Printer;
@@ -71,9 +72,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
#traits-as-parameters",
);
}
- (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
+ (ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => {
diag.note("an associated type was expected, but a different one was found");
}
+ // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
{
@@ -209,7 +211,7 @@ impl<T> Trait<T> for X {
if !sp.contains(p_span) {
diag.span_label(p_span, "this type parameter");
}
- diag.help(&format!(
+ diag.help(format!(
"every closure has a distinct type and so could not always match the \
caller-chosen type of parameter `{}`",
p
@@ -222,7 +224,7 @@ impl<T> Trait<T> for X {
diag.span_label(p_span, "this type parameter");
}
}
- (ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
+ (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
self.expected_projection(
diag,
proj_ty,
@@ -231,7 +233,7 @@ impl<T> Trait<T> for X {
cause.code(),
);
}
- (_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
+ (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
let msg = format!(
"consider constraining the associated type `{}` to `{}`",
values.found, values.expected,
@@ -248,13 +250,22 @@ impl<T> Trait<T> for X {
proj_ty,
values.expected,
)) {
- diag.help(&msg);
+ diag.help(msg);
diag.note(
"for more information, visit \
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
);
}
}
+ (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => {
+ if tcx.is_type_alias_impl_trait(alias.def_id) {
+ if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) {
+ diag.span_note(tcx.def_span(body_owner_def_id), "\
+ this item must have the opaque type in its signature \
+ in order to be able to register hidden types");
+ }
+ }
+ }
(ty::FnPtr(_), ty::FnDef(def, _))
if let hir::def::DefKind::Fn = tcx.def_kind(def) => {
diag.note(
@@ -415,12 +426,12 @@ impl<T> Trait<T> for X {
if !impl_comparison {
// Generic suggestion when we can't be more specific.
if callable_scope {
- diag.help(&format!(
+ diag.help(format!(
"{} or calling a method that returns `{}`",
msg, values.expected
));
} else {
- diag.help(&msg);
+ diag.help(msg);
}
diag.note(
"for more information, visit \
@@ -462,10 +473,7 @@ fn foo(&self) -> Self::T { String::new() }
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
let opaque_local_def_id = def_id.as_local();
let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
- match &tcx.hir().expect_item(opaque_local_def_id).kind {
- hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
- _ => bug!("The HirId comes from a `ty::Opaque`"),
- }
+ tcx.hir().expect_item(opaque_local_def_id).expect_opaque_ty()
} else {
return false;
};
@@ -539,7 +547,7 @@ fn foo(&self) -> Self::T { String::new() }
for (sp, label) in methods.into_iter() {
span.push_span_label(sp, label);
}
- diag.span_help(span, &msg);
+ diag.span_help(span, msg);
return true;
}
false
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index b5aeca12a..d885d0407 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -1,16 +1,15 @@
use hir::def::CtorKind;
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::Diagnostic;
+use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_middle::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
StatementAsExpression,
};
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
use rustc_span::{sym, BytePos, Span};
-use rustc_target::abi::FieldIdx;
use crate::errors::{
ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
@@ -114,7 +113,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
})
.filter_map(|variant| {
- let sole_field = &variant.fields[FieldIdx::from_u32(0)];
+ let sole_field = &variant.single_field();
let sole_field_ty = sole_field.ty(self.tcx, substs);
if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
let variant_path =
@@ -536,6 +535,82 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
None
}
+
+ /// For "one type is more general than the other" errors on closures, suggest changing the lifetime
+ /// of the parameters to accept all lifetimes.
+ pub(super) fn suggest_for_all_lifetime_closure(
+ &self,
+ span: Span,
+ hir: hir::Node<'_>,
+ exp_found: &ty::error::ExpectedFound<ty::PolyTraitRef<'tcx>>,
+ diag: &mut Diagnostic,
+ ) {
+ // 0. Extract fn_decl from hir
+ let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(hir::Closure { body, fn_decl, .. }), .. }) = hir else { return; };
+ let hir::Body { params, .. } = self.tcx.hir().body(*body);
+
+ // 1. Get the substs of the closure.
+ // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1].
+ let Some(expected) = exp_found.expected.skip_binder().substs.get(1) else { return; };
+ let Some(found) = exp_found.found.skip_binder().substs.get(1) else { return; };
+ let expected = expected.unpack();
+ let found = found.unpack();
+ // 3. Extract the tuple type from Fn trait and suggest the change.
+ if let GenericArgKind::Type(expected) = expected &&
+ let GenericArgKind::Type(found) = found &&
+ let ty::Tuple(expected) = expected.kind() &&
+ let ty::Tuple(found)= found.kind() &&
+ expected.len() == found.len() {
+ let mut suggestion = "|".to_string();
+ let mut is_first = true;
+ let mut has_suggestion = false;
+
+ for (((expected, found), param_hir), arg_hir) in expected.iter()
+ .zip(found.iter())
+ .zip(params.iter())
+ .zip(fn_decl.inputs.iter()) {
+ if is_first {
+ is_first = false;
+ } else {
+ suggestion += ", ";
+ }
+
+ if let ty::Ref(expected_region, _, _) = expected.kind() &&
+ let ty::Ref(found_region, _, _) = found.kind() &&
+ expected_region.is_late_bound() &&
+ !found_region.is_late_bound() &&
+ let hir::TyKind::Infer = arg_hir.kind {
+ // If the expected region is late bound, the found region is not, and users are asking compiler
+ // to infer the type, we can suggest adding `: &_`.
+ if param_hir.pat.span == param_hir.ty_span {
+ // for `|x|`, `|_|`, `|x: impl Foo|`
+ let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
+ suggestion += &format!("{}: &_", pat);
+ } else {
+ // for `|x: ty|`, `|_: ty|`
+ let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
+ let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; };
+ suggestion += &format!("{}: &{}", pat, ty);
+ }
+ has_suggestion = true;
+ } else {
+ let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; };
+ // Otherwise, keep it as-is.
+ suggestion += &arg;
+ }
+ }
+ suggestion += "|";
+
+ if has_suggestion {
+ diag.span_suggestion_verbose(
+ span,
+ "consider specifying the type of the closure parameters",
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {