Rollup merge of #132939 - uellenberg:suggest-deref, r=oli-obk
Suggest using deref in patterns Fixes #132784 This changes the following code: ```rs use std::sync::Arc; fn main() { let mut x = Arc::new(Some(1)); match x { Some(_) => {} None => {} } } ``` to output ```rs error[E0308]: mismatched types --> src/main.rs:5:9 | LL | match x { | - this expression has type `Arc<Option<{integer}>>` ... LL | Some(_) => {} | ^^^^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>` | = note: expected struct `Arc<Option<{integer}>>` found enum `Option<_>` help: consider dereferencing to access the inner value using the Deref trait | LL | match *x { | ~~ ``` instead of ```rs error[E0308]: mismatched types --> src/main.rs:5:9 | 4 | match x { | - this expression has type `Arc<Option<{integer}>>` 5 | Some(_) => {} | ^^^^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>` | = note: expected struct `Arc<Option<{integer}>>` found enum `Option<_>` ``` This makes it more obvious that a Deref is available, and gives a suggestion on how to use it in order to fix the issue at hand.
This commit is contained in:
commit
db77788dc5
12 changed files with 544 additions and 64 deletions
|
@ -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
|
||||
|
|
|
@ -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<'_>,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -316,8 +316,8 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
span: Option<Span>,
|
||||
/// 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<PatternOriginExpr>,
|
||||
},
|
||||
|
||||
/// Computing common supertype in an if expression
|
||||
|
@ -530,6 +530,25 @@ pub struct MatchExpressionArmCause<'tcx> {
|
|||
pub tail_defines_return_position_impl_trait: Option<LocalDefId>,
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
|
|
|
@ -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<ty::error::ExpectedFound<Ty<'tcx>>>,
|
||||
terr: TypeError<'tcx>,
|
||||
param_env: Option<ParamEnv<'tcx>>,
|
||||
) {
|
||||
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(
|
||||
// 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!("*{snippet}"),
|
||||
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 == <deref_from as Deref>::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<String> {
|
||||
// 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<Ty<'a>>),
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -2,57 +2,61 @@ error[E0308]: mismatched types
|
|||
--> $DIR/issue-57741.rs:20:9
|
||||
|
|
||||
LL | let y = match x {
|
||||
| -
|
||||
| |
|
||||
| this expression has type `Box<T>`
|
||||
| help: consider dereferencing the boxed value: `*x`
|
||||
| - this expression has type `Box<T>`
|
||||
LL | T::A(a) | T::B(a) => a,
|
||||
| ^^^^^^^ expected `Box<T>`, found `T`
|
||||
|
|
||||
= note: expected struct `Box<T>`
|
||||
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<T>`
|
||||
| help: consider dereferencing the boxed value: `*x`
|
||||
| - this expression has type `Box<T>`
|
||||
LL | T::A(a) | T::B(a) => a,
|
||||
| ^^^^^^^ expected `Box<T>`, found `T`
|
||||
|
|
||||
= note: expected struct `Box<T>`
|
||||
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<S>`
|
||||
| help: consider dereferencing the boxed value: `*x`
|
||||
| - this expression has type `Box<S>`
|
||||
LL | S::A { a } | S::B { b: a } => a,
|
||||
| ^^^^^^^^^^ expected `Box<S>`, found `S`
|
||||
|
|
||||
= note: expected struct `Box<S>`
|
||||
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<S>`
|
||||
| help: consider dereferencing the boxed value: `*x`
|
||||
| - this expression has type `Box<S>`
|
||||
LL | S::A { a } | S::B { b: a } => a,
|
||||
| ^^^^^^^^^^^^^ expected `Box<S>`, found `S`
|
||||
|
|
||||
= note: expected struct `Box<S>`
|
||||
found enum `S`
|
||||
help: consider dereferencing the boxed value
|
||||
|
|
||||
LL | let y = match *x {
|
||||
| ~~
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
84
tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs
Normal file
84
tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs
Normal file
|
@ -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<Option<i32>> {
|
||||
//~^ 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<Option<i32>> = &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<Option<i32>> = &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<Option<i32>> = &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
|
||||
}
|
||||
}
|
259
tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr
Normal file
259
tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr
Normal file
|
@ -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<Option<{integer}>>`
|
||||
...
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<{integer}>>`
|
||||
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<Option<{integer}>>`
|
||||
...
|
||||
LL | None => {}
|
||||
| ^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<{integer}>>`
|
||||
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<Option<{integer}>>`
|
||||
...
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<{integer}>>`
|
||||
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<Option<{integer}>>`
|
||||
...
|
||||
LL | None => {}
|
||||
| ^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<{integer}>>`
|
||||
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<Option<{integer}>>`
|
||||
...
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^ expected `Box<Option<{integer}>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Box<Option<{integer}>>`
|
||||
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<Option<{integer}>>`
|
||||
...
|
||||
LL | None => {}
|
||||
| ^^^^ expected `Box<Option<{integer}>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Box<Option<{integer}>>`
|
||||
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<Option<i32>> {
|
||||
| --------------------- this expression has type `Arc<Option<i32>>`
|
||||
...
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<i32>>`
|
||||
found enum `Option<_>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *(z as Arc<Option<i32>>) {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-deref-in-match-issue-132784.rs:38:9
|
||||
|
|
||||
LL | match z as Arc<Option<i32>> {
|
||||
| --------------------- this expression has type `Arc<Option<i32>>`
|
||||
...
|
||||
LL | None => {}
|
||||
| ^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<i32>>`
|
||||
found enum `Option<_>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *(z as Arc<Option<i32>>) {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-deref-in-match-issue-132784.rs:46:9
|
||||
|
|
||||
LL | match z_const {
|
||||
| ------- this expression has type `&Arc<Option<i32>>`
|
||||
...
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<i32>>`
|
||||
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<Option<i32>>`
|
||||
...
|
||||
LL | None => {}
|
||||
| ^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<i32>>`
|
||||
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<Option<i32>>`
|
||||
...
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<i32>>`
|
||||
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<Option<i32>>`
|
||||
...
|
||||
LL | None => {}
|
||||
| ^^^^ expected `Arc<Option<i32>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<i32>>`
|
||||
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<Option<i32>>`
|
||||
...
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^ expected `Box<Option<i32>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Box<Option<i32>>`
|
||||
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<Option<i32>>`
|
||||
...
|
||||
LL | None => {}
|
||||
| ^^^^ expected `Box<Option<i32>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Box<Option<i32>>`
|
||||
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<Option<{integer}>>`
|
||||
...
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<{integer}>>`
|
||||
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<Option<{integer}>>`
|
||||
...
|
||||
LL | None => {}
|
||||
| ^^^^ expected `Arc<Option<{integer}>>`, found `Option<_>`
|
||||
|
|
||||
= note: expected struct `Arc<Option<{integer}>>`
|
||||
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`.
|
Loading…
Add table
Add a link
Reference in a new issue