mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
Auto merge of #6863 - Jarcho:wild_enum_match, r=llogiq
`match_wildcard` improvements fixes: #6604 fixes: #5733 fixes: #6862 #5733 is only fixed in the normal case, if different paths are used for the variants then the same problem will occur. It's cause by `def_path_str` returning an utterly useless result. I haven't dug into why yet. For #6604 there should be some discussion before accepting this. It's easy enough to change the message rather than disable the lint for `Option` and `Result`. changelog: Attempt to find a common path prefix for `match_wildcard_for_single_variants` and `wildcard_enum_match_arm` changelog: Don't lint op `Option` and `Result` for `match_wildcard_for_single_variants` and `wildcard_enum_match_arm` changelog: Consider `or` patterns and `Self` prefix for `match_wildcard_for_single_variants` and `wildcard_enum_match_arm`
This commit is contained in:
commit
4d686196b9
@ -430,7 +430,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_
|
||||
|stmt| match &stmt.kind {
|
||||
StmtKind::Local(_) => true,
|
||||
StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr),
|
||||
_ => false,
|
||||
StmtKind::Item(_) => false,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -613,7 +613,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
MetaItemKind::NameValue(..) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -583,7 +583,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
|
||||
let returns_nothing = match &sig.decl.output {
|
||||
FnRetTy::Default(..) => true,
|
||||
FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
|
||||
_ => false,
|
||||
FnRetTy::Ty(_) => false,
|
||||
};
|
||||
|
||||
if returns_nothing && !is_async && !block.stmts.is_empty() {
|
||||
|
@ -273,7 +273,7 @@ fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -
|
||||
.init
|
||||
.as_ref()
|
||||
.map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)),
|
||||
_ => StopEarly::KeepGoing,
|
||||
StmtKind::Item(..) => StopEarly::KeepGoing,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> {
|
||||
match stmt.kind {
|
||||
StmtKind::Semi(ref e, ..) | StmtKind::Expr(ref e, ..) => Some(e),
|
||||
StmtKind::Local(ref local) => local.init.as_deref(),
|
||||
_ => None,
|
||||
StmtKind::Item(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,21 +8,21 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, pe
|
||||
use clippy_utils::visitors::LocalUsedVisitor;
|
||||
use clippy_utils::{
|
||||
get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, meets_msrv, path_to_local,
|
||||
path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, remove_blocks, strip_pat_refs,
|
||||
path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, strip_pat_refs,
|
||||
};
|
||||
use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::{
|
||||
Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource, Mutability, Node, Pat,
|
||||
PatKind, QPath, RangeEnd,
|
||||
self as hir, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource,
|
||||
Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Ty, TyS};
|
||||
use rustc_middle::ty::{self, Ty, TyS, VariantDef};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
@ -956,114 +956,181 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
|
||||
}
|
||||
}
|
||||
|
||||
fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
|
||||
let ty = cx.typeck_results().expr_ty(ex);
|
||||
if !ty.is_enum() {
|
||||
// If there isn't a nice closed set of possible values that can be conveniently enumerated,
|
||||
// don't complain about not enumerating the mall.
|
||||
return;
|
||||
enum CommonPrefixSearcher<'a> {
|
||||
None,
|
||||
Path(&'a [PathSegment<'a>]),
|
||||
Mixed,
|
||||
}
|
||||
impl CommonPrefixSearcher<'a> {
|
||||
fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
|
||||
match path {
|
||||
[path @ .., _] => self.with_prefix(path),
|
||||
[] => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_prefix(&mut self, path: &'a [PathSegment<'a>]) {
|
||||
match self {
|
||||
Self::None => *self = Self::Path(path),
|
||||
Self::Path(self_path)
|
||||
if path
|
||||
.iter()
|
||||
.map(|p| p.ident.name)
|
||||
.eq(self_path.iter().map(|p| p.ident.name)) => {},
|
||||
Self::Path(_) => *self = Self::Mixed,
|
||||
Self::Mixed => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
|
||||
let ty = cx.typeck_results().expr_ty(ex).peel_refs();
|
||||
let adt_def = match ty.kind() {
|
||||
ty::Adt(adt_def, _)
|
||||
if adt_def.is_enum()
|
||||
&& !(is_type_diagnostic_item(cx, ty, sym::option_type)
|
||||
|| is_type_diagnostic_item(cx, ty, sym::result_type)) =>
|
||||
{
|
||||
adt_def
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// First pass - check for violation, but don't do much book-keeping because this is hopefully
|
||||
// the uncommon case, and the book-keeping is slightly expensive.
|
||||
let mut wildcard_span = None;
|
||||
let mut wildcard_ident = None;
|
||||
let mut has_non_wild = false;
|
||||
for arm in arms {
|
||||
if let PatKind::Wild = arm.pat.kind {
|
||||
wildcard_span = Some(arm.pat.span);
|
||||
} else if let PatKind::Binding(_, _, ident, None) = arm.pat.kind {
|
||||
wildcard_span = Some(arm.pat.span);
|
||||
wildcard_ident = Some(ident);
|
||||
match peel_hir_pat_refs(arm.pat).0.kind {
|
||||
PatKind::Wild => wildcard_span = Some(arm.pat.span),
|
||||
PatKind::Binding(_, _, ident, None) => {
|
||||
wildcard_span = Some(arm.pat.span);
|
||||
wildcard_ident = Some(ident);
|
||||
},
|
||||
_ => has_non_wild = true,
|
||||
}
|
||||
}
|
||||
let wildcard_span = match wildcard_span {
|
||||
Some(x) if has_non_wild => x,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
if let Some(wildcard_span) = wildcard_span {
|
||||
// Accumulate the variants which should be put in place of the wildcard because they're not
|
||||
// already covered.
|
||||
// Accumulate the variants which should be put in place of the wildcard because they're not
|
||||
// already covered.
|
||||
let mut missing_variants: Vec<_> = adt_def.variants.iter().collect();
|
||||
|
||||
let mut missing_variants = vec![];
|
||||
if let ty::Adt(def, _) = ty.kind() {
|
||||
for variant in &def.variants {
|
||||
missing_variants.push(variant);
|
||||
let mut path_prefix = CommonPrefixSearcher::None;
|
||||
for arm in arms {
|
||||
// Guards mean that this case probably isn't exhaustively covered. Technically
|
||||
// this is incorrect, as we should really check whether each variant is exhaustively
|
||||
// covered by the set of guards that cover it, but that's really hard to do.
|
||||
recurse_or_patterns(arm.pat, |pat| {
|
||||
let path = match &peel_hir_pat_refs(pat).0.kind {
|
||||
PatKind::Path(path) => {
|
||||
#[allow(clippy::match_same_arms)]
|
||||
let id = match cx.qpath_res(path, pat.hir_id) {
|
||||
Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
|
||||
Res::Def(_, id) => id,
|
||||
_ => return,
|
||||
};
|
||||
if arm.guard.is_none() {
|
||||
missing_variants.retain(|e| e.ctor_def_id != Some(id));
|
||||
}
|
||||
path
|
||||
},
|
||||
PatKind::TupleStruct(path, patterns, ..) => {
|
||||
if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
|
||||
let id = cx.qpath_res(path, pat.hir_id).def_id();
|
||||
missing_variants.retain(|e| e.ctor_def_id != Some(id));
|
||||
}
|
||||
path
|
||||
},
|
||||
PatKind::Struct(path, patterns, ..) => {
|
||||
if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) {
|
||||
let id = cx.qpath_res(path, pat.hir_id).def_id();
|
||||
missing_variants.retain(|e| e.def_id != id);
|
||||
}
|
||||
path
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
match path {
|
||||
QPath::Resolved(_, path) => path_prefix.with_path(path.segments),
|
||||
QPath::TypeRelative(
|
||||
hir::Ty {
|
||||
kind: TyKind::Path(QPath::Resolved(_, path)),
|
||||
..
|
||||
},
|
||||
_,
|
||||
) => path_prefix.with_prefix(path.segments),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for arm in arms {
|
||||
if arm.guard.is_some() {
|
||||
// Guards mean that this case probably isn't exhaustively covered. Technically
|
||||
// this is incorrect, as we should really check whether each variant is exhaustively
|
||||
// covered by the set of guards that cover it, but that's really hard to do.
|
||||
continue;
|
||||
}
|
||||
if let PatKind::Path(ref path) = arm.pat.kind {
|
||||
if let QPath::Resolved(_, p) = path {
|
||||
missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
|
||||
}
|
||||
} else if let PatKind::TupleStruct(QPath::Resolved(_, p), ref patterns, ..) = arm.pat.kind {
|
||||
// Some simple checks for exhaustive patterns.
|
||||
// There is a room for improvements to detect more cases,
|
||||
// but it can be more expensive to do so.
|
||||
let is_pattern_exhaustive =
|
||||
|pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None));
|
||||
if patterns.iter().all(is_pattern_exhaustive) {
|
||||
missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
|
||||
let format_suggestion = |variant: &VariantDef| {
|
||||
format!(
|
||||
"{}{}{}{}",
|
||||
if let Some(ident) = wildcard_ident {
|
||||
format!("{} @ ", ident.name)
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
if let CommonPrefixSearcher::Path(path_prefix) = path_prefix {
|
||||
let mut s = String::new();
|
||||
for seg in path_prefix {
|
||||
s.push_str(&seg.ident.as_str());
|
||||
s.push_str("::");
|
||||
}
|
||||
s
|
||||
} else {
|
||||
let mut s = cx.tcx.def_path_str(adt_def.did);
|
||||
s.push_str("::");
|
||||
s
|
||||
},
|
||||
variant.ident.name,
|
||||
match variant.ctor_kind {
|
||||
CtorKind::Fn if variant.fields.len() == 1 => "(_)",
|
||||
CtorKind::Fn => "(..)",
|
||||
CtorKind::Const => "",
|
||||
CtorKind::Fictive => "{ .. }",
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
let mut suggestion: Vec<String> = missing_variants
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let suffix = match v.ctor_kind {
|
||||
CtorKind::Fn => "(..)",
|
||||
CtorKind::Const | CtorKind::Fictive => "",
|
||||
};
|
||||
let ident_str = if let Some(ident) = wildcard_ident {
|
||||
format!("{} @ ", ident.name)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
// This path assumes that the enum type is imported into scope.
|
||||
format!("{}{}{}", ident_str, cx.tcx.def_path_str(v.def_id), suffix)
|
||||
})
|
||||
.collect();
|
||||
match missing_variants.as_slice() {
|
||||
[] => (),
|
||||
[x] if !adt_def.is_variant_list_non_exhaustive() => span_lint_and_sugg(
|
||||
cx,
|
||||
MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
|
||||
wildcard_span,
|
||||
"wildcard matches only a single variant and will also match any future added variants",
|
||||
"try this",
|
||||
format_suggestion(x),
|
||||
Applicability::MaybeIncorrect,
|
||||
),
|
||||
variants => {
|
||||
let mut suggestions: Vec<_> = variants.iter().cloned().map(format_suggestion).collect();
|
||||
let message = if adt_def.is_variant_list_non_exhaustive() {
|
||||
suggestions.push("_".into());
|
||||
"wildcard matches known variants and will also match future added variants"
|
||||
} else {
|
||||
"wildcard match will also match any future added variants"
|
||||
};
|
||||
|
||||
if suggestion.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut message = "wildcard match will miss any future added variants";
|
||||
|
||||
if let ty::Adt(def, _) = ty.kind() {
|
||||
if def.is_variant_list_non_exhaustive() {
|
||||
message = "match on non-exhaustive enum doesn't explicitly match all known variants";
|
||||
suggestion.push(String::from("_"));
|
||||
}
|
||||
}
|
||||
|
||||
if suggestion.len() == 1 {
|
||||
// No need to check for non-exhaustive enum as in that case len would be greater than 1
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
|
||||
WILDCARD_ENUM_MATCH_ARM,
|
||||
wildcard_span,
|
||||
message,
|
||||
"try this",
|
||||
suggestion[0].clone(),
|
||||
suggestions.join(" | "),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
WILDCARD_ENUM_MATCH_ARM,
|
||||
wildcard_span,
|
||||
message,
|
||||
"try this",
|
||||
suggestion.join(" | "),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// If the block contains only a `panic!` macro (as expression or statement)
|
||||
|
@ -556,7 +556,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
|
||||
mir::Operand::Copy(p) | mir::Operand::Move(p) => {
|
||||
self.possible_borrower.add(p.local, *dest);
|
||||
},
|
||||
_ => (),
|
||||
mir::Operand::Constant(..) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -578,7 +578,7 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
|
||||
|
||||
let mut visit_op = |op: &mir::Operand<'_>| match op {
|
||||
mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local),
|
||||
_ => (),
|
||||
mir::Operand::Constant(..) => (),
|
||||
};
|
||||
|
||||
match rvalue {
|
||||
|
@ -276,7 +276,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
|
||||
match item.kind {
|
||||
TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_ty(cx, ty, false),
|
||||
TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, &sig.decl),
|
||||
_ => (),
|
||||
TraitItemKind::Type(..) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,7 +452,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeComplexity {
|
||||
TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_type(cx, ty),
|
||||
TraitItemKind::Fn(FnSig { ref decl, .. }, TraitFn::Required(_)) => self.check_fndecl(cx, decl),
|
||||
// methods with default impl are covered by check_fn
|
||||
_ => (),
|
||||
TraitItemKind::Type(..) | TraitItemKind::Fn(_, TraitFn::Provided(_)) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,7 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeComplexity {
|
||||
match item.kind {
|
||||
ImplItemKind::Const(ref ty, _) | ImplItemKind::TyAlias(ref ty) => self.check_type(cx, ty),
|
||||
// methods are covered by check_fn
|
||||
_ => (),
|
||||
ImplItemKind::Fn(..) => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
|
||||
}
|
||||
},
|
||||
FnKind::Closure => return,
|
||||
_ => (),
|
||||
FnKind::Method(..) => (),
|
||||
}
|
||||
|
||||
// Abort if the method is implementing a trait or of it a trait method.
|
||||
|
@ -977,6 +977,16 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call
|
||||
/// the function once on the given pattern.
|
||||
pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
|
||||
if let PatKind::Or(pats) = pat.kind {
|
||||
pats.iter().cloned().for_each(f)
|
||||
} else {
|
||||
f(pat)
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
|
||||
/// implementations have.
|
||||
pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
|
||||
|
@ -15,6 +15,16 @@ enum Color {
|
||||
Blue,
|
||||
Rgb(u8, u8, u8),
|
||||
}
|
||||
impl Color {
|
||||
fn f(self) {
|
||||
match self {
|
||||
Self::Red => (),
|
||||
Self::Green => (),
|
||||
Self::Blue => (),
|
||||
Self::Rgb(..) => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let f = Foo::A;
|
||||
@ -56,4 +66,46 @@ fn main() {
|
||||
Color::Rgb(255, _, _) => {},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
// References shouldn't change anything
|
||||
match &color {
|
||||
&Color::Red => (),
|
||||
Color::Green => (),
|
||||
&Color::Rgb(..) => (),
|
||||
Color::Blue => (),
|
||||
}
|
||||
|
||||
use self::Color as C;
|
||||
|
||||
match color {
|
||||
C::Red => (),
|
||||
C::Green => (),
|
||||
C::Rgb(..) => (),
|
||||
C::Blue => (),
|
||||
}
|
||||
|
||||
match color {
|
||||
C::Red => (),
|
||||
Color::Green => (),
|
||||
Color::Rgb(..) => (),
|
||||
Color::Blue => (),
|
||||
}
|
||||
|
||||
match Some(0) {
|
||||
Some(0) => 0,
|
||||
Some(_) => 1,
|
||||
_ => 2,
|
||||
};
|
||||
|
||||
#[non_exhaustive]
|
||||
enum Bar {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
}
|
||||
match Bar::A {
|
||||
Bar::A => (),
|
||||
Bar::B => (),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
@ -15,6 +15,16 @@ enum Color {
|
||||
Blue,
|
||||
Rgb(u8, u8, u8),
|
||||
}
|
||||
impl Color {
|
||||
fn f(self) {
|
||||
match self {
|
||||
Self::Red => (),
|
||||
Self::Green => (),
|
||||
Self::Blue => (),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let f = Foo::A;
|
||||
@ -56,4 +66,46 @@ fn main() {
|
||||
Color::Rgb(255, _, _) => {},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
// References shouldn't change anything
|
||||
match &color {
|
||||
&Color::Red => (),
|
||||
Color::Green => (),
|
||||
&Color::Rgb(..) => (),
|
||||
&_ => (),
|
||||
}
|
||||
|
||||
use self::Color as C;
|
||||
|
||||
match color {
|
||||
C::Red => (),
|
||||
C::Green => (),
|
||||
C::Rgb(..) => (),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
match color {
|
||||
C::Red => (),
|
||||
Color::Green => (),
|
||||
Color::Rgb(..) => (),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
match Some(0) {
|
||||
Some(0) => 0,
|
||||
Some(_) => 1,
|
||||
_ => 2,
|
||||
};
|
||||
|
||||
#[non_exhaustive]
|
||||
enum Bar {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
}
|
||||
match Bar::A {
|
||||
Bar::A => (),
|
||||
Bar::B => (),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
@ -1,28 +1,52 @@
|
||||
error: wildcard match will miss any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:24:9
|
||||
error: wildcard matches only a single variant and will also match any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:24:13
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^ help: try this: `Foo::C`
|
||||
LL | _ => (),
|
||||
| ^ help: try this: `Self::Rgb(..)`
|
||||
|
|
||||
= note: `-D clippy::match-wildcard-for-single-variants` implied by `-D warnings`
|
||||
|
||||
error: wildcard match will miss any future added variants
|
||||
error: wildcard matches only a single variant and will also match any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:34:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^ help: try this: `Color::Blue`
|
||||
| ^ help: try this: `Foo::C`
|
||||
|
||||
error: wildcard match will miss any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:42:9
|
||||
error: wildcard matches only a single variant and will also match any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:44:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^ help: try this: `Color::Blue`
|
||||
|
||||
error: wildcard match will miss any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:48:9
|
||||
error: wildcard matches only a single variant and will also match any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:52:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^ help: try this: `Color::Blue`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: wildcard matches only a single variant and will also match any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:58:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^ help: try this: `Color::Blue`
|
||||
|
||||
error: wildcard matches only a single variant and will also match any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:75:9
|
||||
|
|
||||
LL | &_ => (),
|
||||
| ^^ help: try this: `Color::Blue`
|
||||
|
||||
error: wildcard matches only a single variant and will also match any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:84:9
|
||||
|
|
||||
LL | _ => (),
|
||||
| ^ help: try this: `C::Blue`
|
||||
|
||||
error: wildcard matches only a single variant and will also match any future added variants
|
||||
--> $DIR/match_wildcard_for_single_variants.rs:91:9
|
||||
|
|
||||
LL | _ => (),
|
||||
| ^ help: try this: `Color::Blue`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
@ -77,7 +77,7 @@ fn main() {
|
||||
let error_kind = ErrorKind::NotFound;
|
||||
match error_kind {
|
||||
ErrorKind::NotFound => {},
|
||||
std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _ => {},
|
||||
ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | _ => {},
|
||||
}
|
||||
match error_kind {
|
||||
ErrorKind::NotFound => {},
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: wildcard match will miss any future added variants
|
||||
error: wildcard match will also match any future added variants
|
||||
--> $DIR/wildcard_enum_match_arm.rs:39:9
|
||||
|
|
||||
LL | _ => eprintln!("Not red"),
|
||||
@ -10,29 +10,29 @@ note: the lint level is defined here
|
||||
LL | #![deny(clippy::wildcard_enum_match_arm)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: wildcard match will miss any future added variants
|
||||
error: wildcard match will also match any future added variants
|
||||
--> $DIR/wildcard_enum_match_arm.rs:43:9
|
||||
|
|
||||
LL | _not_red => eprintln!("Not red"),
|
||||
| ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan`
|
||||
|
||||
error: wildcard match will miss any future added variants
|
||||
error: wildcard match will also match any future added variants
|
||||
--> $DIR/wildcard_enum_match_arm.rs:47:9
|
||||
|
|
||||
LL | not_red => format!("{:?}", not_red),
|
||||
| ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan`
|
||||
|
||||
error: wildcard match will miss any future added variants
|
||||
error: wildcard match will also match any future added variants
|
||||
--> $DIR/wildcard_enum_match_arm.rs:63:9
|
||||
|
|
||||
LL | _ => "No red",
|
||||
| ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
|
||||
|
||||
error: match on non-exhaustive enum doesn't explicitly match all known variants
|
||||
error: wildcard matches known variants and will also match future added variants
|
||||
--> $DIR/wildcard_enum_match_arm.rs:80:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^ help: try this: `std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _`
|
||||
| ^ help: try this: `ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | _`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user