diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 357033a9e183b..2e795d84559c3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2025,6 +2025,22 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { } } +/// Checks if the specified expression needs parentheses for prefix +/// or postfix suggestions to be valid. +/// For example, `a + b` requires parentheses to suggest `&(a + b)`, +/// but just `a` does not. +/// Similarly, `(a + b).c()` also requires parentheses. +/// This should not be used for other types of suggestions. +pub fn expr_needs_parens(expr: &Expr<'_>) -> bool { + match expr.kind { + // parenthesize if needed (Issue #46756) + ExprKind::Cast(_, _) | ExprKind::Binary(_, _, _) => true, + // parenthesize borrows of range literals (Issue #54505) + _ if is_range_literal(expr) => true, + _ => false, + } +} + #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ExprKind<'hir> { /// Allow anonymous constants from an inline `const` block diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index ddcd90a2a9da6..21b1768ae6f4d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -10,7 +10,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, - Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind, + Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind, expr_needs_parens, }; use rustc_hir_analysis::collect::suggest_impl_trait; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; @@ -35,7 +35,6 @@ use tracing::{debug, instrument}; use super::FnCtxt; use crate::fn_ctxt::rustc_span::BytePos; -use crate::hir::is_range_literal; use crate::method::probe; use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use crate::{errors, fluent_generated as fluent}; @@ -2648,7 +2647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| { - if self.needs_parentheses(expr) { + if expr_needs_parens(expr) { ( vec![ (span.shrink_to_lo(), format!("{prefix}{sugg}(")), @@ -2861,7 +2860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } - if self.needs_parentheses(expr) { + if expr_needs_parens(expr) { return Some(( vec![ (span, format!("{suggestion}(")), @@ -2902,16 +2901,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn needs_parentheses(&self, expr: &hir::Expr<'_>) -> bool { - match expr.kind { - // parenthesize if needed (Issue #46756) - hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, - // parenthesize borrows of range literals (Issue #54505) - _ if is_range_literal(expr) => true, - _ => false, - } - } - pub(crate) fn suggest_cast( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 2a8ed26aa2bee..e7726845652f3 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -10,8 +10,12 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::{self as hir, BindingMode, ByRef, HirId, LangItem, Mutability, Pat, PatKind}; +use rustc_hir::{ + self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatKind, + expr_needs_parens, +}; use rustc_infer::infer; +use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; @@ -94,10 +98,32 @@ struct PatInfo<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> { + // If origin_expr exists, then expected represents the type of origin_expr. + // If span also exists, then span == origin_expr.span (although it doesn't need to exist). + // In that case, we can peel away references from both and treat them + // as the same. + let origin_expr_info = ti.origin_expr.map(|mut cur_expr| { + let mut count = 0; + + // cur_ty may have more layers of references than cur_expr. + // We can only make suggestions about cur_expr, however, so we'll + // use that as our condition for stopping. + while let ExprKind::AddrOf(.., inner) = &cur_expr.kind { + cur_expr = inner; + count += 1; + } + + PatternOriginExpr { + peeled_span: cur_expr.span, + peeled_count: count, + peeled_prefix_suggestion_parentheses: expr_needs_parens(cur_expr), + } + }); + let code = ObligationCauseCode::Pattern { span: ti.span, root_ty: ti.expected, - origin_expr: ti.origin_expr.is_some(), + origin_expr: origin_expr_info, }; self.cause(cause_span, code) } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 0a77c3bc42fb9..8c434265d2764 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -316,8 +316,8 @@ pub enum ObligationCauseCode<'tcx> { span: Option, /// The root expected type induced by a scrutinee or type expression. root_ty: Ty<'tcx>, - /// Whether the `Span` came from an expression or a type expression. - origin_expr: bool, + /// Information about the `Span`, if it came from an expression, otherwise `None`. + origin_expr: Option, }, /// Computing common supertype in an if expression @@ -530,6 +530,25 @@ pub struct MatchExpressionArmCause<'tcx> { pub tail_defines_return_position_impl_trait: Option, } +/// Information about the origin expression of a pattern, relevant to diagnostics. +/// Fields here refer to the scrutinee of a pattern. +/// If the scrutinee isn't given in the diagnostic, then this won't exist. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] +pub struct PatternOriginExpr { + /// A span representing the scrutinee expression, with all leading references + /// peeled from the expression. + /// Only references in the expression are peeled - if the expression refers to a variable + /// whose type is a reference, then that reference is kept because it wasn't created + /// in the expression. + pub peeled_span: Span, + /// The number of references that were peeled to produce `peeled_span`. + pub peeled_count: usize, + /// Does the peeled expression need to be wrapped in parentheses for + /// a prefix suggestion (i.e., dereference) to be valid. + pub peeled_prefix_suggestion_parentheses: bool, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct IfExpressionCause<'tcx> { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index f856a8d7abbe7..5a62a4c3bd5fe 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -63,10 +63,11 @@ use rustc_hir::{self as hir}; use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; +use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt}; use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, with_forced_trimmed_paths}; use rustc_middle::ty::{ - self, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, + self, List, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; use rustc_span::def_id::LOCAL_CRATE; @@ -77,7 +78,7 @@ use crate::error_reporting::TypeErrCtxt; use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags}; use crate::infer; use crate::infer::relate::{self, RelateResult, TypeRelation}; -use crate::infer::{InferCtxt, TypeTrace, ValuePairs}; +use crate::infer::{InferCtxt, InferCtxtExt as _, TypeTrace, ValuePairs}; use crate::solve::deeply_normalize_for_diagnostics; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, @@ -433,15 +434,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, exp_found: Option>>, terr: TypeError<'tcx>, + param_env: Option>, ) { match *cause.code() { - ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { - let ty = self.resolve_vars_if_possible(root_ty); - if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_))) - { + ObligationCauseCode::Pattern { + origin_expr: Some(origin_expr), + span: Some(span), + root_ty, + } => { + let expected_ty = self.resolve_vars_if_possible(root_ty); + if !matches!( + expected_ty.kind(), + ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)) + ) { // don't show type `_` if span.desugaring_kind() == Some(DesugaringKind::ForLoop) - && let ty::Adt(def, args) = ty.kind() + && let ty::Adt(def, args) = expected_ty.kind() && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option) { err.span_label( @@ -449,22 +457,48 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("this is an iterator with items of type `{}`", args.type_at(0)), ); } else { - err.span_label(span, format!("this expression has type `{ty}`")); + err.span_label(span, format!("this expression has type `{expected_ty}`")); } } if let Some(ty::error::ExpectedFound { found, .. }) = exp_found - && ty.boxed_ty() == Some(found) - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + && let Ok(mut peeled_snippet) = + self.tcx.sess.source_map().span_to_snippet(origin_expr.peeled_span) { - err.span_suggestion( - span, - "consider dereferencing the boxed value", - format!("*{snippet}"), - Applicability::MachineApplicable, - ); + // Parentheses are needed for cases like as casts. + // We use the peeled_span for deref suggestions. + // It's also safe to use for box, since box only triggers if there + // wasn't a reference to begin with. + if origin_expr.peeled_prefix_suggestion_parentheses { + peeled_snippet = format!("({peeled_snippet})"); + } + + // Try giving a box suggestion first, as it is a special case of the + // deref suggestion. + if expected_ty.boxed_ty() == Some(found) { + err.span_suggestion_verbose( + span, + "consider dereferencing the boxed value", + format!("*{peeled_snippet}"), + Applicability::MachineApplicable, + ); + } else if let Some(param_env) = param_env + && let Some(prefix) = self.should_deref_suggestion_on_mismatch( + param_env, + found, + expected_ty, + origin_expr, + ) + { + err.span_suggestion_verbose( + span, + "consider dereferencing to access the inner value using the Deref trait", + format!("{prefix}{peeled_snippet}"), + Applicability::MaybeIncorrect, + ); + } } } - ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => { + ObligationCauseCode::Pattern { origin_expr: None, span: Some(span), .. } => { err.span_label(span, "expected due to this"); } ObligationCauseCode::BlockTailExpression( @@ -618,6 +652,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } + /// Determines whether deref_to == ::Target, and if so, + /// returns a prefix that should be added to deref_from as a suggestion. + fn should_deref_suggestion_on_mismatch( + &self, + param_env: ParamEnv<'tcx>, + deref_to: Ty<'tcx>, + deref_from: Ty<'tcx>, + origin_expr: PatternOriginExpr, + ) -> Option { + // origin_expr contains stripped away versions of our expression. + // We'll want to use that to avoid suggesting things like *&x. + // However, the type that we have access to hasn't been stripped away, + // so we need to ignore the first n dereferences, where n is the number + // that's been stripped away in origin_expr. + + // Find a way to autoderef from deref_from to deref_to. + let Some((num_derefs, (after_deref_ty, _))) = (self.autoderef_steps)(deref_from) + .into_iter() + .enumerate() + .find(|(_, (ty, _))| self.infcx.can_eq(param_env, *ty, deref_to)) + else { + return None; + }; + + if num_derefs <= origin_expr.peeled_count { + return None; + } + + let deref_part = "*".repeat(num_derefs - origin_expr.peeled_count); + + // If the user used a reference in the original expression, they probably + // want the suggestion to still give a reference. + if deref_from.is_ref() && !after_deref_ty.is_ref() { + Some(format!("&{deref_part}")) + } else { + Some(deref_part) + } + } + /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and /// populate `other_value` with `other_ty`. @@ -1406,8 +1479,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Variable(ty::error::ExpectedFound>), Fixed(&'static str), } - let (expected_found, exp_found, is_simple_error, values) = match values { - None => (None, Mismatch::Fixed("type"), false, None), + let (expected_found, exp_found, is_simple_error, values, param_env) = match values { + None => (None, Mismatch::Fixed("type"), false, None, None), Some(ty::ParamEnvAnd { param_env, value: values }) => { let mut values = self.resolve_vars_if_possible(values); if self.next_trait_solver() { @@ -1459,7 +1532,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { diag.downgrade_to_delayed_bug(); return; }; - (Some(vals), exp_found, is_simple_error, Some(values)) + (Some(vals), exp_found, is_simple_error, Some(values), Some(param_env)) } }; @@ -1791,7 +1864,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // It reads better to have the error origin as the final // thing. - self.note_error_origin(diag, cause, exp_found, terr); + self.note_error_origin(diag, cause, exp_found, terr, param_env); debug!(?diag); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index fc2d0ba36f04e..08775df5ac99a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -210,7 +210,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code() { ObligationCauseCode::Pattern { span: Some(then_span), origin_expr, .. } => { - origin_expr.then_some(ConsiderAddingAwait::FutureSugg { + origin_expr.is_some().then_some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi(), }) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 94682f501a8c4..cc8941b92242d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -20,7 +20,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ - CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node, is_range_literal, + CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node, expr_needs_parens, + is_range_literal, }; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_middle::hir::map; @@ -1391,13 +1392,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let Some(expr) = expr_finder.result else { return false; }; - let needs_parens = match expr.kind { - // parenthesize if needed (Issue #46756) - hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, - // parenthesize borrows of range literals (Issue #54505) - _ if is_range_literal(expr) => true, - _ => false, - }; + let needs_parens = expr_needs_parens(expr); let span = if needs_parens { span } else { span.shrink_to_lo() }; let suggestions = if !needs_parens { diff --git a/tests/ui/closures/2229_closure_analysis/issue-118144.stderr b/tests/ui/closures/2229_closure_analysis/issue-118144.stderr index 85cb5adc07e90..87084e6023729 100644 --- a/tests/ui/closures/2229_closure_analysis/issue-118144.stderr +++ b/tests/ui/closures/2229_closure_analysis/issue-118144.stderr @@ -5,6 +5,11 @@ LL | V(x) = func_arg; | ^^^^ -------- this expression has type `&mut V` | | | expected `&mut V`, found `V` + | +help: consider dereferencing to access the inner value using the Deref trait + | +LL | V(x) = &*func_arg; + | ~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr b/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr index 38014ecce7574..3c19b68cffbb3 100644 --- a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr +++ b/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr @@ -2,57 +2,61 @@ error[E0308]: mismatched types --> $DIR/issue-57741.rs:20:9 | LL | let y = match x { - | - - | | - | this expression has type `Box` - | help: consider dereferencing the boxed value: `*x` + | - this expression has type `Box` LL | T::A(a) | T::B(a) => a, | ^^^^^^^ expected `Box`, found `T` | = note: expected struct `Box` found enum `T` +help: consider dereferencing the boxed value + | +LL | let y = match *x { + | ~~ error[E0308]: mismatched types --> $DIR/issue-57741.rs:20:19 | LL | let y = match x { - | - - | | - | this expression has type `Box` - | help: consider dereferencing the boxed value: `*x` + | - this expression has type `Box` LL | T::A(a) | T::B(a) => a, | ^^^^^^^ expected `Box`, found `T` | = note: expected struct `Box` found enum `T` +help: consider dereferencing the boxed value + | +LL | let y = match *x { + | ~~ error[E0308]: mismatched types --> $DIR/issue-57741.rs:27:9 | LL | let y = match x { - | - - | | - | this expression has type `Box` - | help: consider dereferencing the boxed value: `*x` + | - this expression has type `Box` LL | S::A { a } | S::B { b: a } => a, | ^^^^^^^^^^ expected `Box`, found `S` | = note: expected struct `Box` found enum `S` +help: consider dereferencing the boxed value + | +LL | let y = match *x { + | ~~ error[E0308]: mismatched types --> $DIR/issue-57741.rs:27:22 | LL | let y = match x { - | - - | | - | this expression has type `Box` - | help: consider dereferencing the boxed value: `*x` + | - this expression has type `Box` LL | S::A { a } | S::B { b: a } => a, | ^^^^^^^^^^^^^ expected `Box`, found `S` | = note: expected struct `Box` found enum `S` +help: consider dereferencing the boxed value + | +LL | let y = match *x { + | ~~ error: aborting due to 4 previous errors diff --git a/tests/ui/let-else/let-else-deref-coercion.stderr b/tests/ui/let-else/let-else-deref-coercion.stderr index 143b838bac500..da8b1f4c48e97 100644 --- a/tests/ui/let-else/let-else-deref-coercion.stderr +++ b/tests/ui/let-else/let-else-deref-coercion.stderr @@ -5,6 +5,11 @@ LL | let Bar::Present(z) = self else { | ^^^^^^^^^^^^^^^ ---- this expression has type `&mut Foo` | | | expected `Foo`, found `Bar` + | +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Bar::Present(z) = &**self else { + | ~~~~~~~ error[E0308]: mismatched types --> $DIR/let-else-deref-coercion.rs:68:13 @@ -13,6 +18,11 @@ LL | let Bar(z) = x; | ^^^^^^ - this expression has type `&mut irrefutable::Foo` | | | expected `Foo`, found `Bar` + | +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Bar(z) = &**x; + | ~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs new file mode 100644 index 0000000000000..205e57f4a9ff5 --- /dev/null +++ b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs @@ -0,0 +1,84 @@ +use std::sync::Arc; +fn main() { + let mut x = Arc::new(Some(1)); + match x { + //~^ HELP consider dereferencing to access the inner value using the Deref trait + //~| HELP consider dereferencing to access the inner value using the Deref trait + Some(_) => {} + //~^ ERROR mismatched types + None => {} + //~^ ERROR mismatched types + } + + match &x { + //~^ HELP consider dereferencing to access the inner value using the Deref trait + //~| HELP consider dereferencing to access the inner value using the Deref trait + Some(_) => {} + //~^ ERROR mismatched types + None => {} + //~^ ERROR mismatched types + } + + let mut y = Box::new(Some(1)); + match y { + //~^ HELP consider dereferencing to access the inner value using the Deref trait + //~| HELP consider dereferencing to access the inner value using the Deref trait + Some(_) => {} + //~^ ERROR mismatched types + None => {} + //~^ ERROR mismatched types + } + + let mut z = Arc::new(Some(1)); + match z as Arc> { + //~^ HELP consider dereferencing to access the inner value using the Deref trait + //~| HELP consider dereferencing to access the inner value using the Deref trait + Some(_) => {} + //~^ ERROR mismatched types + None => {} + //~^ ERROR mismatched types + } + + let z_const: &Arc> = &z; + match z_const { + //~^ HELP consider dereferencing to access the inner value using the Deref trait + //~| HELP consider dereferencing to access the inner value using the Deref trait + Some(_) => {} + //~^ ERROR mismatched types + None => {} + //~^ ERROR mismatched types + } + + // Normal reference because Arc doesn't implement DerefMut. + let z_mut: &mut Arc> = &mut z; + match z_mut { + //~^ HELP consider dereferencing to access the inner value using the Deref trait + //~| HELP consider dereferencing to access the inner value using the Deref trait + Some(_) => {} + //~^ ERROR mismatched types + None => {} + //~^ ERROR mismatched types + } + + // Mutable reference because Box does implement DerefMut. + let y_mut: &mut Box> = &mut y; + match y_mut { + //~^ HELP consider dereferencing to access the inner value using the Deref trait + //~| HELP consider dereferencing to access the inner value using the Deref trait + Some(_) => {} + //~^ ERROR mismatched types + None => {} + //~^ ERROR mismatched types + } + + // Difficult expression. + let difficult = Arc::new(Some(1)); + match (& (&difficult) ) { + //~^ HELP consider dereferencing to access the inner value using the Deref trait + //~| HELP consider dereferencing to access the inner value using the Deref trait + Some(_) => {} + //~^ ERROR mismatched types + None => {} + //~^ ERROR mismatched types + } +} diff --git a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr new file mode 100644 index 0000000000000..9338ef1908943 --- /dev/null +++ b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr @@ -0,0 +1,259 @@ +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:7:9 + | +LL | match x { + | - this expression has type `Arc>` +... +LL | Some(_) => {} + | ^^^^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *x { + | ~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:9:9 + | +LL | match x { + | - this expression has type `Arc>` +... +LL | None => {} + | ^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *x { + | ~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:16:9 + | +LL | match &x { + | -- this expression has type `&Arc>` +... +LL | Some(_) => {} + | ^^^^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &*x { + | ~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:18:9 + | +LL | match &x { + | -- this expression has type `&Arc>` +... +LL | None => {} + | ^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &*x { + | ~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:26:9 + | +LL | match y { + | - this expression has type `Box>` +... +LL | Some(_) => {} + | ^^^^^^^ expected `Box>`, found `Option<_>` + | + = note: expected struct `Box>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *y { + | ~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:28:9 + | +LL | match y { + | - this expression has type `Box>` +... +LL | None => {} + | ^^^^ expected `Box>`, found `Option<_>` + | + = note: expected struct `Box>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *y { + | ~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:36:9 + | +LL | match z as Arc> { + | --------------------- this expression has type `Arc>` +... +LL | Some(_) => {} + | ^^^^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *(z as Arc>) { + | ~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:38:9 + | +LL | match z as Arc> { + | --------------------- this expression has type `Arc>` +... +LL | None => {} + | ^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *(z as Arc>) { + | ~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:46:9 + | +LL | match z_const { + | ------- this expression has type `&Arc>` +... +LL | Some(_) => {} + | ^^^^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &**z_const { + | ~~~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:48:9 + | +LL | match z_const { + | ------- this expression has type `&Arc>` +... +LL | None => {} + | ^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &**z_const { + | ~~~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:57:9 + | +LL | match z_mut { + | ----- this expression has type `&mut Arc>` +... +LL | Some(_) => {} + | ^^^^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &**z_mut { + | ~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:59:9 + | +LL | match z_mut { + | ----- this expression has type `&mut Arc>` +... +LL | None => {} + | ^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &**z_mut { + | ~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:68:9 + | +LL | match y_mut { + | ----- this expression has type `&mut Box>` +... +LL | Some(_) => {} + | ^^^^^^^ expected `Box>`, found `Option<_>` + | + = note: expected struct `Box>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &**y_mut { + | ~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:70:9 + | +LL | match y_mut { + | ----- this expression has type `&mut Box>` +... +LL | None => {} + | ^^^^ expected `Box>`, found `Option<_>` + | + = note: expected struct `Box>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &**y_mut { + | ~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:79:9 + | +LL | match (& (&difficult) ) { + | ------------------ this expression has type `&&Arc>` +... +LL | Some(_) => {} + | ^^^^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &*difficult { + | ~~~~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/suggest-deref-in-match-issue-132784.rs:81:9 + | +LL | match (& (&difficult) ) { + | ------------------ this expression has type `&&Arc>` +... +LL | None => {} + | ^^^^ expected `Arc>`, found `Option<_>` + | + = note: expected struct `Arc>` + found enum `Option<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match &*difficult { + | ~~~~~~~~~~~ + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0308`.