about summary refs log tree commit diff
path: root/tests/ui/methods/method-probe-no-guessing-dyn-trait.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/methods/method-probe-no-guessing-dyn-trait.rs')
-rw-r--r--tests/ui/methods/method-probe-no-guessing-dyn-trait.rs60
1 files changed, 60 insertions, 0 deletions
diff --git a/tests/ui/methods/method-probe-no-guessing-dyn-trait.rs b/tests/ui/methods/method-probe-no-guessing-dyn-trait.rs
new file mode 100644
index 00000000000..ec41b711709
--- /dev/null
+++ b/tests/ui/methods/method-probe-no-guessing-dyn-trait.rs
@@ -0,0 +1,60 @@
+// run-pass
+// Check that method matching does not make "guesses" depending on
+// Deref impls that don't eventually end up being picked.
+
+use std::ops::Deref;
+
+// An impl with less derefs will get called over an impl with more derefs,
+// so `(t: Foo<_>).my_fn()` will use `<Foo<u32> as MyTrait1>::my_fn(t)`,
+// and does *not* force the `_` to equal `()`, because the Deref impl
+// was *not* used.
+
+trait MyTrait1 {
+    fn my_fn(&self) {}
+}
+
+impl MyTrait1 for Foo<u32> {}
+
+struct Foo<T>(#[allow(unused_tuple_struct_fields)] T);
+
+impl Deref for Foo<()> {
+    type Target = dyn MyTrait1 + 'static;
+    fn deref(&self) -> &(dyn MyTrait1 + 'static) {
+        panic!()
+    }
+}
+
+// ...but if there is no impl with less derefs, the "guess" will be
+// forced, so `(t: Bar<_>).my_fn2()` is `<dyn MyTrait2 as MyTrait2>::my_fn2(*t)`,
+// and because the deref impl is used, the `_` is forced to equal `u8`.
+
+trait MyTrait2 {
+    fn my_fn2(&self) {}
+}
+
+impl MyTrait2 for u32 {}
+struct Bar<T>(#[allow(unused_tuple_struct_fields)] T, u32);
+impl Deref for Bar<u8> {
+    type Target = dyn MyTrait2 + 'static;
+    fn deref(&self) -> &(dyn MyTrait2 + 'static) {
+        &self.1
+    }
+}
+
+// actually invoke things
+
+fn main() {
+    let mut foo: Option<Foo<_>> = None;
+    let mut bar: Option<Bar<_>> = None;
+    let mut first_iter = true;
+    loop {
+        if !first_iter {
+            foo.as_ref().unwrap().my_fn();
+            bar.as_ref().unwrap().my_fn2();
+            break;
+        }
+        foo = Some(Foo(0));
+        bar = Some(Bar(Default::default(), 0));
+        first_iter = false;
+    }
+}