summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/tests/ui/manual_let_else_match.rs
blob: 28caed9d79df244f074eab27b108794139ca3ac2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#![allow(unused_braces, unused_variables, dead_code)]
#![allow(clippy::collapsible_else_if, clippy::let_unit_value)]
#![warn(clippy::manual_let_else)]
// Ensure that we don't conflict with match -> if let lints
#![warn(clippy::single_match_else, clippy::single_match)]

fn f() -> Result<u32, u32> {
    Ok(0)
}

fn g() -> Option<()> {
    None
}

fn h() -> (Option<()>, Option<()>) {
    (None, None)
}

enum Variant {
    Foo,
    Bar(u32),
    Baz(u32),
}

fn build_enum() -> Variant {
    Variant::Foo
}

fn main() {}

fn fire() {
    let v = match g() {
        Some(v_some) => v_some,
        None => return,
    };

    let v = match g() {
        Some(v_some) => v_some,
        _ => return,
    };

    loop {
        // More complex pattern for the identity arm and diverging arm
        let v = match h() {
            (Some(_), Some(_)) | (None, None) => continue,
            (Some(v), None) | (None, Some(v)) => v,
        };
        // Custom enums are supported as long as the "else" arm is a simple _
        let v = match build_enum() {
            _ => continue,
            Variant::Bar(v) | Variant::Baz(v) => v,
        };
    }

    // There is a _ in the diverging arm
    // TODO also support unused bindings aka _v
    let v = match f() {
        Ok(v) => v,
        Err(_) => return,
    };

    // Err(()) is an allowed pattern
    let v = match f().map_err(|_| ()) {
        Ok(v) => v,
        Err(()) => return,
    };

    let f = Variant::Bar(1);

    let _value = match f {
        Variant::Bar(_) | Variant::Baz(_) => (),
        _ => return,
    };
}

fn not_fire() {
    // Multiple diverging arms
    let v = match h() {
        _ => panic!(),
        (None, Some(_v)) => return,
        (Some(v), None) => v,
    };

    // Multiple identity arms
    let v = match h() {
        _ => panic!(),
        (None, Some(v)) => v,
        (Some(v), None) => v,
    };

    // No diverging arm at all, only identity arms.
    // This is no case for let else, but destructuring assignment.
    let v = match f() {
        Ok(v) => v,
        Err(e) => e,
    };

    // The identity arm has a guard
    let v = match g() {
        Some(v) if g().is_none() => v,
        _ => return,
    };

    // The diverging arm has a guard
    let v = match f() {
        Err(v) if v > 0 => panic!(),
        Ok(v) | Err(v) => v,
    };

    // The diverging arm creates a binding
    let v = match f() {
        Ok(v) => v,
        Err(e) => panic!("error: {e}"),
    };

    // Custom enum where the diverging arm
    // explicitly mentions the variant
    let v = match build_enum() {
        Variant::Foo => return,
        Variant::Bar(v) | Variant::Baz(v) => v,
    };

    // The custom enum is surrounded by an Err()
    let v = match Err(build_enum()) {
        Ok(v) | Err(Variant::Bar(v) | Variant::Baz(v)) => v,
        Err(Variant::Foo) => return,
    };
}