diff options
| author | Michael Goulet <michael@errs.io> | 2023-05-30 18:47:50 +0000 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2023-06-08 16:30:05 +0000 |
| commit | af54d584b29e6afd7069bfdad071c43c0aa135f5 (patch) | |
| tree | 144ab1a99ce868ec48ca7d5b3e5990d12c28c3cb | |
| parent | 522ae84e0344669ee64754595dd5f04eed9f0d1c (diff) | |
| download | rust-af54d584b29e6afd7069bfdad071c43c0aa135f5.tar.gz rust-af54d584b29e6afd7069bfdad071c43c0aa135f5.zip | |
More robust as_ref/as_deref suggestions
| -rw-r--r-- | compiler/rustc_hir_typeck/messages.ftl | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/errors.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 221 | ||||
| -rw-r--r-- | compiler/rustc_infer/messages.ftl | 3 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/errors/mod.rs | 24 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/suggest.rs | 27 | ||||
| -rw-r--r-- | tests/ui/issues/issue-100605.stderr | 14 | ||||
| -rw-r--r-- | tests/ui/let-else/let-else-ref-bindings.stderr | 16 | ||||
| -rw-r--r-- | tests/ui/suggestions/as-ref.rs | 2 | ||||
| -rw-r--r-- | tests/ui/suggestions/as-ref.stderr | 32 | ||||
| -rw-r--r-- | tests/ui/typeck/issue-89856.stderr | 2 |
12 files changed, 207 insertions, 152 deletions
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index aab432eee57..4728edd837a 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -25,6 +25,8 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item hir_typeck_convert_to_str = try converting the passed type into a `&str` +hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `{$expected}` + hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private hir_typeck_expected_default_return_type = expected `()` because of default return type diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 4222205c841..20116fde661 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -327,3 +327,18 @@ pub struct CtorIsPrivate { pub span: Span, pub def: String, } + +#[derive(Subdiagnostic)] +#[suggestion( + hir_typeck_convert_using_method, + code = "{sugg}", + applicability = "machine-applicable", + style = "verbose" +)] +pub struct SuggestConvertViaMethod<'tcx> { + #[primary_span] + pub span: Span, + pub sugg: &'static str, + pub expected: Ty<'tcx>, + pub found: Ty<'tcx>, +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index e19b0664461..21a52d3eccc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,6 +1,8 @@ use super::FnCtxt; -use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing}; +use crate::errors::{ + AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing, SuggestConvertViaMethod, +}; use crate::fluent_generated as fluent; use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; @@ -275,6 +277,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { let expr = expr.peel_blocks(); + let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); + if let Some((suggestion, msg, applicability, verbose, annotation)) = self.suggest_deref_or_ref(expr, found, expected) { @@ -325,9 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } return true; - } else if self.suggest_else_fn_with_closure(err, expr, found, expected) { + } + + if self.suggest_else_fn_with_closure(err, expr, found, expected) { return true; - } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected)) + } + + if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected)) && let ty::FnDef(def_id, ..) = *found.kind() && let Some(sp) = self.tcx.hir().span_if_local(def_id) { @@ -343,97 +351,142 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(sp, format!("{descr} `{name}` defined here")); } return true; - } else if self.suggest_cast(err, expr, found, expected, expected_ty_expr) { + } + + if self.suggest_cast(err, expr, found, expected, expected_ty_expr) { return true; - } else { - let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); - if !methods.is_empty() { - let mut suggestions = methods.iter() - .filter_map(|conversion_method| { - let receiver_method_ident = expr.method_ident(); - if let Some(method_ident) = receiver_method_ident - && method_ident.name == conversion_method.name - { - return None // do not suggest code that is already there (#53348) - } + } - let method_call_list = [sym::to_vec, sym::to_string]; - let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind - && receiver_method.ident.name == sym::clone - && method_call_list.contains(&conversion_method.name) - // If receiver is `.clone()` and found type has one of those methods, - // we guess that the user wants to convert from a slice type (`&[]` or `&str`) - // to an owned type (`Vec` or `String`). These conversions clone internally, - // so we remove the user's `clone` call. - { - vec![( - receiver_method.ident.span, - conversion_method.name.to_string() - )] - } else if expr.precedence().order() - < ExprPrecedence::MethodCall.order() - { - vec![ - (expr.span.shrink_to_lo(), "(".to_string()), - (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)), - ] - } else { - vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))] - }; - let struct_pat_shorthand_field = self.maybe_get_struct_pattern_shorthand_field(expr); - if let Some(name) = struct_pat_shorthand_field { - sugg.insert( - 0, - (expr.span.shrink_to_lo(), format!("{}: ", name)), - ); - } - Some(sugg) - }) - .peekable(); - if suggestions.peek().is_some() { - err.multipart_suggestions( - "try using a conversion method", - suggestions, - Applicability::MaybeIncorrect, - ); - return true; - } - } else if let ty::Adt(found_adt, found_substs) = found.kind() - && self.tcx.is_diagnostic_item(sym::Option, found_adt.did()) - && let ty::Adt(expected_adt, expected_substs) = expected.kind() - && self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) - && let ty::Ref(_, inner_ty, _) = expected_substs.type_at(0).kind() - && inner_ty.is_str() - { - let ty = found_substs.type_at(0); - let mut peeled = ty; - let mut ref_cnt = 0; - while let ty::Ref(_, inner, _) = peeled.kind() { - peeled = *inner; - ref_cnt += 1; - } - if let ty::Adt(adt, _) = peeled.kind() - && Some(adt.did()) == self.tcx.lang_items().string() - { - let sugg = if ref_cnt == 0 { - ".as_deref()" + if !methods.is_empty() { + let mut suggestions = methods + .iter() + .filter_map(|conversion_method| { + let receiver_method_ident = expr.method_ident(); + if let Some(method_ident) = receiver_method_ident + && method_ident.name == conversion_method.name + { + return None // do not suggest code that is already there (#53348) + } + + let method_call_list = [sym::to_vec, sym::to_string]; + let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind + && receiver_method.ident.name == sym::clone + && method_call_list.contains(&conversion_method.name) + // If receiver is `.clone()` and found type has one of those methods, + // we guess that the user wants to convert from a slice type (`&[]` or `&str`) + // to an owned type (`Vec` or `String`). These conversions clone internally, + // so we remove the user's `clone` call. + { + vec![( + receiver_method.ident.span, + conversion_method.name.to_string() + )] + } else if expr.precedence().order() + < ExprPrecedence::MethodCall.order() + { + vec![ + (expr.span.shrink_to_lo(), "(".to_string()), + (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)), + ] } else { - ".map(|x| x.as_str())" + vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))] }; - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - fluent::hir_typeck_convert_to_str, - sugg, - Applicability::MachineApplicable, - ); - return true; - } + let struct_pat_shorthand_field = + self.maybe_get_struct_pattern_shorthand_field(expr); + if let Some(name) = struct_pat_shorthand_field { + sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name))); + } + Some(sugg) + }) + .peekable(); + if suggestions.peek().is_some() { + err.multipart_suggestions( + "try using a conversion method", + suggestions, + Applicability::MaybeIncorrect, + ); + return true; + } + } + + if let Some((found_ty_inner, expected_ty_inner, error_tys)) = + self.deconstruct_option_or_result(found, expected) + && let ty::Ref(_, peeled, hir::Mutability::Not) = *expected_ty_inner.kind() + { + // Check that given `Result<_, E>`, our expected ty is `Result<_, &E>` + let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| { + self.can_eq(self.param_env, self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, found), expected) + }); + // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`, + // but those checks need to be a bit more delicate and the benefit is diminishing. + if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref { + err.subdiagnostic(SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg: ".as_ref()", + expected, + found, + }); + 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 + { + err.subdiagnostic(SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg: ".as_deref()", + expected, + found, + }); + return true; + } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind() + && Some(adt.did()) == self.tcx.lang_items().string() + && peeled.is_str() + && error_tys.map_or(true, |(found, expected)| { + self.can_eq(self.param_env, found, expected) + }) + { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + fluent::hir_typeck_convert_to_str, + ".map(|x| x.as_str())", + Applicability::MachineApplicable, + ); + return true; } } false } + fn deconstruct_option_or_result( + &self, + found_ty: Ty<'tcx>, + expected_ty: Ty<'tcx>, + ) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)> { + let ty::Adt(found_adt, found_substs) = found_ty.peel_refs().kind() else { + return None; + }; + let ty::Adt(expected_adt, expected_substs) = expected_ty.kind() else { + return None; + }; + if self.tcx.is_diagnostic_item(sym::Option, found_adt.did()) + && self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) + { + Some((found_substs.type_at(0), expected_substs.type_at(0), None)) + } else if self.tcx.is_diagnostic_item(sym::Result, found_adt.did()) + && self.tcx.is_diagnostic_item(sym::Result, expected_adt.did()) + { + Some(( + found_substs.type_at(0), + expected_substs.type_at(0), + Some((found_substs.type_at(1), expected_substs.type_at(1))), + )) + } else { + None + } + } + /// When encountering the expected boxed value allocated in the stack, suggest allocating it /// in the heap by calling `Box::new()`. pub(in super::super) fn suggest_boxing_when_appropriate( diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index f44c4a7c1e3..4d0e7706367 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -278,9 +278,6 @@ infer_ril_introduced_by = requirement introduced by this return type infer_ril_introduced_here = `'static` requirement introduced here infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type -infer_sarwa_option = you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()` -infer_sarwa_result = you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()` - infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index b1e819e83f1..7e1fa08f23a 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1247,30 +1247,6 @@ pub struct FnConsiderCasting { } #[derive(Subdiagnostic)] -pub enum SuggestAsRefWhereAppropriate<'a> { - #[suggestion( - infer_sarwa_option, - code = "{snippet}.as_ref()", - applicability = "machine-applicable" - )] - Option { - #[primary_span] - span: Span, - snippet: &'a str, - }, - #[suggestion( - infer_sarwa_result, - code = "{snippet}.as_ref()", - applicability = "machine-applicable" - )] - Result { - #[primary_span] - span: Span, - snippet: &'a str, - }, -} - -#[derive(Subdiagnostic)] pub enum SuggestAccessingField<'a> { #[suggestion( infer_suggest_accessing_field, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index f8a253c8949..ce5b5882e3b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1897,7 +1897,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if should_suggest_fixes { self.suggest_tuple_pattern(cause, &exp_found, diag); - self.suggest_as_ref_where_appropriate(span, &exp_found, diag); self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag); self.suggest_await_on_expect_found(cause, span, &exp_found, diag); self.suggest_function_pointers(cause, span, &exp_found, diag); diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index d885d040707..1422bdc9ea2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -13,9 +13,9 @@ use rustc_span::{sym, BytePos, Span}; use crate::errors::{ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, - FunctionPointerSuggestion, SuggestAccessingField, SuggestAsRefWhereAppropriate, - SuggestBoxingForReturnImplTrait, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, - SuggestTuplePatternOne, TypeErrorAdditionalDiags, + FunctionPointerSuggestion, SuggestAccessingField, SuggestBoxingForReturnImplTrait, + SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, SuggestTuplePatternOne, + TypeErrorAdditionalDiags, }; use super::TypeErrCtxt; @@ -289,27 +289,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate, - /// suggests it. - pub(super) fn suggest_as_ref_where_appropriate( - &self, - span: Span, - exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - diag: &mut Diagnostic, - ) { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) - && let Some(msg) = self.should_suggest_as_ref_kind(exp_found.expected, exp_found.found) - { - // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&` - let snippet = snippet.trim_start_matches('&'); - let subdiag = match msg { - SuggestAsRefKind::Option => SuggestAsRefWhereAppropriate::Option { span, snippet }, - SuggestAsRefKind::Result => SuggestAsRefWhereAppropriate::Result { span, snippet }, - }; - diag.subdiagnostic(subdiag); - } - } - pub(super) fn suggest_function_pointers( &self, cause: &ObligationCause<'tcx>, diff --git a/tests/ui/issues/issue-100605.stderr b/tests/ui/issues/issue-100605.stderr index be30eef2af4..e4fc5cb367c 100644 --- a/tests/ui/issues/issue-100605.stderr +++ b/tests/ui/issues/issue-100605.stderr @@ -13,10 +13,6 @@ note: function defined here | LL | fn takes_option(_arg: Option<&String>) {} | ^^^^^^^^^^^^ --------------------- -help: you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()` - | -LL | takes_option(None.as_ref()); - | ~~~~~~~~~~~~~ help: consider removing the borrow | LL - takes_option(&None); @@ -27,10 +23,8 @@ error[E0308]: mismatched types --> $DIR/issue-100605.rs:8:18 | LL | takes_option(&res); - | ------------ ^^^^ - | | | - | | expected `Option<&String>`, found `&Option<String>` - | | help: you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`: `res.as_ref()` + | ------------ ^^^^ expected `Option<&String>`, found `&Option<String>` + | | | arguments to this function are incorrect | = note: expected enum `Option<&String>` @@ -40,6 +34,10 @@ note: function defined here | LL | fn takes_option(_arg: Option<&String>) {} | ^^^^^^^^^^^^ --------------------- +help: try using `.as_ref()` to convert `&Option<String>` to `Option<&String>` + | +LL | takes_option(&res.as_ref()); + | +++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/let-else/let-else-ref-bindings.stderr b/tests/ui/let-else/let-else-ref-bindings.stderr index ada1805e725..7093b5fa9af 100644 --- a/tests/ui/let-else/let-else-ref-bindings.stderr +++ b/tests/ui/let-else/let-else-ref-bindings.stderr @@ -6,6 +6,10 @@ LL | let Some(ref a): Option<&[u8]> = some else { return }; | = note: expected enum `Option<&[u8]>` found enum `Option<Vec<u8>>` +help: try using `.as_deref()` to convert `Option<Vec<u8>>` to `Option<&[u8]>` + | +LL | let Some(ref a): Option<&[u8]> = some.as_deref() else { return }; + | +++++++++++ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:20:38 @@ -15,6 +19,10 @@ LL | let Some(ref a): Option<&[u8]> = &some else { return }; | = note: expected enum `Option<&[u8]>` found reference `&Option<Vec<u8>>` +help: try using `.as_deref()` to convert `&Option<Vec<u8>>` to `Option<&[u8]>` + | +LL | let Some(ref a): Option<&[u8]> = &some.as_deref() else { return }; + | +++++++++++ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:24:34 @@ -26,6 +34,10 @@ LL | let Some(a): Option<&[u8]> = some else { return }; | = note: expected enum `Option<&[u8]>` found enum `Option<Vec<u8>>` +help: try using `.as_deref()` to convert `Option<Vec<u8>>` to `Option<&[u8]>` + | +LL | let Some(a): Option<&[u8]> = some.as_deref() else { return }; + | +++++++++++ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:27:34 @@ -37,6 +49,10 @@ LL | let Some(a): Option<&[u8]> = &some else { return }; | = note: expected enum `Option<&[u8]>` found reference `&Option<Vec<u8>>` +help: try using `.as_deref()` to convert `&Option<Vec<u8>>` to `Option<&[u8]>` + | +LL | let Some(a): Option<&[u8]> = &some.as_deref() else { return }; + | +++++++++++ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:44:46 diff --git a/tests/ui/suggestions/as-ref.rs b/tests/ui/suggestions/as-ref.rs index a0535344185..0d9790ac229 100644 --- a/tests/ui/suggestions/as-ref.rs +++ b/tests/ui/suggestions/as-ref.rs @@ -24,4 +24,6 @@ fn main() { let multiple_ref_result = &&Ok(Foo); multiple_ref_result.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308] multiple_ref_result.and_then(|arg| Ok(takes_ref(arg))); //~ ERROR mismatched types [E0308] + + let _: Result<&usize, _> = &Ok(42); //~ ERROR mismatched types [E0308] } diff --git a/tests/ui/suggestions/as-ref.stderr b/tests/ui/suggestions/as-ref.stderr index 2147d2d92e3..c5b2bb1260f 100644 --- a/tests/ui/suggestions/as-ref.stderr +++ b/tests/ui/suggestions/as-ref.stderr @@ -74,14 +74,16 @@ error[E0308]: mismatched types --> $DIR/as-ref.rs:13:29 | LL | let y: Option<&usize> = x; - | -------------- ^ - | | | - | | expected `Option<&usize>`, found `&Option<usize>` - | | help: you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`: `x.as_ref()` + | -------------- ^ expected `Option<&usize>`, found `&Option<usize>` + | | | expected due to this | = note: expected enum `Option<&usize>` found reference `&Option<usize>` +help: try using `.as_ref()` to convert `&Option<usize>` to `Option<&usize>` + | +LL | let y: Option<&usize> = x.as_ref(); + | +++++++++ error[E0308]: mismatched types --> $DIR/as-ref.rs:15:37 @@ -93,10 +95,10 @@ LL | let y: Result<&usize, &usize> = x; | = note: expected enum `Result<&usize, &usize>` found reference `&Result<usize, usize>` -help: you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()` +help: try using `.as_ref()` to convert `&Result<usize, usize>` to `Result<&usize, &usize>` | LL | let y: Result<&usize, &usize> = x.as_ref(); - | ~~~~~~~~~~ + | +++++++++ error[E0308]: mismatched types --> $DIR/as-ref.rs:19:36 @@ -181,6 +183,22 @@ help: consider using `as_ref` instead LL | multiple_ref_result.as_ref().and_then(|arg| Ok(takes_ref(arg))); | +++++++++ -error: aborting due to 11 previous errors +error[E0308]: mismatched types + --> $DIR/as-ref.rs:28:32 + | +LL | let _: Result<&usize, _> = &Ok(42); + | ----------------- ^^^^^^^ expected `Result<&usize, _>`, found `&Result<{integer}, _>` + | | + | expected due to this + | + = note: expected enum `Result<&usize, _>` + found reference `&Result<{integer}, _>` +help: try using `.as_ref()` to convert `&Result<{integer}, _>` to `Result<&usize, _>` + | +LL - let _: Result<&usize, _> = &Ok(42); +LL + let _: Result<&usize, _> = Ok(42).as_ref(); + | + +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/issue-89856.stderr b/tests/ui/typeck/issue-89856.stderr index bd76f172468..0db3e67ede0 100644 --- a/tests/ui/typeck/issue-89856.stderr +++ b/tests/ui/typeck/issue-89856.stderr @@ -13,7 +13,7 @@ note: function defined here | LL | fn take_str_maybe(_: Option<&str>) { } | ^^^^^^^^^^^^^^ --------------- -help: try converting the passed type into a `&str` +help: try using `.as_deref()` to convert `Option<String>` to `Option<&str>` | LL | take_str_maybe(option.as_deref()); | +++++++++++ |
