diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_infer/src/infer/error_reporting | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-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')
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> { |