about summary refs log tree commit diff
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 00000000000..986fe103cdc
--- /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!"),
+        }
+    }
+
+}