summaryrefslogtreecommitdiffstats
path: root/src/test/ui/methods/method-lookup-order.rs
blob: 986fe103cdc796cbd6f609d5341eb659fe660948 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// ignore-tidy-linelength

// run-pass

// There are five cfg's below. I explored the set of all non-empty combinations
// of the below five cfg's, which is 2^5 - 1 = 31 combinations.
//
// Of the 31, 11 resulted in ambiguous method resolutions; while it may be good
// to have a test for all of the eleven variations of that error, I am not sure
// this particular test is the best way to encode it. So they are skipped in
// this revisions list (but not in the expansion mapping the binary encoding to
// the corresponding cfg flags).
//
// Notable, here are the cases that will be incompatible if something does not override them first:
// {bar_for_foo, valbar_for_et_foo}: these are higher precedent than the `&mut self` method on `Foo`, and so no case matching bx1x1x is included.
// {mutbar_for_foo, valbar_for_etmut_foo} (which are lower precedent than the inherent `&mut self` method on `Foo`; e.g. b10101 *is* included.

// revisions: b00001 b00010 b00011 b00100 b00101 b00110 b00111 b01000 b01001 b01100 b01101 b10000 b10001 b10010 b10011 b10101 b10111 b11000 b11001 b11101

//[b00001]compile-flags:  --cfg inherent_mut
//[b00010]compile-flags:                     --cfg bar_for_foo
//[b00011]compile-flags:  --cfg inherent_mut --cfg bar_for_foo
//[b00100]compile-flags:                                       --cfg mutbar_for_foo
//[b00101]compile-flags:  --cfg inherent_mut                   --cfg mutbar_for_foo
//[b00110]compile-flags:                     --cfg bar_for_foo --cfg mutbar_for_foo
//[b00111]compile-flags:  --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo
//[b01000]compile-flags:                                                            --cfg valbar_for_et_foo
//[b01001]compile-flags:  --cfg inherent_mut                                        --cfg valbar_for_et_foo
//[b01010]compile-flags:                     --cfg bar_for_foo                      --cfg valbar_for_et_foo
//[b01011]compile-flags:  --cfg inherent_mut --cfg bar_for_foo                      --cfg valbar_for_et_foo
//[b01100]compile-flags:                                       --cfg mutbar_for_foo --cfg valbar_for_et_foo
//[b01101]compile-flags:  --cfg inherent_mut                   --cfg mutbar_for_foo --cfg valbar_for_et_foo
//[b01110]compile-flags:                     --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo
//[b01111]compile-flags:  --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo
//[b10000]compile-flags:                                                                                    --cfg valbar_for_etmut_foo
//[b10001]compile-flags:  --cfg inherent_mut                                                                --cfg valbar_for_etmut_foo
//[b10010]compile-flags:                     --cfg bar_for_foo                                              --cfg valbar_for_etmut_foo
//[b10011]compile-flags:  --cfg inherent_mut --cfg bar_for_foo                                              --cfg valbar_for_etmut_foo
//[b10100]compile-flags:                                       --cfg mutbar_for_foo                         --cfg valbar_for_etmut_foo
//[b10101]compile-flags:  --cfg inherent_mut                   --cfg mutbar_for_foo                         --cfg valbar_for_etmut_foo
//[b10110]compile-flags:                     --cfg bar_for_foo --cfg mutbar_for_foo                         --cfg valbar_for_etmut_foo
//[b10111]compile-flags:  --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo                         --cfg valbar_for_etmut_foo
//[b11000]compile-flags:                                                            --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
//[b11001]compile-flags:  --cfg inherent_mut                                        --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
//[b11010]compile-flags:                     --cfg bar_for_foo                      --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
//[b11011]compile-flags:  --cfg inherent_mut --cfg bar_for_foo                      --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
//[b11100]compile-flags:                                       --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
//[b11101]compile-flags:  --cfg inherent_mut                   --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
//[b11110]compile-flags:                     --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
//[b11111]compile-flags:  --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo

struct Foo {}

type S = &'static str;

