// 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!"), } } }