diff options
Diffstat (limited to 'tests/ui/methods/method-lookup-order.rs')
-rw-r--r-- | tests/ui/methods/method-lookup-order.rs | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/tests/ui/methods/method-lookup-order.rs b/tests/ui/methods/method-lookup-order.rs new file mode 100644 index 000000000..986fe103c --- /dev/null +++ b/tests/ui/methods/method-lookup-order.rs @@ -0,0 +1,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!"), + } + } + +} |