trait Bar {
    fn bar(&self, _: &str) -> S;
}

trait MutBar {
    fn bar(&mut self, _: &str) -> S;
}

trait ValBar {
    fn bar(self, _: &str) -> S;
}

#[cfg(inherent_mut)]
impl Foo {
    fn bar(&mut self, _: &str) -> S {
        "In struct impl!"
    }
}

#[cfg(bar_for_foo)]
impl Bar for Foo {
    fn bar(&self, _: &str) -> S {
        "In trait &self impl!"
    }
}

#[cfg(mutbar_for_foo)]
impl MutBar for Foo {
    fn bar(&mut self, _: &str) -> S {
        "In trait &mut self impl!"
    }
}

#[cfg(valbar_for_et_foo)]
impl ValBar for &Foo {
    fn bar(self, _: &str) -> S {
        "In trait self impl for &Foo!"
    }
}

#[cfg(valbar_for_etmut_foo)]
impl ValBar for &mut Foo {
    fn bar(self, _: &str) -> S {
        "In trait self impl for &mut Foo!"
    }
}

fn main() {
    #![allow(unused_mut)] // some of the impls above will want it.

    #![allow(unreachable_patterns)] // the cfg-coding pattern below generates unreachable patterns.

    {
        macro_rules! all_variants_on_value {
            ($e:expr) => {
                match $e {
                    #[cfg(bar_for_foo)]
                    x => assert_eq!(x, "In trait &self impl!"),

                    #[cfg(valbar_for_et_foo)]
                    x => assert_eq!(x, "In trait self impl for &Foo!"),

                    #[cfg(inherent_mut)]
                    x => assert_eq!(x, "In struct impl!"),

                    #[cfg(mutbar_for_foo)]
                    x => assert_eq!(x, "In trait &mut self impl!"),

                    #[cfg(valbar_for_etmut_foo)]
                    x => assert_eq!(x, "In trait self impl for &mut Foo!"),
                }
            }
        }

        let mut f = Foo {};
        all_variants_on_value!(f.bar("f.bar"));

        let f_mr = &mut Foo {};
        all_variants_on_value!((*f_mr).bar("(*f_mr).bar"));
    }

    // This is sort of interesting: `&mut Foo` ends up with a significantly
    // different resolution order than what was devised above. Presumably this
    // is because we can get to a `&self` method by first a deref of the given
    // `&mut Foo` and then an autoref, and that is a longer path than a mere
    // auto-ref of a `Foo`.

    {
        let f_mr = &mut Foo {};

        match f_mr.bar("f_mr.bar") {
            #[cfg(inherent_mut)]
            x => assert_eq!(x, "In struct impl!"),

            #[cfg(valbar_for_etmut_foo)]
            x => assert_eq!(x, "In trait self impl for &mut Foo!"),

            #[cfg(mutbar_for_foo)]
            x => assert_eq!(x, "In trait &mut self impl!"),

            #[cfg(valbar_for_et_foo)]
            x => assert_eq!(x, "In trait self impl for &Foo!"),

            #[cfg(bar_for_foo)]
            x => assert_eq!(x, "In trait &self impl!"),
        }
    }


    // Note that this isn't actually testing a resolution order; if both of these are
    // enabled, it yields an ambiguous method resolution error. The test tries to embed
    // that fact by testing *both* orders (and so the only way that can be right is if
    // they are not actually compatible).
    #[cfg(any(bar_for_foo, valbar_for_et_foo))]
    {
        let f_r = &Foo {};

        match f_r.bar("f_r.bar") {
            #[cfg(bar_for_foo)]
            x => assert_eq!(x, "In trait &self impl!"),

            #[cfg(valbar_for_et_foo)]
            x => assert_eq!(x, "In trait self impl for &Foo!"),
        }

        match f_r.bar("f_r.bar") {
            #[cfg(valbar_for_et_foo)]
            x => assert_eq!(x, "In trait self impl for &Foo!"),

            #[cfg(bar_for_foo)]
            x => assert_eq!(x, "In trait &self impl!"),
        }
    }

}