diff options
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.rs | 60 |
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 000000000..ec41b7117 --- /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; + } +} |