about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduardo Broto <ebroto@tutanota.com>2020-06-17 00:32:47 +0200
committerEduardo Broto <ebroto@tutanota.com>2020-06-17 00:32:47 +0200
commita7743e9084f9ccd7c966f98a14fa667c694d66ab (patch)
tree17dab8aec52f1c496a080c794b11d201249bf44c
parentf065d4b887e6722d617eacc93d5dcb75e6b32105 (diff)
downloadrust-a7743e9084f9ccd7c966f98a14fa667c694d66ab.tar.gz
rust-a7743e9084f9ccd7c966f98a14fa667c694d66ab.zip
redundant_pattern_matching: avoid non-const fn in const context
-rw-r--r--clippy_lints/src/redundant_pattern_matching.rs80
-rw-r--r--tests/ui/redundant_pattern_matching.fixed42
-rw-r--r--tests/ui/redundant_pattern_matching.rs42
-rw-r--r--tests/ui/redundant_pattern_matching.stderr56
-rw-r--r--tests/ui/redundant_pattern_matching_const_result.fixed46
-rw-r--r--tests/ui/redundant_pattern_matching_const_result.rs52
-rw-r--r--tests/ui/redundant_pattern_matching_const_result.stderr46
7 files changed, 318 insertions, 46 deletions
diff --git a/clippy_lints/src/redundant_pattern_matching.rs b/clippy_lints/src/redundant_pattern_matching.rs
index 7ee298e9833..b95b12c4eb5 100644
--- a/clippy_lints/src/redundant_pattern_matching.rs
+++ b/clippy_lints/src/redundant_pattern_matching.rs
@@ -1,10 +1,13 @@
-use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
+use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_mir::const_eval::is_const_fn;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Symbol;
 
 declare_clippy_lint! {
     /// **What it does:** Lint for redundant pattern matching over `Result` or
@@ -64,26 +67,37 @@ fn find_sugg_for_if_let<'a, 'tcx>(
     arms: &[Arm<'_>],
     keyword: &'static str,
 ) {
+    fn find_suggestion(cx: &LateContext<'_, '_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
+        if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
+            return Some("is_ok()");
+        }
+        if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
+            return Some("is_err()");
+        }
+        if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
+            return Some("is_some()");
+        }
+        if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
+            return Some("is_none()");
+        }
+        None
+    }
+
+    let hir_id = expr.hir_id;
     let good_method = match arms[0].pat.kind {
         PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
             if let PatKind::Wild = patterns[0].kind {
-                if match_qpath(path, &paths::RESULT_OK) {
-                    "is_ok()"
-                } else if match_qpath(path, &paths::RESULT_ERR) {
-                    "is_err()"
-                } else if match_qpath(path, &paths::OPTION_SOME) {
-                    "is_some()"
-                } else {
-                    return;
-                }
+                find_suggestion(cx, hir_id, path)
             } else {
-                return;
+                None
             }
         },
-
-        PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()",
-
-        _ => return,
+        PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
+        _ => None,
+    };
+    let good_method = match good_method {
+        Some(method) => method,
+        None => return,
     };
 
     // check that `while_let_on_iterator` lint does not trigger
@@ -128,6 +142,7 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
     if arms.len() == 2 {
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 
+        let hir_id = expr.hir_id;
         let found_good_method = match node_pair {
             (
                 PatKind::TupleStruct(ref path_left, ref patterns_left, _),
@@ -142,6 +157,8 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
                         &paths::RESULT_ERR,
                         "is_ok()",
                         "is_err()",
+                        || can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
+                        || can_suggest(cx, hir_id, sym!(result_type), "is_err"),
                     )
                 } else {
                     None
@@ -160,6 +177,8 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
                         &paths::OPTION_NONE,
                         "is_some()",
                         "is_none()",
+                        || can_suggest(cx, hir_id, sym!(option_type), "is_some"),
+                        || can_suggest(cx, hir_id, sym!(option_type), "is_none"),
                     )
                 } else {
                     None
@@ -188,6 +207,7 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
     }
 }
 
+#[allow(clippy::too_many_arguments)]
 fn find_good_method_for_match<'a>(
     arms: &[Arm<'_>],
     path_left: &QPath<'_>,
@@ -196,6 +216,8 @@ fn find_good_method_for_match<'a>(
     expected_right: &[&str],
     should_be_left: &'a str,
     should_be_right: &'a str,
+    can_suggest_left: impl Fn() -> bool,
+    can_suggest_right: impl Fn() -> bool,
 ) -> Option<&'a str> {
     let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
         (&(*arms[0].body).kind, &(*arms[1].body).kind)
