Skip to content

Commit c529294

Browse files
committed
Regression tests for fn ptr and #[structural_match] as discussed in #63479.
1 parent 7437f77 commit c529294

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// run-pass
2+
3+
// This file checks that fn ptrs are considered structurally matchable.
4+
// See also rust-lang/rust#63479.
5+
6+
fn main() {
7+
let mut count = 0;
8+
9+
// A type which is not structurally matchable:
10+
struct NotSM;
11+
12+
// And one that is:
13+
#[derive(PartialEq, Eq)]
14+
struct SM;
15+
16+
fn trivial() {}
17+
18+
fn sm_to(_: SM) {}
19+
fn not_sm_to(_: NotSM) {}
20+
fn to_sm() -> SM { SM }
21+
fn to_not_sm() -> NotSM { NotSM }
22+
23+
// To recreate the scenario of interest in #63479, we need to add
24+
// a ref-level-of-indirection so that we descend into the type.
25+
26+
fn r_sm_to(_: &SM) {}
27+
fn r_not_sm_to(_: &NotSM) {}
28+
fn r_to_r_sm(_: &()) -> &SM { &SM }
29+
fn r_to_r_not_sm(_: &()) -> &NotSM { &NotSM }
30+
31+
#[derive(PartialEq, Eq)]
32+
struct Wrap<T>(T);
33+
34+
// In the code below, we put the match input into a local so that
35+
// we can assign it an explicit type that is an fn ptr instead of
36+
// a singleton type of the fn itself that the type inference would
37+
// otherwise assign.
38+
39+
// Check that fn() is #[structural_match]
40+
const CFN1: Wrap<fn()> = Wrap(trivial);
41+
let input: Wrap<fn()> = Wrap(trivial);
42+
match Wrap(input) {
43+
Wrap(CFN1) => count += 1,
44+
Wrap(_) => {}
45+
};
46+
47+
// Check that fn(T) is #[structural_match] when T is too.
48+
const CFN2: Wrap<fn(SM)> = Wrap(sm_to);
49+
let input: Wrap<fn(SM)> = Wrap(sm_to);
50+
match Wrap(input) {
51+
Wrap(CFN2) => count += 1,
52+
Wrap(_) => {}
53+
};
54+
55+
// Check that fn() -> T is #[structural_match] when T is too.
56+
const CFN3: Wrap<fn() -> SM> = Wrap(to_sm);
57+
let input: Wrap<fn() -> SM> = Wrap(to_sm);
58+
match Wrap(input) {
59+
Wrap(CFN3) => count += 1,
60+
Wrap(_) => {}
61+
};
62+
63+
// Check that fn(T) is #[structural_match] even if T is not.
64+
const CFN4: Wrap<fn(NotSM)> = Wrap(not_sm_to);
65+
let input: Wrap<fn(NotSM)> = Wrap(not_sm_to);
66+
match Wrap(input) {
67+
Wrap(CFN4) => count += 1,
68+
Wrap(_) => {}
69+
};
70+
71+
// Check that fn() -> T is #[structural_match] even if T is not.
72+
const CFN5: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
73+
let input: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
74+
match Wrap(input) {
75+
Wrap(CFN5) => count += 1,
76+
Wrap(_) => {}
77+
};
78+
79+
// Check that fn(&T) is #[structural_match] when T is too.
80+
const CFN6: Wrap<fn(&SM)> = Wrap(r_sm_to);
81+
let input: Wrap<fn(&SM)> = Wrap(r_sm_to);
82+
match Wrap(input) {
83+
Wrap(CFN6) => count += 1,
84+
Wrap(_) => {}
85+
};
86+
87+
// Check that fn() -> &T is #[structural_match] when T is too.
88+
const CFN7: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
89+
let input: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
90+
match Wrap(input) {
91+
Wrap(CFN7) => count += 1,
92+
Wrap(_) => {}
93+
};
94+
95+
// Check that fn(T) is #[structural_match] even if T is not.
96+
const CFN8: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
97+
let input: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
98+
match Wrap(input) {
99+
Wrap(CFN8) => count += 1,
100+
Wrap(_) => {}
101+
};
102+
103+
// Check that fn() -> T is #[structural_match] even if T is not.
104+
const CFN9: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
105+
let input: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
106+
match Wrap(input) {
107+
Wrap(CFN9) => count += 1,
108+
Wrap(_) => {}
109+
};
110+
111+
// Check that a type which has fn ptrs is `#[structural_match]`.
112+
#[derive(PartialEq, Eq)]
113+
struct Foo {
114+
alpha: fn(NotSM),
115+
beta: fn() -> NotSM,
116+
gamma: fn(SM),
117+
delta: fn() -> SM,
118+
}
119+
120+
const CFOO: Foo = Foo {
121+
alpha: not_sm_to,
122+
beta: to_not_sm,
123+
gamma: sm_to,
124+
delta: to_sm,
125+
};
126+
127+
let input = Foo { alpha: not_sm_to, beta: to_not_sm, gamma: sm_to, delta: to_sm };
128+
match input {
129+
CFOO => count += 1,
130+
Foo { .. } => {}
131+
};
132+
133+
// Final count must be 10 now if all
134+
assert_eq!(count, 10);
135+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// run-pass
2+
3+
// The actual regression test from #63479. (Including this because my
4+
// first draft at fn-ptr-is-structurally-matchable.rs failed to actually
5+
// cover the case this hit; I've since expanded it accordingly, but the
6+
// experience left me wary of leaving this regression test out.)
7+
8+
#[derive(Eq)]
9+
struct A {
10+
a: i64
11+
}
12+
13+
impl PartialEq for A {
14+
#[inline]
15+
fn eq(&self, other: &Self) -> bool {
16+
self.a.eq(&other.a)
17+
}
18+
}
19+
20+
type Fn = fn(&[A]);
21+
22+
fn my_fn(_args: &[A]) {
23+
println!("hello world");
24+
}
25+
26+
const TEST: Fn = my_fn;
27+
28+
struct B(Fn);
29+
30+
fn main() {
31+
let s = B(my_fn);
32+
match s {
33+
B(TEST) => println!("matched"),
34+
_ => panic!("didn't match")
35+
};
36+
}

0 commit comments

Comments
 (0)