summaryrefslogtreecommitdiffstats
path: root/src/test/ui/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs
blob: 2b3fbd2a4d28a2ee21ab9dc8278142d76f73df5f (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
129
130
131
132
133
134
135
// run-pass

// This file checks that fn ptrs are considered structurally matchable.
// See also rust-lang/rust#63479.

fn main() {
    let mut count = 0;

    // A type which is not structurally matchable:
    struct NotSM;

    // And one that is:
    #[derive(PartialEq, Eq)]
    struct SM;

    fn trivial() {}

    fn sm_to(_: SM) {}
    fn not_sm_to(_: NotSM) {}
    fn to_sm() -> SM { SM }
    fn to_not_sm() -> NotSM { NotSM }

    // To recreate the scenario of interest in #63479, we need to add
    // a ref-level-of-indirection so that we descend into the type.

    fn r_sm_to(_: &SM) {}
    fn r_not_sm_to(_: &NotSM) {}
    fn r_to_r_sm(_: &()) -> &SM { &SM }
    fn r_to_r_not_sm(_: &()) -> &NotSM { &NotSM }

    #[derive(PartialEq, Eq)]
    struct Wrap<T>(T);

    // In the code below, we put the match input into a local so that
    // we can assign it an explicit type that is an fn ptr instead of
    // a singleton type of the fn itself that the type inference would
    // otherwise assign.

    // Check that fn() is structural-match
    const CFN1: Wrap<fn()> = Wrap(trivial);
    let input: Wrap<fn()> = Wrap(trivial);
    match Wrap(input) {
        Wrap(CFN1) => count += 1,
        Wrap(_) => {}
    };

    // Check that fn(T) is structural-match when T is too.
    const CFN2: Wrap<fn(SM)> = Wrap(sm_to);
    let input: Wrap<fn(SM)> = Wrap(sm_to);
    match Wrap(input) {
        Wrap(CFN2) => count += 1,
        Wrap(_) => {}
    };

    // Check that fn() -> T is structural-match when T is too.
    const CFN3: Wrap<fn() -> SM> = Wrap(to_sm);
    let input: Wrap<fn() -> SM> = Wrap(to_sm);
    match Wrap(input) {
        Wrap(CFN3) => count += 1,
        Wrap(_) => {}
    };

    // Check that fn(T) is structural-match even if T is not.
    const CFN4: Wrap<fn(NotSM)> = Wrap(not_sm_to);
    let input: Wrap<fn(NotSM)> = Wrap(not_sm_to);
    match Wrap(input) {
        Wrap(CFN4) => count += 1,
        Wrap(_) => {}
    };

    // Check that fn() -> T is structural-match even if T is not.
    const CFN5: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
    let input: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
    match Wrap(input) {
        Wrap(CFN5) => count += 1,
        Wrap(_) => {}
    };

    // Check that fn(&T) is structural-match when T is too.
    const CFN6: Wrap<fn(&SM)> = Wrap(r_sm_to);
    let input: Wrap<fn(&SM)> = Wrap(r_sm_to);
    match Wrap(input) {
        Wrap(CFN6) => count += 1,
        Wrap(_) => {}
    };

    // Check that fn() -> &T is structural-match when T is too.
    const CFN7: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
    let input: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
    match Wrap(input) {
        Wrap(CFN7) => count += 1,
        Wrap(_) => {}
    };

    // Check that fn(T) is structural-match even if T is not.
    const CFN8: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
    let input: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
    match Wrap(input) {
        Wrap(CFN8) => count += 1,
        Wrap(_) => {}
    };

    // Check that fn() -> T is structural-match even if T is not.
    const CFN9: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
    let input: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
    match Wrap(input) {
        Wrap(CFN9) => count += 1,
        Wrap(_) => {}
    };

    // Check that a type which has fn ptrs is structural-match.
    #[derive(PartialEq, Eq)]
    struct Foo {
        alpha: fn(NotSM),
        beta: fn() -> NotSM,
        gamma: fn(SM),
        delta: fn() -> SM,
    }

    const CFOO: Foo = Foo {
        alpha: not_sm_to,
        beta: to_not_sm,
        gamma: sm_to,
        delta: to_sm,
    };

    let input = Foo { alpha: not_sm_to, beta: to_not_sm, gamma: sm_to, delta: to_sm };
    match input {
        CFOO => count += 1,
        Foo { .. } => {}
    };

    // Final count must be 10 now if all
    assert_eq!(count, 10);
}