// 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); // 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 = Wrap(trivial); let input: Wrap = Wrap(trivial); match Wrap(input) { Wrap(CFN1) => count += 1, Wrap(_) => {} }; // Check that fn(T) is structural-match when T is too. const CFN2: Wrap = Wrap(sm_to); let input: Wrap = 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 SM> = Wrap(to_sm); let input: Wrap 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 = Wrap(not_sm_to); let input: Wrap = 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 NotSM> = Wrap(to_not_sm); let input: Wrap 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 = Wrap(r_sm_to); let input: Wrap = 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 &SM> = Wrap(r_to_r_sm); let input: Wrap &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 = Wrap(r_not_sm_to); let input: Wrap = 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 &NotSM> = Wrap(r_to_r_not_sm); let input: Wrap &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); }