summaryrefslogtreecommitdiffstats
path: root/tests/ui/methods/method-lookup-order.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/methods/method-lookup-order.rs')
-rw-r--r--tests/ui/methods/method-lookup-order.rs190
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!"),
+ }
+ }
+
+}