@@ -207,10 +229,32 @@ fn find_good_method_for_match<'a>(
 
     match body_node_pair {
         (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
-            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
-            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
+            (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
             _ => None,
         },
         _ => None,
     }
 }
+
+fn can_suggest(cx: &LateContext<'_, '_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
+    if !in_constant(cx, hir_id) {
+        return true;
+    }
+
+    // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
+    cx.tcx
+        .get_diagnostic_item(diag_item)
+        .and_then(|def_id| {
+            cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
+                cx.tcx
+                    .associated_items(*imp)
+                    .in_definition_order()
+                    .find_map(|item| match item.kind {
+                        ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
+                        _ => None,
+                    })
+            })
+        })
+        .map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
+}
diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed
index fc8cb0e747c..6ba5cfb1d71 100644
--- a/tests/ui/redundant_pattern_matching.fixed
+++ b/tests/ui/redundant_pattern_matching.fixed
@@ -1,5 +1,7 @@
 // run-rustfix
 
+#![feature(const_if_match)]
+#![feature(const_loop)]
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
@@ -67,6 +69,7 @@ fn main() {
     takes_bool(x);
 
     issue5504();
+    issue5697();
 
     let _ = if gen_opt().is_some() {
         1
@@ -117,3 +120,42 @@ fn issue5504() {
     if m!().is_some() {}
     while m!().is_some() {}
 }
+
+// None of these should be linted because none of the suggested methods
+// are `const fn` without toggling a feature.
+const fn issue5697() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs
index 51912dade03..17de66f9ad0 100644
--- a/tests/ui/redundant_pattern_matching.rs
+++ b/tests/ui/redundant_pattern_matching.rs
@@ -1,5 +1,7 @@
 // run-rustfix
 
+#![feature(const_if_match)]
+#![feature(const_loop)]
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
@@ -88,6 +90,7 @@ fn main() {
     takes_bool(x);
 
     issue5504();
+    issue5697();
 
     let _ = if let Some(_) = gen_opt() {
         1
@@ -138,3 +141,42 @@ fn issue5504() {
     if let Some(_) = m!() {}
     while let Some(_) = m!() {}
 }
+
+// None of these should be linted because none of the suggested methods
+// are `const fn` without toggling a feature.
+const fn issue5697() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr
index b58deb7954e..1b9a4b40a2f 100644
--- a/tests/ui/redundant_pattern_matching.stderr
+++ b/tests/ui/redundant_pattern_matching.stderr
@@ -1,5 +1,5 @@
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:8:12
+  --> $DIR/redundant_pattern_matching.rs:10:12
    |
 LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
@@ -7,67 +7,67 @@ LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:10:12
+  --> $DIR/redundant_pattern_matching.rs:12:12
    |
 LL |     if let Err(_) = Err::<i32, i32>(42) {}
    |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:12:12
+  --> $DIR/redundant_pattern_matching.rs:14:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:14:12
+  --> $DIR/redundant_pattern_matching.rs:16:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:16:12
+  --> $DIR/redundant_pattern_matching.rs:18:12
    |
 LL |     if let Some(_) = Some(42) {
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:22:15
+  --> $DIR/redundant_pattern_matching.rs:24:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:24:15
+  --> $DIR/redundant_pattern_matching.rs:26:15
    |
 LL |     while let None = Some(42) {}
    |     ----------^^^^----------- help: try this: `while Some(42).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:26:15
+  --> $DIR/redundant_pattern_matching.rs:28:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:28:15
+  --> $DIR/redundant_pattern_matching.rs:30:15
    |
 LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:30:15
+  --> $DIR/redundant_pattern_matching.rs:32:15
    |
 LL |     while let Err(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:33:15
+  --> $DIR/redundant_pattern_matching.rs:35:15
    |
 LL |     while let Some(_) = v.pop() {
    |     ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:49:5
+  --> $DIR/redundant_pattern_matching.rs:51:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -76,7 +76,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:54:5
+  --> $DIR/redundant_pattern_matching.rs:56:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -85,7 +85,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:59:5
+  --> $DIR/redundant_pattern_matching.rs:61:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -94,7 +94,7 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:64:5
+  --> $DIR/redundant_pattern_matching.rs:66:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -103,7 +103,7 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:69:5
+  --> $DIR/redundant_pattern_matching.rs:71:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -112,7 +112,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:74:5
+  --> $DIR/redundant_pattern_matching.rs:76:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -121,7 +121,7 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:79:13
+  --> $DIR/redundant_pattern_matching.rs:81:13
    |
 LL |       let _ = match None::<()> {
    |  _____________^
@@ -131,61 +131,61 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:84:20
+  --> $DIR/redundant_pattern_matching.rs:86:20
    |
 LL |     let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
    |             -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:87:20
+  --> $DIR/redundant_pattern_matching.rs:89:20
    |
 LL |     let x = if let Some(_) = opt { true } else { false };
    |             -------^^^^^^^------ help: try this: `if opt.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:92:20
+  --> $DIR/redundant_pattern_matching.rs:95:20
    |
 LL |     let _ = if let Some(_) = gen_opt() {
    |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:94:19
+  --> $DIR/redundant_pattern_matching.rs:97:19
    |
 LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:96:19
+  --> $DIR/redundant_pattern_matching.rs:99:19
    |
 LL |     } else if let Ok(_) = gen_res() {
    |            -------^^^^^------------ help: try this: `if gen_res().is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:98:19
+  --> $DIR/redundant_pattern_matching.rs:101:19
    |
 LL |     } else if let Err(_) = gen_res() {
    |            -------^^^^^^------------ help: try this: `if gen_res().is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:131:19
+  --> $DIR/redundant_pattern_matching.rs:134:19
    |
 LL |         while let Some(_) = r#try!(result_opt()) {}
    |         ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:132:16
+  --> $DIR/redundant_pattern_matching.rs:135:16
    |
 LL |         if let Some(_) = r#try!(result_opt()) {}
    |         -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:138:12
+  --> $DIR/redundant_pattern_matching.rs:141:12
    |
 LL |     if let Some(_) = m!() {}
    |     -------^^^^^^^------- help: try this: `if m!().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:139:15
+  --> $DIR/redundant_pattern_matching.rs:142:15
    |
 LL |     while let Some(_) = m!() {}
    |     ----------^^^^^^^------- help: try this: `while m!().is_some()`
diff --git a/tests/ui/redundant_pattern_matching_const_result.fixed b/tests/ui/redundant_pattern_matching_const_result.fixed
new file mode 100644
index 00000000000..c8bc5458067
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_const_result.fixed
@@ -0,0 +1,46 @@
+// run-rustfix
+
+#![feature(const_if_match)]
+#![feature(const_loop)]
+#![feature(const_result)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused)]
+
+// Test that results are linted with the feature enabled.
+
+const fn issue_5697() {
+    if Ok::<i32, i32>(42).is_ok() {}
+
+    if Err::<i32, i32>(42).is_err() {}
+
+    while Ok::<i32, i32>(10).is_ok() {}
+
+    while Ok::<i32, i32>(10).is_err() {}
+
+    Ok::<i32, i32>(42).is_ok();
+
+    Err::<i32, i32>(42).is_err();
+
+    // These should not be linted until `const_option` is implemented.
+    // See https://github.com/rust-lang/rust/issues/67441
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/redundant_pattern_matching_const_result.rs b/tests/ui/redundant_pattern_matching_const_result.rs
new file mode 100644
index 00000000000..75f37ec15c6
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_const_result.rs
@@ -0,0 +1,52 @@
+// run-rustfix
+
+#![feature(const_if_match)]
+#![feature(const_loop)]
+#![feature(const_result)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused)]
+
+// Test that results are linted with the feature enabled.
+
+const fn issue_5697() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+
+    // These should not be linted until `const_option` is implemented.
+    // See https://github.com/rust-lang/rust/issues/67441
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/redundant_pattern_matching_const_result.stderr b/tests/ui/redundant_pattern_matching_const_result.stderr
new file mode 100644
index 00000000000..c32292f0eee
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_const_result.stderr
@@ -0,0 +1,46 @@
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:12:12
+   |
+LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
+   |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:14:12
+   |
+LL |     if let Err(_) = Err::<i32, i32>(42) {}
+   |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:16:15
+   |
+LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:18:15
+   |
+LL |     while let Err(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:20:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         Err(_) => false,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:25:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         Err(_) => true,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+
+error: aborting due to 6 previous errors
+