From d9170dc6666211902c7fbfa4f229c43cc286890c Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 11 Jul 2024 22:20:53 +0000 Subject: [PATCH 1/3] Add regression test for issue 127545 --- .../transforming-option-ref-issue-127545.rs | 6 ++++++ .../transforming-option-ref-issue-127545.stderr | 14 ++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs create mode 100644 tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs new file mode 100644 index 0000000000000..5ba58e7427581 --- /dev/null +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs @@ -0,0 +1,6 @@ +// Regression test for . +#![crate_type = "lib"] + +pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { + arg //~ ERROR 5:5: 5:8: mismatched types [E0308] +} diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr new file mode 100644 index 0000000000000..798a4da23b0d7 --- /dev/null +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:5:5 + | +LL | pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { + | -------------- expected `Option<&[i32]>` because of return type +LL | arg + | ^^^ expected `Option<&[i32]>`, found `Option<&Vec>` + | + = note: expected enum `Option<&[i32]>` + found enum `Option<&Vec>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From 872d7b82e181235bdf8842847c76592f70419b09 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 11 Jul 2024 22:15:48 +0000 Subject: [PATCH 2/3] Add suggestion for `Option<&Vec> -> Option<&[T]` --- .../src/fn_ctxt/suggestions.rs | 49 +++++++++++++------ ...ransforming-option-ref-issue-127545.stderr | 4 ++ 2 files changed, 38 insertions(+), 15 deletions(-) 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 From a776e5f922d3b39d74d4b4d3acb752ce3585a2fb Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 11 Jul 2024 05:10:20 +0000 Subject: [PATCH 3/3] Add doc for deconstruct_option_or_result --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 50c4e9d5d6076..0817ad3aed2c2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -521,6 +521,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } + /// If `ty` is `Option`, returns `T, T, None`. + /// If `ty` is `Result`, returns `T, T, Some(E, E)`. + /// Otherwise, returns `None`. fn deconstruct_option_or_result( &self, found_ty: Ty<'tcx>,