diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 8d380caf91628..50c4e9d5d6076 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -466,21 +466,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { borrow_removal_span, }); return true; - } else if let Some((deref_ty, _)) = - self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1) - && self.can_eq(self.param_env, deref_ty, peeled) - && error_tys_equate_as_ref - { - let sugg = prefix_wrap(".as_deref()"); - err.subdiagnostic(errors::SuggestConvertViaMethod { - span: expr.span.shrink_to_hi(), - sugg, - expected, - found, - borrow_removal_span, - }); - return true; - } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind() + } else if let ty::Ref(_, peeled_found_ty, _) = found_ty_inner.kind() + && let ty::Adt(adt, _) = peeled_found_ty.peel_refs().kind() && self.tcx.is_lang_item(adt.did(), LangItem::String) && peeled.is_str() // `Result::map`, conversely, does not take ref of the error type. @@ -496,6 +483,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); return true; + } else { + if !error_tys_equate_as_ref { + return false; + } + let mut steps = self.autoderef(expr.span, found_ty_inner).silence_errors(); + if let Some((deref_ty, _)) = steps.nth(1) + && self.can_eq(self.param_env, deref_ty, peeled) + { + let sugg = prefix_wrap(".as_deref()"); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); + return true; + } + for (deref_ty, n_step) in steps { + if self.can_eq(self.param_env, deref_ty, peeled) { + let explicit_deref = "*".repeat(n_step); + let sugg = prefix_wrap(&format!(".map(|v| &{explicit_deref}v)")); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); + return true; + } + } } } diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 798a4da23b0d7..b7c7202113a16 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -8,6 +8,10 @@ LL | arg | = note: expected enum `Option<&[i32]>` found enum `Option<&Vec>` +help: try using `.map(|v| &**v)` to convert `Option<&Vec>` to `Option<&[i32]>` + | +LL | arg.map(|v| &**v) + | ++++++++++++++ error: aborting due to 1 previous error