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 8e3935505095..f9a63841a70b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1758,73 +1758,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.note_conflicting_closure_bounds(cause, &mut err); - let found_args = match found.kind() { - ty::FnPtr(f) => f.inputs().skip_binder().iter(), - kind => { - span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind) - } - }; - let expected_args = match expected.kind() { - ty::FnPtr(f) => f.inputs().skip_binder().iter(), - kind => { - span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) - } - }; - if let Some(found_node) = found_node { - let fn_decl = match found_node { - Node::Expr(expr) => match &expr.kind { - hir::ExprKind::Closure(hir::Closure { fn_decl, .. }) => fn_decl, - kind => { - span_bug!(found_span, "expression must be a closure but is {:?}", kind) - } - }, - Node::Item(item) => match &item.kind { - hir::ItemKind::Fn(signature, _generics, _body) => signature.decl, - kind => { - span_bug!(found_span, "item must be a function but is {:?}", kind) - } - }, - node => { - span_bug!(found_span, "node must be a expr or item but is {:?}", node) - } - }; - - let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span); - - fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { - let mut refs = 0; - - while let ty::Ref(_, new_ty, _) = ty.kind() { - ty = *new_ty; - refs += 1; - } - - (ty, refs) - } - - for ((found_arg, expected_arg), arg_span) in - found_args.zip(expected_args).zip(arg_spans) - { - let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg); - let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); - - if found_ty == expected_ty { - let hint = if found_refs < expected_refs { - "consider borrowing here:" - } else if found_refs == expected_refs { - continue; - } else { - "consider removing the borrow:" - }; - err.span_suggestion_verbose( - arg_span, - hint, - expected_arg.to_string(), - Applicability::MaybeIncorrect, - ); - } - } + hint_missing_borrow(span, found_span, found, expected, found_node, &mut err); } err @@ -3455,6 +3390,81 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } +/// Add a hint to add a missing borrow or remove an unnecessary one. +fn hint_missing_borrow<'tcx>( + span: Span, + found_span: Span, + found: Ty<'tcx>, + expected: Ty<'tcx>, + found_node: Node<'_>, + err: &mut Diagnostic, +) { + let found_args = match found.kind() { + ty::FnPtr(f) => f.inputs().skip_binder().iter(), + kind => { + span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind) + } + }; + let expected_args = match expected.kind() { + ty::FnPtr(f) => f.inputs().skip_binder().iter(), + kind => { + span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) + } + }; + + let fn_decl = match found_node { + Node::Expr(expr) => match &expr.kind { + hir::ExprKind::Closure(hir::Closure { fn_decl, .. }) => fn_decl, + kind => { + span_bug!(found_span, "expression must be a closure but is {:?}", kind) + } + }, + Node::Item(item) => match &item.kind { + hir::ItemKind::Fn(signature, _generics, _body) => signature.decl, + kind => { + span_bug!(found_span, "item must be a function but is {:?}", kind) + } + }, + node => { + span_bug!(found_span, "node must be a expr or item but is {:?}", node) + } + }; + + let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span); + + fn get_deref_type_and_refs<'tcx>(mut ty: Ty<'tcx>) -> (Ty<'tcx>, usize) { + let mut refs = 0; + + while let ty::Ref(_, new_ty, _) = ty.kind() { + ty = *new_ty; + refs += 1; + } + + (ty, refs) + } + + for ((found_arg, expected_arg), arg_span) in found_args.zip(expected_args).zip(arg_spans) { + let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg); + let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); + + if found_ty == expected_ty { + let hint = if found_refs < expected_refs { + "consider borrowing here:" + } else if found_refs == expected_refs { + continue; + } else { + "consider removing the borrow:" + }; + err.span_suggestion_verbose( + arg_span, + hint, + expected_arg.to_string(), + Applicability::MaybeIncorrect, + ); + } + } +} + /// Collect all the returned expressions within the input expression. /// Used to point at the return spans when we want to suggest some change to them. #[derive(Default)]