diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 2c4a0782e60..d5e1efb9663 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -17,7 +17,7 @@ use rustc_errors::{ ErrorGuaranteed, MultiSpan, Style, SuggestionStyle, }; use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; @@ -36,7 +36,7 @@ use rustc_middle::ty::{ TypeSuperFoldable, TypeVisitableExt, TypeckResults, }; use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; use std::borrow::Cow; @@ -1043,7 +1043,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; }; - let hir::def::Res::Local(hir_id) = path.res else { + let Res::Local(hir_id) = path.res else { return; }; let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else { @@ -1627,7 +1627,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind - && let hir::def::Res::Local(hir_id) = path.res + && let Res::Local(hir_id) = path.res && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id) && let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id) && let None = local.ty @@ -2047,9 +2047,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let hir::ExprKind::Path(path) = arg.kind else { return; }; - let expected_inputs = self.tcx.erase_late_bound_regions(*expected).inputs(); - let found_inputs = self.tcx.erase_late_bound_regions(*found).inputs(); - let both_tys = expected_inputs.iter().cloned().zip(found_inputs.iter().cloned()); + let expected_inputs = self.tcx.instantiate_bound_regions_with_erased(*expected).inputs(); + let found_inputs = self.tcx.instantiate_bound_regions_with_erased(*found).inputs(); + let both_tys = expected_inputs.iter().copied().zip(found_inputs.iter().copied()); let arg_expr = |infcx: &InferCtxt<'tcx>, name, expected: Ty<'tcx>, found: Ty<'tcx>| { let (expected_ty, expected_refs) = get_deref_type_and_refs(expected); @@ -2057,29 +2057,24 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if infcx.can_eq(param_env, found_ty, expected_ty) { if found_refs.len() == expected_refs.len() - && found_refs.iter().zip(expected_refs.iter()).all(|(e, f)| e == f) + && found_refs.iter().eq(expected_refs.iter()) { name } else if found_refs.len() > expected_refs.len() { - if found_refs[..found_refs.len() - expected_refs.len()] - .iter() - .zip(expected_refs.iter()) - .any(|(e, f)| e != f) - { - // The refs have different mutability. + let refs = &found_refs[..found_refs.len() - expected_refs.len()]; + if found_refs[..expected_refs.len()].iter().eq(expected_refs.iter()) { format!( - "{}*{name}", - found_refs[..found_refs.len() - expected_refs.len()] - .iter() + "{}{name}", + refs.iter() .map(|mutbl| format!("&{}", mutbl.prefix_str())) .collect::>() .join(""), ) } else { + // The refs have different mutability. format!( - "{}{name}", - found_refs[..found_refs.len() - expected_refs.len()] - .iter() + "{}*{name}", + refs.iter() .map(|mutbl| format!("&{}", mutbl.prefix_str())) .collect::>() .join(""), @@ -2108,48 +2103,52 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { format!("/* {found} */") } }; - let (closure_names, call_names): (Vec<_>, Vec<_>) = - if both_tys.clone().all(|(expected, found)| { - let (expected_ty, _) = get_deref_type_and_refs(expected); - let (found_ty, _) = get_deref_type_and_refs(found); - self.can_eq(param_env, found_ty, expected_ty) - }) && !expected_inputs.is_empty() - && expected_inputs.len() == found_inputs.len() - && let hir::QPath::Resolved(_, path) = path - && let hir::def::Res::Def(_, fn_def_id) = path.res - && let Some(node) = self.tcx.hir().get_if_local(fn_def_id) - && let Some(body_id) = node.body_id() - { - let closure = self - .tcx - .hir() - .body_param_names(body_id) - .map(|name| format!("{name}")) - .collect(); - let args = self - .tcx - .hir() - .body_param_names(body_id) - .zip(both_tys) - .map(|(name, (expected, found))| { - arg_expr(self.infcx, format!("{name}"), expected, found) - }) - .collect(); - (closure, args) - } else { - let closure_args = expected_inputs - .iter() - .enumerate() - .map(|(i, _)| format!("arg{i}")) - .collect::>(); - let call_args = both_tys - .enumerate() - .map(|(i, (expected, found))| { - arg_expr(self.infcx, format!("arg{i}"), expected, found) - }) - .collect::>(); - (closure_args, call_args) - }; + let args_have_same_underlying_type = both_tys.clone().all(|(expected, found)| { + let (expected_ty, _) = get_deref_type_and_refs(expected); + let (found_ty, _) = get_deref_type_and_refs(found); + self.can_eq(param_env, found_ty, expected_ty) + }); + let (closure_names, call_names): (Vec<_>, Vec<_>) = if args_have_same_underlying_type + && !expected_inputs.is_empty() + && expected_inputs.len() == found_inputs.len() + && let Some(typeck) = &self.typeck_results + && let Res::Def(_, fn_def_id) = typeck.qpath_res(&path, *arg_hir_id) + { + let closure: Vec<_> = self + .tcx + .fn_arg_names(fn_def_id) + .iter() + .enumerate() + .map(|(i, ident)| { + if ident.name.is_empty() || ident.name == kw::SelfLower { + format!("arg{i}") + } else { + format!("{ident}") + } + }) + .collect(); + let args = closure + .iter() + .zip(both_tys) + .map(|(name, (expected, found))| { + arg_expr(self.infcx, name.to_owned(), expected, found) + }) + .collect(); + (closure, args) + } else { + let closure_args = expected_inputs + .iter() + .enumerate() + .map(|(i, _)| format!("arg{i}")) + .collect::>(); + let call_args = both_tys + .enumerate() + .map(|(i, (expected, found))| { + arg_expr(self.infcx, format!("arg{i}"), expected, found) + }) + .collect::>(); + (closure_args, call_args) + }; let closure_names: Vec<_> = closure_names .into_iter() .zip(expected_inputs.iter()) @@ -3790,7 +3789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind - && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let hir::Path { res: Res::Local(hir_id), .. } = path && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) && let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id) && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id) @@ -4050,7 +4049,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind - && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let hir::Path { res: Res::Local(hir_id), .. } = path && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) { @@ -4664,7 +4663,7 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) { if let hir::TyKind::Path(hir::QPath::Resolved( None, - hir::Path { res: hir::def::Res::Def(_, segment_did), .. }, + hir::Path { res: Res::Def(_, segment_did), .. }, )) = t.kind { if self.param_did == *segment_did { diff --git a/tests/ui/mismatched_types/suggest-option-asderef.stderr b/tests/ui/mismatched_types/suggest-option-asderef.stderr index 6c4a143e5af..1702a7f1dec 100644 --- a/tests/ui/mismatched_types/suggest-option-asderef.stderr +++ b/tests/ui/mismatched_types/suggest-option-asderef.stderr @@ -87,8 +87,8 @@ note: required by a bound in `Option::::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL help: consider wrapping the function in a closure | -LL | let _ = produces_string().and_then(|: String| generic_ref(&)); - | ++++++++++ +++ +LL | let _ = produces_string().and_then(|arg0: String| generic_ref(&arg0)); + | ++++++++++++++ +++++++ help: consider adjusting the signature so it does not borrow its argument | LL - fn generic_ref(_: &T) -> Option<()> {