about summary refs log tree commit diff
path: root/src/test/ui/methods
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-07-27 01:33:01 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-07-27 18:56:16 +0300
commit9be35f82c1abf2ecbab489bca9eca138ea648312 (patch)
tree69888506e34af447d9748c0d542de3ba1dd76210 /src/test/ui/methods
parentca9faa52f5ada0054b1fa27d97aedf448afb059b (diff)
downloadrust-9be35f82c1abf2ecbab489bca9eca138ea648312.tar.gz
rust-9be35f82c1abf2ecbab489bca9eca138ea648312.zip
tests: Move run-pass tests without naming conflicts to ui
Diffstat (limited to 'src/test/ui/methods')
-rw-r--r--src/test/ui/methods/auxiliary/method_self_arg1.rs37
-rw-r--r--src/test/ui/methods/auxiliary/method_self_arg2.rs54
-rw-r--r--src/test/ui/methods/method-argument-inference-associated-type.rs28
-rw-r--r--src/test/ui/methods/method-early-bound-lifetimes-on-self.rs31
-rw-r--r--src/test/ui/methods/method-mut-self-modifies-mut-slice-lvalue.rs44
-rw-r--r--src/test/ui/methods/method-normalize-bounds-issue-20604.rs61
-rw-r--r--src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs60
-rw-r--r--src/test/ui/methods/method-projection.rs70
-rw-r--r--src/test/ui/methods/method-recursive-blanket-impl.rs41
-rw-r--r--src/test/ui/methods/method-self-arg-aux1.rs20
-rw-r--r--src/test/ui/methods/method-self-arg-aux2.rs24
-rw-r--r--src/test/ui/methods/method-self-arg-trait.rs69
-rw-r--r--src/test/ui/methods/method-self-arg.rs48
-rw-r--r--src/test/ui/methods/method-two-trait-defer-resolution-1.rs37
-rw-r--r--src/test/ui/methods/method-two-trait-defer-resolution-2.rs48
-rw-r--r--src/test/ui/methods/method-two-traits-distinguished-via-where-clause.rs27
-rw-r--r--src/test/ui/methods/method-where-clause.rs34
17 files changed, 733 insertions, 0 deletions
diff --git a/src/test/ui/methods/auxiliary/method_self_arg1.rs b/src/test/ui/methods/auxiliary/method_self_arg1.rs
new file mode 100644
index 00000000000..8258fdd9ab9
--- /dev/null
+++ b/src/test/ui/methods/auxiliary/method_self_arg1.rs
@@ -0,0 +1,37 @@
+#![crate_type = "lib"]
+
+#![feature(box_syntax)]
+
+static mut COUNT: u64 = 1;
+
+pub fn get_count() -> u64 { unsafe { COUNT } }
+
+#[derive(Copy, Clone)]
+pub struct Foo;
+
+impl Foo {
+    pub fn foo(self, x: &Foo) {
+        unsafe { COUNT *= 2; }
+        // Test internal call.
+        Foo::bar(&self);
+        Foo::bar(x);
+
+        Foo::baz(self);
+        Foo::baz(*x);
+
+        Foo::qux(box self);
+        Foo::qux(box *x);
+    }
+
+    pub fn bar(&self) {
+        unsafe { COUNT *= 3; }
+    }
+
+    pub fn baz(self) {
+        unsafe { COUNT *= 5; }
+    }
+
+    pub fn qux(self: Box<Foo>) {
+        unsafe { COUNT *= 7; }
+    }
+}
diff --git a/src/test/ui/methods/auxiliary/method_self_arg2.rs b/src/test/ui/methods/auxiliary/method_self_arg2.rs
new file mode 100644
index 00000000000..94a4a016c3e
--- /dev/null
+++ b/src/test/ui/methods/auxiliary/method_self_arg2.rs
@@ -0,0 +1,54 @@
+#![crate_type = "lib"]
+
+#![feature(box_syntax)]
+
+static mut COUNT: u64 = 1;
+
+pub fn get_count() -> u64 { unsafe { COUNT } }
+
+#[derive(Copy, Clone)]
+pub struct Foo;
+
+impl Foo {
+    pub fn run_trait(self) {
+        unsafe { COUNT *= 17; }
+        // Test internal call.
+        Bar::foo1(&self);
+        Bar::foo2(self);
+        Bar::foo3(box self);
+
+        Bar::bar1(&self);
+        Bar::bar2(self);
+        Bar::bar3(box self);
+    }
+}
+
+pub trait Bar : Sized {
+    fn foo1(&self);
+    fn foo2(self);
+    fn foo3(self: Box<Self>);
+
+    fn bar1(&self) {
+        unsafe { COUNT *= 7; }
+    }
+    fn bar2(self) {
+        unsafe { COUNT *= 11; }
+    }
+    fn bar3(self: Box<Self>) {
+        unsafe { COUNT *= 13; }
+    }
+}
+
+impl Bar for Foo {
+    fn foo1(&self) {
+        unsafe { COUNT *= 2; }
+    }
+
+    fn foo2(self) {
+        unsafe { COUNT *= 3; }
+    }
+
+    fn foo3(self: Box<Foo>) {
+        unsafe { COUNT *= 5; }
+    }
+}
diff --git a/src/test/ui/methods/method-argument-inference-associated-type.rs b/src/test/ui/methods/method-argument-inference-associated-type.rs
new file mode 100644
index 00000000000..acd4a8465b0
--- /dev/null
+++ b/src/test/ui/methods/method-argument-inference-associated-type.rs
@@ -0,0 +1,28 @@
+// run-pass
+pub struct ClientMap;
+pub struct ClientMap2;
+
+pub trait Service {
+    type Request;
+    fn call(&self, _req: Self::Request);
+}
+
+pub struct S<T>(T);
+
+impl Service for ClientMap {
+    type Request = S<Box<dyn Fn(i32)>>;
+    fn call(&self, _req: Self::Request) {}
+}
+
+
+impl Service for ClientMap2 {
+    type Request = (Box<dyn Fn(i32)>,);
+    fn call(&self, _req: Self::Request) {}
+}
+
+
+fn main() {
+    ClientMap.call(S { 0: Box::new(|_msgid| ()) });
+    ClientMap.call(S(Box::new(|_msgid| ())));
+    ClientMap2.call((Box::new(|_msgid| ()),));
+}
diff --git a/src/test/ui/methods/method-early-bound-lifetimes-on-self.rs b/src/test/ui/methods/method-early-bound-lifetimes-on-self.rs
new file mode 100644
index 00000000000..f2ace32c6b6
--- /dev/null
+++ b/src/test/ui/methods/method-early-bound-lifetimes-on-self.rs
@@ -0,0 +1,31 @@
+// run-pass
+// Check that we successfully handle methods where the `self` type has
+// an early-bound lifetime. Issue #18208.
+
+// pretty-expanded FIXME #23616
+
+#![allow(dead_code)]
+
+use std::marker;
+
+struct Cursor<'a> {
+    m: marker::PhantomData<&'a ()>
+}
+
+trait CursorNavigator {
+    fn init_cursor<'a, 'b:'a>(&'a self, cursor: &mut Cursor<'b>) -> bool;
+}
+
+struct SimpleNavigator;
+
+impl CursorNavigator for SimpleNavigator {
+    fn init_cursor<'a, 'b: 'a>(&'a self, _cursor: &mut Cursor<'b>) -> bool {
+        false
+    }
+}
+
+fn main() {
+    let mut c = Cursor { m: marker::PhantomData };
+    let n = SimpleNavigator;
+    n.init_cursor(&mut c);
+}
diff --git a/src/test/ui/methods/method-mut-self-modifies-mut-slice-lvalue.rs b/src/test/ui/methods/method-mut-self-modifies-mut-slice-lvalue.rs
new file mode 100644
index 00000000000..daff037b27b
--- /dev/null
+++ b/src/test/ui/methods/method-mut-self-modifies-mut-slice-lvalue.rs
@@ -0,0 +1,44 @@
+// run-pass
+// Test that an `&mut self` method, when invoked on a place whose
+// type is `&mut [u8]`, passes in a pointer to the place and not a
+// temporary. Issue #19147.
+
+use std::slice;
+use std::cmp;
+
+trait MyWriter {
+    fn my_write(&mut self, buf: &[u8]) -> Result<(), ()>;
+}
+
+impl<'a> MyWriter for &'a mut [u8] {
+    fn my_write(&mut self, buf: &[u8]) -> Result<(), ()> {
+        let amt = cmp::min(self.len(), buf.len());
+        self[..amt].clone_from_slice(&buf[..amt]);
+
+        let write_len = buf.len();
+        unsafe {
+            *self = slice::from_raw_parts_mut(
+                self.as_mut_ptr().add(write_len),
+                self.len() - write_len
+            );
+        }
+
+        Ok(())
+    }
+}
+
+fn main() {
+    let mut buf = [0; 6];
+
+    {
+        let mut writer: &mut [_] = &mut buf;
+        writer.my_write(&[0, 1, 2]).unwrap();
+        writer.my_write(&[3, 4, 5]).unwrap();
+    }
+
+    // If `my_write` is not modifying `buf` in place, then we will
+    // wind up with `[3, 4, 5, 0, 0, 0]` because the first call to
+    // `my_write()` doesn't update the starting point for the write.
+
+    assert_eq!(buf, [0, 1, 2, 3, 4, 5]);
+}
diff --git a/src/test/ui/methods/method-normalize-bounds-issue-20604.rs b/src/test/ui/methods/method-normalize-bounds-issue-20604.rs
new file mode 100644
index 00000000000..9c0b952849e
--- /dev/null
+++ b/src/test/ui/methods/method-normalize-bounds-issue-20604.rs
@@ -0,0 +1,61 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(stable_features)]
+
+// Test that we handle projection types which wind up important for
+// resolving methods. This test was reduced from a larger example; the
+// call to `foo()` at the end was failing to resolve because the
+// winnowing stage of method resolution failed to handle an associated
+// type projection.
+
+// pretty-expanded FIXME #23616
+
+#![feature(associated_types)]
+
+trait Hasher {
+    type Output;
+    fn finish(&self) -> Self::Output;
+}
+
+trait Hash<H: Hasher> {
+    fn hash(&self, h: &mut H);
+}
+
+trait HashState {
+    type Wut: Hasher;
+    fn hasher(&self) -> Self::Wut;
+}
+
+struct SipHasher;
+impl Hasher for SipHasher {
+    type Output = u64;
+    fn finish(&self) -> u64 { 4 }
+}
+
+impl Hash<SipHasher> for isize {
+    fn hash(&self, h: &mut SipHasher) {}
+}
+
+struct SipState;
+impl HashState for SipState {
+    type Wut = SipHasher;
+    fn hasher(&self) -> SipHasher { SipHasher }
+}
+
+struct Map<S> {
+    s: S,
+}
+
+impl<S> Map<S>
+    where S: HashState,
+          <S as HashState>::Wut: Hasher<Output=u64>,
+{
+    fn foo<K>(&self, k: K) where K: Hash< <S as HashState>::Wut> {}
+}
+
+fn foo<K: Hash<SipHasher>>(map: &Map<SipState>) {
+    map.foo(22);
+}
+
+fn main() {}
diff --git a/src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs b/src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs
new file mode 100644
index 00000000000..af362efe15c
--- /dev/null
+++ b/src/test/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>(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>(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;
+    }
+}
diff --git a/src/test/ui/methods/method-projection.rs b/src/test/ui/methods/method-projection.rs
new file mode 100644
index 00000000000..cf33d53968b
--- /dev/null
+++ b/src/test/ui/methods/method-projection.rs
@@ -0,0 +1,70 @@
+// run-pass
+// Test that we can use method notation to call methods based on a
+// projection bound from a trait. Issue #20469.
+
+///////////////////////////////////////////////////////////////////////////
+
+
+trait MakeString {
+    fn make_string(&self) -> String;
+}
+
+impl MakeString for isize {
+    fn make_string(&self) -> String {
+        format!("{}", *self)
+    }
+}
+
+impl MakeString for usize {
+    fn make_string(&self) -> String {
+        format!("{}", *self)
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+trait Foo {
+    type F: MakeString;
+
+    fn get(&self) -> &Self::F;
+}
+
+fn foo<F:Foo>(f: &F) -> String {
+    f.get().make_string()
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+struct SomeStruct {
+    field: isize,
+}
+
+impl Foo for SomeStruct {
+    type F = isize;
+
+    fn get(&self) -> &isize {
+        &self.field
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+struct SomeOtherStruct {
+    field: usize,
+}
+
+impl Foo for SomeOtherStruct {
+    type F = usize;
+
+    fn get(&self) -> &usize {
+        &self.field
+    }
+}
+
+fn main() {
+    let x = SomeStruct { field: 22 };
+    assert_eq!(foo(&x), format!("22"));
+
+    let x = SomeOtherStruct { field: 44 };
+    assert_eq!(foo(&x), format!("44"));
+}
diff --git a/src/test/ui/methods/method-recursive-blanket-impl.rs b/src/test/ui/methods/method-recursive-blanket-impl.rs
new file mode 100644
index 00000000000..a2db75b4e85
--- /dev/null
+++ b/src/test/ui/methods/method-recursive-blanket-impl.rs
@@ -0,0 +1,41 @@
+// run-pass
+#![allow(unused_variables)]
+#![allow(unused_imports)]
+// Test that we don't trigger on the blanket impl for all `&'a T` but
+// rather keep autoderefing and trigger on the underlying impl.  To
+// know not to stop at the blanket, we have to recursively evaluate
+// the `T:Foo` bound.
+
+// pretty-expanded FIXME #23616
+
+use std::marker::Sized;
+
+// Note: this must be generic for the problem to show up
+trait Foo<A> {
+    fn foo(&self, a: A);
+}
+
+impl Foo<u8> for [u8] {
+    fn foo(&self, a: u8) {}
+}
+
+impl<'a, A, T> Foo<A> for &'a T where T: Foo<A> {
+    fn foo(&self, a: A) {
+        Foo::foo(*self, a)
+    }
+}
+
+trait Bar {
+    fn foo(&self);
+}
+
+struct MyType;
+
+impl Bar for MyType {
+    fn foo(&self) {}
+}
+
+fn main() {
+    let mut m = MyType;
+    (&mut m).foo()
+}
diff --git a/src/test/ui/methods/method-self-arg-aux1.rs b/src/test/ui/methods/method-self-arg-aux1.rs
new file mode 100644
index 00000000000..9e38ff7de34
--- /dev/null
+++ b/src/test/ui/methods/method-self-arg-aux1.rs
@@ -0,0 +1,20 @@
+// run-pass
+// Test method calls with self as an argument (cross-crate)
+
+#![feature(box_syntax)]
+
+// aux-build:method_self_arg1.rs
+extern crate method_self_arg1;
+use method_self_arg1::Foo;
+
+fn main() {
+    let x = Foo;
+    // Test external call.
+    Foo::bar(&x);
+    Foo::baz(x);
+    Foo::qux(box x);
+
+    x.foo(&x);
+
+    assert_eq!(method_self_arg1::get_count(), 2*3*3*3*5*5*5*7*7*7);
+}
diff --git a/src/test/ui/methods/method-self-arg-aux2.rs b/src/test/ui/methods/method-self-arg-aux2.rs
new file mode 100644
index 00000000000..8e70399d047
--- /dev/null
+++ b/src/test/ui/methods/method-self-arg-aux2.rs
@@ -0,0 +1,24 @@
+// run-pass
+// Test method calls with self as an argument (cross-crate)
+
+#![feature(box_syntax)]
+
+// aux-build:method_self_arg2.rs
+extern crate method_self_arg2;
+use method_self_arg2::{Foo, Bar};
+
+fn main() {
+    let x = Foo;
+    // Test external call.
+    Bar::foo1(&x);
+    Bar::foo2(x);
+    Bar::foo3(box x);
+
+    Bar::bar1(&x);
+    Bar::bar2(x);
+    Bar::bar3(box x);
+
+    x.run_trait();
+
+    assert_eq!(method_self_arg2::get_count(), 2*2*3*3*5*5*7*7*11*11*13*13*17);
+}
diff --git a/src/test/ui/methods/method-self-arg-trait.rs b/src/test/ui/methods/method-self-arg-trait.rs
new file mode 100644
index 00000000000..227b1eab25d
--- /dev/null
+++ b/src/test/ui/methods/method-self-arg-trait.rs
@@ -0,0 +1,69 @@
+// run-pass
+// Test method calls with self as an argument
+
+#![feature(box_syntax)]
+
+static mut COUNT: u64 = 1;
+
+#[derive(Copy, Clone)]
+struct Foo;
+
+trait Bar : Sized {
+    fn foo1(&self);
+    fn foo2(self);
+    fn foo3(self: Box<Self>);
+
+    fn bar1(&self) {
+        unsafe { COUNT *= 7; }
+    }
+    fn bar2(self) {
+        unsafe { COUNT *= 11; }
+    }
+    fn bar3(self: Box<Self>) {
+        unsafe { COUNT *= 13; }
+    }
+}
+
+impl Bar for Foo {
+    fn foo1(&self) {
+        unsafe { COUNT *= 2; }
+    }
+
+    fn foo2(self) {
+        unsafe { COUNT *= 3; }
+    }
+
+    fn foo3(self: Box<Foo>) {
+        unsafe { COUNT *= 5; }
+    }
+}
+
+impl Foo {
+    fn baz(self) {
+        unsafe { COUNT *= 17; }
+        // Test internal call.
+        Bar::foo1(&self);
+        Bar::foo2(self);
+        Bar::foo3(box self);
+
+        Bar::bar1(&self);
+        Bar::bar2(self);
+        Bar::bar3(box self);
+    }
+}
+
+fn main() {
+    let x = Foo;
+    // Test external call.
+    Bar::foo1(&x);
+    Bar::foo2(x);
+    Bar::foo3(box x);
+
+    Bar::bar1(&x);
+    Bar::bar2(x);
+    Bar::bar3(box x);
+
+    x.baz();
+
+    unsafe { assert_eq!(COUNT, 2*2*3*3*5*5*7*7*11*11*13*13*17); }
+}
diff --git a/src/test/ui/methods/method-self-arg.rs b/src/test/ui/methods/method-self-arg.rs
new file mode 100644
index 00000000000..2d25b0dbad1
--- /dev/null
+++ b/src/test/ui/methods/method-self-arg.rs
@@ -0,0 +1,48 @@
+// run-pass
+// Test method calls with self as an argument
+
+#![feature(box_syntax)]
+
+static mut COUNT: usize = 1;
+
+#[derive(Copy, Clone)]
+struct Foo;
+
+impl Foo {
+    fn foo(self, x: &Foo) {
+        unsafe { COUNT *= 2; }
+        // Test internal call.
+        Foo::bar(&self);
+        Foo::bar(x);
+
+        Foo::baz(self);
+        Foo::baz(*x);
+
+        Foo::qux(box self);
+        Foo::qux(box *x);
+    }
+
+    fn bar(&self) {
+        unsafe { COUNT *= 3; }
+    }
+
+    fn baz(self) {
+        unsafe { COUNT *= 5; }
+    }
+
+    fn qux(self: Box<Foo>) {
+        unsafe { COUNT *= 7; }
+    }
+}
+
+fn main() {
+    let x = Foo;
+    // Test external call.
+    Foo::bar(&x);
+    Foo::baz(x);
+    Foo::qux(box x);
+
+    x.foo(&x);
+
+    unsafe { assert_eq!(COUNT, 2*3*3*3*5*5*5*7*7*7); }
+}
diff --git a/src/test/ui/methods/method-two-trait-defer-resolution-1.rs b/src/test/ui/methods/method-two-trait-defer-resolution-1.rs
new file mode 100644
index 00000000000..b768620cd3a
--- /dev/null
+++ b/src/test/ui/methods/method-two-trait-defer-resolution-1.rs
@@ -0,0 +1,37 @@
+// run-pass
+#![allow(non_camel_case_types)]
+
+// Test that we pick which version of `foo` to run based on the
+// type that is (ultimately) inferred for `x`.
+
+
+trait foo {
+    fn foo(&self) -> i32;
+}
+
+impl foo for Vec<u32> {
+    fn foo(&self) -> i32 {1}
+}
+
+impl foo for Vec<i32> {
+    fn foo(&self) -> i32 {2}
+}
+
+fn call_foo_uint() -> i32 {
+    let mut x = Vec::new();
+    let y = x.foo();
+    x.push(0u32);
+    y
+}
+
+fn call_foo_int() -> i32 {
+    let mut x = Vec::new();
+    let y = x.foo();
+    x.push(0i32);
+    y
+}
+
+fn main() {
+    assert_eq!(call_foo_uint(), 1);
+    assert_eq!(call_foo_int(), 2);
+}
diff --git a/src/test/ui/methods/method-two-trait-defer-resolution-2.rs b/src/test/ui/methods/method-two-trait-defer-resolution-2.rs
new file mode 100644
index 00000000000..8af3dcf5c3d
--- /dev/null
+++ b/src/test/ui/methods/method-two-trait-defer-resolution-2.rs
@@ -0,0 +1,48 @@
+// run-pass
+// Test that when we write `x.foo()`, we do not have to know the
+// complete type of `x` in order to type-check the method call. In
+// this case, we know that `x: Vec<_1>`, but we don't know what type
+// `_1` is (because the call to `push` comes later). To pick between
+// the impls, we would have to know `_1`, since we have to know
+// whether `_1: MyCopy` or `_1 == Box<i32>`.  However (and this is the
+// point of the test), we don't have to pick between the two impls --
+// it is enough to know that `foo` comes from the `Foo` trait. We can
+// codegen the call as `Foo::foo(&x)` and let the specific impl get
+// chosen later.
+
+#![feature(box_syntax)]
+
+trait Foo {
+    fn foo(&self) -> isize;
+}
+
+trait MyCopy { fn foo(&self) { } }
+impl MyCopy for i32 { }
+
+impl<T:MyCopy> Foo for Vec<T> {
+    fn foo(&self) -> isize {1}
+}
+
+impl Foo for Vec<Box<i32>> {
+    fn foo(&self) -> isize {2}
+}
+
+fn call_foo_copy() -> isize {
+    let mut x = Vec::new();
+    let y = x.foo();
+    x.push(0_i32);
+    y
+}
+
+fn call_foo_other() -> isize {
+    let mut x: Vec<_> = Vec::new();
+    let y = x.foo();
+    let z: Box<i32> = box 0;
+    x.push(z);
+    y
+}
+
+fn main() {
+    assert_eq!(call_foo_copy(), 1);
+    assert_eq!(call_foo_other(), 2);
+}
diff --git a/src/test/ui/methods/method-two-traits-distinguished-via-where-clause.rs b/src/test/ui/methods/method-two-traits-distinguished-via-where-clause.rs
new file mode 100644
index 00000000000..d820d2ad08a
--- /dev/null
+++ b/src/test/ui/methods/method-two-traits-distinguished-via-where-clause.rs
@@ -0,0 +1,27 @@
+// run-pass
+// Test that we select between traits A and B. To do that, we must
+// consider the `Sized` bound.
+
+// pretty-expanded FIXME #23616
+
+trait A {
+    fn foo(self);
+}
+
+trait B {
+    fn foo(self);
+}
+
+impl<T: Sized> A for *const T {
+    fn foo(self) {}
+}
+
+impl<T> B for *const [T] {
+    fn foo(self) {}
+}
+
+fn main() {
+    let x: [isize; 4] = [1,2,3,4];
+    let xptr = &x[..] as *const [isize];
+    xptr.foo();
+}
diff --git a/src/test/ui/methods/method-where-clause.rs b/src/test/ui/methods/method-where-clause.rs
new file mode 100644
index 00000000000..01692abf9b6
--- /dev/null
+++ b/src/test/ui/methods/method-where-clause.rs
@@ -0,0 +1,34 @@
+// run-pass
+// Test that we can use method notation to call methods based on a
+// where clause type, and not only type parameters.
+
+
+trait Foo {
+    fn foo(&self) -> i32;
+}
+
+impl Foo for Option<i32>
+{
+    fn foo(&self) -> i32 {
+        self.unwrap_or(22)
+    }
+}
+
+impl Foo for Option<u32>
+{
+    fn foo(&self) -> i32 {
+        self.unwrap_or(22) as i32
+    }
+}
+
+fn check<T>(x: Option<T>) -> (i32, i32)
+    where Option<T> : Foo
+{
+    let y: Option<T> = None;
+    (x.foo(), y.foo())
+}
+
+fn main() {
+    assert_eq!(check(Some(23u32)), (23, 22));
+    assert_eq!(check(Some(23)), (23, 22));
+}