summaryrefslogtreecommitdiffstats
path: root/src/test/ui/overloaded
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/overloaded')
-rw-r--r--src/test/ui/overloaded/auxiliary/overloaded_autoderef_xc.rs30
-rw-r--r--src/test/ui/overloaded/fixup-deref-mut.rs50
-rw-r--r--src/test/ui/overloaded/issue-14958.rs31
-rw-r--r--src/test/ui/overloaded/overloaded-autoderef-count.rs74
-rw-r--r--src/test/ui/overloaded/overloaded-autoderef-indexing.rs20
-rw-r--r--src/test/ui/overloaded/overloaded-autoderef-order.rs73
-rw-r--r--src/test/ui/overloaded/overloaded-autoderef-vtable.rs39
-rw-r--r--src/test/ui/overloaded/overloaded-autoderef-xcrate.rs9
-rw-r--r--src/test/ui/overloaded/overloaded-autoderef.rs43
-rw-r--r--src/test/ui/overloaded/overloaded-calls-nontuple.rs29
-rw-r--r--src/test/ui/overloaded/overloaded-calls-nontuple.stderr21
-rw-r--r--src/test/ui/overloaded/overloaded-calls-object-one-arg.rs13
-rw-r--r--src/test/ui/overloaded/overloaded-calls-object-two-args.rs13
-rw-r--r--src/test/ui/overloaded/overloaded-calls-object-zero-args.rs13
-rw-r--r--src/test/ui/overloaded/overloaded-calls-param-vtables.rs32
-rw-r--r--src/test/ui/overloaded/overloaded-calls-simple.rs78
-rw-r--r--src/test/ui/overloaded/overloaded-calls-zero-args.rs30
-rw-r--r--src/test/ui/overloaded/overloaded-deref-count.rs78
-rw-r--r--src/test/ui/overloaded/overloaded-deref.rs43
-rw-r--r--src/test/ui/overloaded/overloaded-index-assoc-list.rs48
-rw-r--r--src/test/ui/overloaded/overloaded-index-autoderef.rs75
-rw-r--r--src/test/ui/overloaded/overloaded-index-in-field.rs46
-rw-r--r--src/test/ui/overloaded/overloaded-index.rs64
-rw-r--r--src/test/ui/overloaded/overloaded_deref_with_ref_pattern.rs95
-rw-r--r--src/test/ui/overloaded/overloaded_deref_with_ref_pattern_issue15609.rs37
25 files changed, 1084 insertions, 0 deletions
diff --git a/src/test/ui/overloaded/auxiliary/overloaded_autoderef_xc.rs b/src/test/ui/overloaded/auxiliary/overloaded_autoderef_xc.rs
new file mode 100644
index 000000000..112455f91
--- /dev/null
+++ b/src/test/ui/overloaded/auxiliary/overloaded_autoderef_xc.rs
@@ -0,0 +1,30 @@
+use std::ops::Deref;
+
+struct DerefWithHelper<H, T> {
+ pub helper: H,
+ pub value: Option<T>
+}
+
+trait Helper<T> {
+ fn helper_borrow(&self) -> &T;
+}
+
+impl<T> Helper<T> for Option<T> {
+ fn helper_borrow(&self) -> &T {
+ self.as_ref().unwrap()
+ }
+}
+
+impl<T, H: Helper<T>> Deref for DerefWithHelper<H, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ self.helper.helper_borrow()
+ }
+}
+
+// Test cross-crate autoderef + vtable.
+pub fn check<T: PartialEq>(x: T, y: T) -> bool {
+ let d: DerefWithHelper<Option<T>, T> = DerefWithHelper { helper: Some(x), value: None };
+ d.eq(&y)
+}
diff --git a/src/test/ui/overloaded/fixup-deref-mut.rs b/src/test/ui/overloaded/fixup-deref-mut.rs
new file mode 100644
index 000000000..6b2fd72b8
--- /dev/null
+++ b/src/test/ui/overloaded/fixup-deref-mut.rs
@@ -0,0 +1,50 @@
+// run-pass
+
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+use std::ops::{Deref, DerefMut};
+
+// Generic unique/owned smaht pointer.
+struct Own<T> {
+ value: *mut T
+}
+
+impl<T> Deref for Own<T> {
+ type Target = T;
+
+ fn deref<'a>(&'a self) -> &'a T {
+ unsafe { &*self.value }
+ }
+}
+
+impl<T> DerefMut for Own<T> {
+ fn deref_mut<'a>(&'a mut self) -> &'a mut T {
+ unsafe { &mut *self.value }
+ }
+}
+
+struct Point {
+ x: isize,
+ y: isize
+}
+
+impl Point {
+ fn get(&mut self) -> (isize, isize) {
+ (self.x, self.y)
+ }
+}
+
+fn test0(mut x: Own<Point>) {
+ let _ = x.get();
+}
+
+fn test1(mut x: Own<Own<Own<Point>>>) {
+ let _ = x.get();
+}
+
+fn test2(mut x: Own<Own<Own<Point>>>) {
+ let _ = (**x).get();
+}
+
+fn main() {}
diff --git a/src/test/ui/overloaded/issue-14958.rs b/src/test/ui/overloaded/issue-14958.rs
new file mode 100644
index 000000000..a12564ca9
--- /dev/null
+++ b/src/test/ui/overloaded/issue-14958.rs
@@ -0,0 +1,31 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+#![feature(fn_traits, unboxed_closures)]
+
+trait Foo { fn dummy(&self) { }}
+
+struct Bar;
+
+impl<'a> std::ops::Fn<(&'a (dyn Foo+'a),)> for Bar {
+ extern "rust-call" fn call(&self, _: (&'a dyn Foo,)) {}
+}
+
+impl<'a> std::ops::FnMut<(&'a (dyn Foo+'a),)> for Bar {
+ extern "rust-call" fn call_mut(&mut self, a: (&'a dyn Foo,)) { self.call(a) }
+}
+
+impl<'a> std::ops::FnOnce<(&'a (dyn Foo+'a),)> for Bar {
+ type Output = ();
+ extern "rust-call" fn call_once(self, a: (&'a dyn Foo,)) { self.call(a) }
+}
+
+struct Baz;
+
+impl Foo for Baz {}
+
+fn main() {
+ let bar = Bar;
+ let baz = &Baz;
+ bar(baz);
+}
diff --git a/src/test/ui/overloaded/overloaded-autoderef-count.rs b/src/test/ui/overloaded/overloaded-autoderef-count.rs
new file mode 100644
index 000000000..d58deda09
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-autoderef-count.rs
@@ -0,0 +1,74 @@
+// run-pass
+use std::cell::Cell;
+use std::ops::{Deref, DerefMut};
+
+#[derive(PartialEq)]
+struct DerefCounter<T> {
+ count_imm: Cell<usize>,
+ count_mut: usize,
+ value: T
+}
+
+impl<T> DerefCounter<T> {
+ fn new(value: T) -> DerefCounter<T> {
+ DerefCounter {
+ count_imm: Cell::new(0),
+ count_mut: 0,
+ value: value
+ }
+ }
+
+ fn counts(&self) -> (usize, usize) {
+ (self.count_imm.get(), self.count_mut)
+ }
+}
+
+impl<T> Deref for DerefCounter<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ self.count_imm.set(self.count_imm.get() + 1);
+ &self.value
+ }
+}
+
+impl<T> DerefMut for DerefCounter<T> {
+ fn deref_mut(&mut self) -> &mut T {
+ self.count_mut += 1;
+ &mut self.value
+ }
+}
+
+#[derive(PartialEq, Debug)]
+struct Point {
+ x: isize,
+ y: isize
+}
+
+impl Point {
+ fn get(&self) -> (isize, isize) {
+ (self.x, self.y)
+ }
+}
+
+pub fn main() {
+ let mut p = DerefCounter::new(Point {x: 0, y: 0});
+
+ let _ = p.x;
+ assert_eq!(p.counts(), (1, 0));
+
+ let _ = &p.x;
+ assert_eq!(p.counts(), (2, 0));
+
+ let _ = &mut p.y;
+ assert_eq!(p.counts(), (2, 1));
+
+ p.x += 3;
+ assert_eq!(p.counts(), (2, 2));
+
+ p.get();
+ assert_eq!(p.counts(), (3, 2));
+
+ // Check the final state.
+ assert_eq!(*p, Point {x: 3, y: 0});
+}
diff --git a/src/test/ui/overloaded/overloaded-autoderef-indexing.rs b/src/test/ui/overloaded/overloaded-autoderef-indexing.rs
new file mode 100644
index 000000000..1c8c7cca9
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-autoderef-indexing.rs
@@ -0,0 +1,20 @@
+// run-pass
+
+use std::ops::Deref;
+
+struct DerefArray<'a, T:'a> {
+ inner: &'a [T]
+}
+
+impl<'a, T> Deref for DerefArray<'a, T> {
+ type Target = &'a [T];
+
+ fn deref<'b>(&'b self) -> &'b &'a [T] {
+ &self.inner
+ }
+}
+
+pub fn main() {
+ let a = &[1, 2, 3];
+ assert_eq!(DerefArray {inner: a}[1], 2);
+}
diff --git a/src/test/ui/overloaded/overloaded-autoderef-order.rs b/src/test/ui/overloaded/overloaded-autoderef-order.rs
new file mode 100644
index 000000000..f48bae55f
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-autoderef-order.rs
@@ -0,0 +1,73 @@
+// run-pass
+
+#![allow(dead_code)]
+
+use std::rc::Rc;
+use std::ops::Deref;
+
+#[derive(Copy, Clone)]
+struct DerefWrapper<X, Y> {
+ x: X,
+ y: Y
+}
+
+impl<X, Y> DerefWrapper<X, Y> {
+ fn get_x(self) -> X {
+ self.x
+ }
+}
+
+impl<X, Y> Deref for DerefWrapper<X, Y> {
+ type Target = Y;
+
+ fn deref(&self) -> &Y {
+ &self.y
+ }
+}
+
+mod priv_test {
+ use std::ops::Deref;
+
+ #[derive(Copy, Clone)]
+ pub struct DerefWrapperHideX<X, Y> {
+ x: X,
+ pub y: Y
+ }
+
+ impl<X, Y> DerefWrapperHideX<X, Y> {
+ pub fn new(x: X, y: Y) -> DerefWrapperHideX<X, Y> {
+ DerefWrapperHideX {
+ x: x,
+ y: y
+ }
+ }
+ }
+
+ impl<X, Y> Deref for DerefWrapperHideX<X, Y> {
+ type Target = Y;
+
+ fn deref(&self) -> &Y {
+ &self.y
+ }
+ }
+}
+
+pub fn main() {
+ let nested = DerefWrapper {x: true, y: DerefWrapper {x: 0, y: 1}};
+
+ // Use the first field that you can find.
+ assert_eq!(nested.x, true);
+ assert_eq!((*nested).x, 0);
+
+ // Same for methods, even though there are multiple
+ // candidates (at different nesting levels).
+ assert_eq!(nested.get_x(), true);
+ assert_eq!((*nested).get_x(), 0);
+
+ // Also go through multiple levels of indirection.
+ assert_eq!(Rc::new(nested).x, true);
+
+ let nested_priv = priv_test::DerefWrapperHideX::new(true, DerefWrapper {x: 0, y: 1});
+ assert_eq!(nested_priv.x, 0);
+ assert_eq!((*nested_priv).x, 0);
+}
diff --git a/src/test/ui/overloaded/overloaded-autoderef-vtable.rs b/src/test/ui/overloaded/overloaded-autoderef-vtable.rs
new file mode 100644
index 000000000..f8e6d1208
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-autoderef-vtable.rs
@@ -0,0 +1,39 @@
+// run-pass
+#![allow(dead_code)]
+
+use std::ops::Deref;
+
+struct DerefWithHelper<H, T> {
+ helper: H,
+ value: T
+}
+
+trait Helper<T> {
+ fn helper_borrow(&self) -> &T;
+}
+
+impl<T> Helper<T> for Option<T> {
+ fn helper_borrow(&self) -> &T {
+ self.as_ref().unwrap()
+ }
+}
+
+impl<T, H: Helper<T>> Deref for DerefWithHelper<H, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ self.helper.helper_borrow()
+ }
+}
+
+struct Foo {x: isize}
+
+impl Foo {
+ fn foo(&self) -> isize {self.x}
+}
+
+pub fn main() {
+ let x: DerefWithHelper<Option<Foo>, Foo> =
+ DerefWithHelper { helper: Some(Foo {x: 5}), value: Foo { x: 2 } };
+ assert_eq!(x.foo(), 5);
+}
diff --git a/src/test/ui/overloaded/overloaded-autoderef-xcrate.rs b/src/test/ui/overloaded/overloaded-autoderef-xcrate.rs
new file mode 100644
index 000000000..d065e825c
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-autoderef-xcrate.rs
@@ -0,0 +1,9 @@
+// run-pass
+// aux-build:overloaded_autoderef_xc.rs
+
+
+extern crate overloaded_autoderef_xc;
+
+fn main() {
+ assert!(overloaded_autoderef_xc::check(5, 5));
+}
diff --git a/src/test/ui/overloaded/overloaded-autoderef.rs b/src/test/ui/overloaded/overloaded-autoderef.rs
new file mode 100644
index 000000000..cae3ec906
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-autoderef.rs
@@ -0,0 +1,43 @@
+// run-pass
+#![allow(unused_variables)]
+#![allow(stable_features)]
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+#[derive(PartialEq, Debug)]
+struct Point {
+ x: isize,
+ y: isize
+}
+
+pub fn main() {
+ let box_5: Box<_> = Box::new(5_usize);
+ let point = Rc::new(Point {x: 2, y: 4});
+ assert_eq!(point.x, 2);
+ assert_eq!(point.y, 4);
+
+ let i = Rc::new(RefCell::new(2));
+ let i_value = *i.borrow();
+ *i.borrow_mut() = 5;
+ assert_eq!((i_value, *i.borrow()), (2, 5));
+
+ let s = Rc::new("foo".to_string());
+ assert_eq!(&**s, "foo");
+
+ let mut_s = Rc::new(RefCell::new(String::from("foo")));
+ mut_s.borrow_mut().push_str("bar");
+ // HACK assert_eq! would panic here because it stores the LHS and RHS in two locals.
+ assert_eq!(&**mut_s.borrow(), "foobar");
+ assert_eq!(&**mut_s.borrow_mut(), "foobar");
+
+ let p = Rc::new(RefCell::new(Point {x: 1, y: 2}));
+ p.borrow_mut().x = 3;
+ p.borrow_mut().y += 3;
+ assert_eq!(*p.borrow(), Point {x: 3, y: 5});
+
+ let v = Rc::new(RefCell::new([1, 2, 3]));
+ v.borrow_mut()[0] = 3;
+ v.borrow_mut()[1] += 3;
+ assert_eq!((v.borrow()[0], v.borrow()[1], v.borrow()[2]), (3, 5, 3));
+}
diff --git a/src/test/ui/overloaded/overloaded-calls-nontuple.rs b/src/test/ui/overloaded/overloaded-calls-nontuple.rs
new file mode 100644
index 000000000..07d44ff82
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-calls-nontuple.rs
@@ -0,0 +1,29 @@
+#![feature(fn_traits, unboxed_closures)]
+
+use std::ops::FnMut;
+
+struct S {
+ x: isize,
+ y: isize,
+}
+
+impl FnMut<isize> for S {
+ extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
+ self.x + self.y + z
+ }
+ //~^^^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+}
+
+impl FnOnce<isize> for S {
+ type Output = isize;
+ extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
+ //~^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+}
+
+fn main() {
+ let mut s = S {
+ x: 1,
+ y: 2,
+ };
+ drop(s(3)) //~ ERROR cannot use call notation
+}
diff --git a/src/test/ui/overloaded/overloaded-calls-nontuple.stderr b/src/test/ui/overloaded/overloaded-calls-nontuple.stderr
new file mode 100644
index 000000000..8f299bc94
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-calls-nontuple.stderr
@@ -0,0 +1,21 @@
+error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
+ --> $DIR/overloaded-calls-nontuple.rs:11:5
+ |
+LL | extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
+ --> $DIR/overloaded-calls-nontuple.rs:19:5
+ |
+LL | extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit
+ --> $DIR/overloaded-calls-nontuple.rs:28:10
+ |
+LL | drop(s(3))
+ | ^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0059`.
diff --git a/src/test/ui/overloaded/overloaded-calls-object-one-arg.rs b/src/test/ui/overloaded/overloaded-calls-object-one-arg.rs
new file mode 100644
index 000000000..1afab9a1f
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-calls-object-one-arg.rs
@@ -0,0 +1,13 @@
+// run-pass
+// Tests calls to closure arguments where the closure takes 1 argument.
+// This is a bit tricky due to rust-call ABI.
+
+
+fn foo(f: &mut dyn FnMut(isize) -> isize) -> isize {
+ f(22)
+}
+
+fn main() {
+ let z = foo(&mut |x| x *100);
+ assert_eq!(z, 2200);
+}
diff --git a/src/test/ui/overloaded/overloaded-calls-object-two-args.rs b/src/test/ui/overloaded/overloaded-calls-object-two-args.rs
new file mode 100644
index 000000000..38087bc87
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-calls-object-two-args.rs
@@ -0,0 +1,13 @@
+// run-pass
+// Tests calls to closure arguments where the closure takes 2 arguments.
+// This is a bit tricky due to rust-call ABI.
+
+
+fn foo(f: &mut dyn FnMut(isize, isize) -> isize) -> isize {
+ f(1, 2)
+}
+
+fn main() {
+ let z = foo(&mut |x, y| x * 10 + y);
+ assert_eq!(z, 12);
+}
diff --git a/src/test/ui/overloaded/overloaded-calls-object-zero-args.rs b/src/test/ui/overloaded/overloaded-calls-object-zero-args.rs
new file mode 100644
index 000000000..9a7bfaa9b
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-calls-object-zero-args.rs
@@ -0,0 +1,13 @@
+// run-pass
+// Tests calls to closure arguments where the closure takes 0 arguments.
+// This is a bit tricky due to rust-call ABI.
+
+
+fn foo(f: &mut dyn FnMut() -> isize) -> isize {
+ f()
+}
+
+fn main() {
+ let z = foo(&mut || 22);
+ assert_eq!(z, 22);
+}
diff --git a/src/test/ui/overloaded/overloaded-calls-param-vtables.rs b/src/test/ui/overloaded/overloaded-calls-param-vtables.rs
new file mode 100644
index 000000000..fde1ad20f
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-calls-param-vtables.rs
@@ -0,0 +1,32 @@
+// run-pass
+// Tests that nested vtables work with overloaded calls.
+
+// pretty-expanded FIXME #23616
+
+#![feature(unboxed_closures, fn_traits)]
+
+use std::marker::PhantomData;
+use std::ops::Fn;
+use std::ops::Add;
+
+struct G<A>(PhantomData<A>);
+
+impl<'a, A: Add<i32, Output=i32>> Fn<(A,)> for G<A> {
+ extern "rust-call" fn call(&self, (arg,): (A,)) -> i32 {
+ arg.add(1)
+ }
+}
+
+impl<'a, A: Add<i32, Output=i32>> FnMut<(A,)> for G<A> {
+ extern "rust-call" fn call_mut(&mut self, args: (A,)) -> i32 { self.call(args) }
+}
+
+impl<'a, A: Add<i32, Output=i32>> FnOnce<(A,)> for G<A> {
+ type Output = i32;
+ extern "rust-call" fn call_once(self, args: (A,)) -> i32 { self.call(args) }
+}
+
+fn main() {
+ // ICE trigger
+ (G(PhantomData))(1);
+}
diff --git a/src/test/ui/overloaded/overloaded-calls-simple.rs b/src/test/ui/overloaded/overloaded-calls-simple.rs
new file mode 100644
index 000000000..413183607
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-calls-simple.rs
@@ -0,0 +1,78 @@
+// run-pass
+
+#![feature(lang_items, unboxed_closures, fn_traits)]
+
+use std::ops::{Fn, FnMut, FnOnce};
+
+struct S1 {
+ x: i32,
+ y: i32,
+}
+
+impl FnMut<(i32,)> for S1 {
+ extern "rust-call" fn call_mut(&mut self, (z,): (i32,)) -> i32 {
+ self.x * self.y * z
+ }
+}
+
+impl FnOnce<(i32,)> for S1 {
+ type Output = i32;
+ extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 {
+ self.call_mut(args)
+ }
+}
+
+struct S2 {
+ x: i32,
+ y: i32,
+}
+
+impl Fn<(i32,)> for S2 {
+ extern "rust-call" fn call(&self, (z,): (i32,)) -> i32 {
+ self.x * self.y * z
+ }
+}
+
+impl FnMut<(i32,)> for S2 {
+ extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> i32 { self.call(args) }
+}
+
+impl FnOnce<(i32,)> for S2 {
+ type Output = i32;
+ extern "rust-call" fn call_once(self, args: (i32,)) -> i32 { self.call(args) }
+}
+
+struct S3 {
+ x: i32,
+ y: i32,
+}
+
+impl FnOnce<(i32,i32)> for S3 {
+ type Output = i32;
+ extern "rust-call" fn call_once(self, (z,zz): (i32,i32)) -> i32 {
+ self.x * self.y * z * zz
+ }
+}
+
+fn main() {
+ let mut s = S1 {
+ x: 3,
+ y: 3,
+ };
+ let ans = s(3);
+
+ assert_eq!(ans, 27);
+ let s = S2 {
+ x: 3,
+ y: 3,
+ };
+ let ans = s.call((3,));
+ assert_eq!(ans, 27);
+
+ let s = S3 {
+ x: 3,
+ y: 3,
+ };
+ let ans = s(3, 1);
+ assert_eq!(ans, 27);
+}
diff --git a/src/test/ui/overloaded/overloaded-calls-zero-args.rs b/src/test/ui/overloaded/overloaded-calls-zero-args.rs
new file mode 100644
index 000000000..69ca88619
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-calls-zero-args.rs
@@ -0,0 +1,30 @@
+// run-pass
+
+#![feature(unboxed_closures, fn_traits)]
+
+use std::ops::FnMut;
+
+struct S {
+ x: i32,
+ y: i32,
+}
+
+impl FnMut<()> for S {
+ extern "rust-call" fn call_mut(&mut self, (): ()) -> i32 {
+ self.x * self.y
+ }
+}
+
+impl FnOnce<()> for S {
+ type Output = i32;
+ extern "rust-call" fn call_once(mut self, args: ()) -> i32 { self.call_mut(args) }
+}
+
+fn main() {
+ let mut s = S {
+ x: 3,
+ y: 3,
+ };
+ let ans = s();
+ assert_eq!(ans, 9);
+}
diff --git a/src/test/ui/overloaded/overloaded-deref-count.rs b/src/test/ui/overloaded/overloaded-deref-count.rs
new file mode 100644
index 000000000..e2f1e10b5
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-deref-count.rs
@@ -0,0 +1,78 @@
+// run-pass
+
+use std::cell::Cell;
+use std::ops::{Deref, DerefMut};
+use std::vec::Vec;
+
+struct DerefCounter<T> {
+ count_imm: Cell<usize>,
+ count_mut: usize,
+ value: T
+}
+
+impl<T> DerefCounter<T> {
+ fn new(value: T) -> DerefCounter<T> {
+ DerefCounter {
+ count_imm: Cell::new(0),
+ count_mut: 0,
+ value: value
+ }
+ }
+
+ fn counts(&self) -> (usize, usize) {
+ (self.count_imm.get(), self.count_mut)
+ }
+}
+
+impl<T> Deref for DerefCounter<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ self.count_imm.set(self.count_imm.get() + 1);
+ &self.value
+ }
+}
+
+impl<T> DerefMut for DerefCounter<T> {
+ fn deref_mut(&mut self) -> &mut T {
+ self.count_mut += 1;
+ &mut self.value
+ }
+}
+
+pub fn main() {
+ let mut n = DerefCounter::new(0);
+ let mut v = DerefCounter::new(Vec::new());
+
+ let _ = *n; // Immutable deref + copy a POD.
+ assert_eq!(n.counts(), (1, 0));
+
+ let _ = (&*n, &*v); // Immutable deref + borrow.
+ assert_eq!(n.counts(), (2, 0)); assert_eq!(v.counts(), (1, 0));
+
+ let _ = (&mut *n, &mut *v); // Mutable deref + mutable borrow.
+ assert_eq!(n.counts(), (2, 1)); assert_eq!(v.counts(), (1, 1));
+
+ let mut v2 = Vec::new();
+ v2.push(1);
+
+ *n = 5; *v = v2; // Mutable deref + assignment.
+ assert_eq!(n.counts(), (2, 2)); assert_eq!(v.counts(), (1, 2));
+
+ *n -= 3; // Mutable deref + assignment with binary operation.
+ assert_eq!(n.counts(), (2, 3));
+
+ // Immutable deref used for calling a method taking &self. (The
+ // typechecker is smarter now about doing this.)
+ (*n).to_string();
+ assert_eq!(n.counts(), (3, 3));
+
+ // Mutable deref used for calling a method taking &mut self.
+ (*v).push(2);
+ assert_eq!(v.counts(), (1, 3));
+
+ // Check the final states.
+ assert_eq!(*n, 2);
+ let expected: &[_] = &[1, 2];
+ assert_eq!((*v), expected);
+}
diff --git a/src/test/ui/overloaded/overloaded-deref.rs b/src/test/ui/overloaded/overloaded-deref.rs
new file mode 100644
index 000000000..73d8232a3
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-deref.rs
@@ -0,0 +1,43 @@
+// run-pass
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::string::String;
+
+#[derive(PartialEq, Debug)]
+struct Point {
+ x: isize,
+ y: isize
+}
+
+pub fn main() {
+ assert_eq!(*Rc::new(5), 5);
+ assert_eq!(***Rc::new(Box::new(Box::new(5))), 5);
+ assert_eq!(*Rc::new(Point {x: 2, y: 4}), Point {x: 2, y: 4});
+
+ let i = Rc::new(RefCell::new(2));
+ let i_value = *(*i).borrow();
+ *(*i).borrow_mut() = 5;
+ assert_eq!((i_value, *(*i).borrow()), (2, 5));
+
+ let s = Rc::new("foo".to_string());
+ assert_eq!(*s, "foo".to_string());
+ assert_eq!((*s), "foo");
+
+ let mut_s = Rc::new(RefCell::new(String::from("foo")));
+ (*(*mut_s).borrow_mut()).push_str("bar");
+ // assert_eq! would panic here because it stores the LHS and RHS in two locals.
+ assert_eq!((*(*mut_s).borrow()), "foobar");
+ assert_eq!((*(*mut_s).borrow_mut()), "foobar");
+
+ let p = Rc::new(RefCell::new(Point {x: 1, y: 2}));
+ (*(*p).borrow_mut()).x = 3;
+ (*(*p).borrow_mut()).y += 3;
+ assert_eq!(*(*p).borrow(), Point {x: 3, y: 5});
+
+ let v = Rc::new(RefCell::new(vec![1, 2, 3]));
+ (*(*v).borrow_mut())[0] = 3;
+ (*(*v).borrow_mut())[1] += 3;
+ assert_eq!(((*(*v).borrow())[0],
+ (*(*v).borrow())[1],
+ (*(*v).borrow())[2]), (3, 5, 3));
+}
diff --git a/src/test/ui/overloaded/overloaded-index-assoc-list.rs b/src/test/ui/overloaded/overloaded-index-assoc-list.rs
new file mode 100644
index 000000000..eb027afea
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-index-assoc-list.rs
@@ -0,0 +1,48 @@
+// run-pass
+// Test overloading of the `[]` operator. In particular test that it
+// takes its argument *by reference*.
+
+use std::ops::Index;
+
+struct AssociationList<K,V> {
+ pairs: Vec<AssociationPair<K,V>> }
+
+#[derive(Clone)]
+struct AssociationPair<K,V> {
+ key: K,
+ value: V
+}
+
+impl<K,V> AssociationList<K,V> {
+ fn push(&mut self, key: K, value: V) {
+ self.pairs.push(AssociationPair {key: key, value: value});
+ }
+}
+
+impl<'a, K: PartialEq + std::fmt::Debug, V:Clone> Index<&'a K> for AssociationList<K,V> {
+ type Output = V;
+
+ fn index(&self, index: &K) -> &V {
+ for pair in &self.pairs {
+ if pair.key == *index {
+ return &pair.value
+ }
+ }
+ panic!("No value found for key: {:?}", index);
+ }
+}
+
+pub fn main() {
+ let foo = "foo".to_string();
+ let bar = "bar".to_string();
+
+ let mut list = AssociationList {pairs: Vec::new()};
+ list.push(foo.clone(), 22);
+ list.push(bar.clone(), 44);
+
+ assert_eq!(list[&foo], 22);
+ assert_eq!(list[&bar], 44);
+
+ assert_eq!(list[&foo], 22);
+ assert_eq!(list[&bar], 44);
+}
diff --git a/src/test/ui/overloaded/overloaded-index-autoderef.rs b/src/test/ui/overloaded/overloaded-index-autoderef.rs
new file mode 100644
index 000000000..41f9efa8c
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-index-autoderef.rs
@@ -0,0 +1,75 @@
+// run-pass
+#![allow(stable_features)]
+
+// Test overloaded indexing combined with autoderef.
+
+use std::ops::{Index, IndexMut};
+
+struct Foo {
+ x: isize,
+ y: isize,
+}
+
+impl Index<isize> for Foo {
+ type Output = isize;
+
+ fn index(&self, z: isize) -> &isize {
+ if z == 0 {
+ &self.x
+ } else {
+ &self.y
+ }
+ }
+}
+
+impl IndexMut<isize> for Foo {
+ fn index_mut(&mut self, z: isize) -> &mut isize {
+ if z == 0 {
+ &mut self.x
+ } else {
+ &mut self.y
+ }
+ }
+}
+
+trait Int {
+ fn get(self) -> isize;
+ fn get_from_ref(&self) -> isize;
+ fn inc(&mut self);
+}
+
+impl Int for isize {
+ fn get(self) -> isize { self }
+ fn get_from_ref(&self) -> isize { *self }
+ fn inc(&mut self) { *self += 1; }
+}
+
+fn main() {
+ let mut f: Box<_> = Box::new(Foo {
+ x: 1,
+ y: 2,
+ });
+
+ assert_eq!(f[1], 2);
+
+ f[0] = 3;
+
+ assert_eq!(f[0], 3);
+
+ // Test explicit IndexMut where `f` must be autoderef:
+ {
+ let p = &mut f[1];
+ *p = 4;
+ }
+
+ // Test explicit Index where `f` must be autoderef:
+ {
+ let p = &f[1];
+ assert_eq!(*p, 4);
+ }
+
+ // Test calling methods with `&mut self`, `self, and `&self` receivers:
+ f[1].inc();
+ assert_eq!(f[1].get(), 5);
+ assert_eq!(f[1].get_from_ref(), 5);
+}
diff --git a/src/test/ui/overloaded/overloaded-index-in-field.rs b/src/test/ui/overloaded/overloaded-index-in-field.rs
new file mode 100644
index 000000000..8a1fa7deb
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-index-in-field.rs
@@ -0,0 +1,46 @@
+// run-pass
+// Test using overloaded indexing when the "map" is stored in a
+// field. This caused problems at some point.
+
+use std::ops::Index;
+
+struct Foo {
+ x: isize,
+ y: isize,
+}
+
+struct Bar {
+ foo: Foo
+}
+
+impl Index<isize> for Foo {
+ type Output = isize;
+
+ fn index(&self, z: isize) -> &isize {
+ if z == 0 {
+ &self.x
+ } else {
+ &self.y
+ }
+ }
+}
+
+trait Int {
+ fn get(self) -> isize;
+ fn get_from_ref(&self) -> isize;
+ fn inc(&mut self);
+}
+
+impl Int for isize {
+ fn get(self) -> isize { self }
+ fn get_from_ref(&self) -> isize { *self }
+ fn inc(&mut self) { *self += 1; }
+}
+
+fn main() {
+ let f = Bar { foo: Foo {
+ x: 1,
+ y: 2,
+ } };
+ assert_eq!(f.foo[1].get(), 2);
+}
diff --git a/src/test/ui/overloaded/overloaded-index.rs b/src/test/ui/overloaded/overloaded-index.rs
new file mode 100644
index 000000000..5ad6d2e70
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded-index.rs
@@ -0,0 +1,64 @@
+// run-pass
+use std::ops::{Index, IndexMut};
+
+struct Foo {
+ x: isize,
+ y: isize,
+}
+
+impl Index<isize> for Foo {
+ type Output = isize;
+
+ fn index(&self, z: isize) -> &isize {
+ if z == 0 {
+ &self.x
+ } else {
+ &self.y
+ }
+ }
+}
+
+impl IndexMut<isize> for Foo {
+ fn index_mut(&mut self, z: isize) -> &mut isize {
+ if z == 0 {
+ &mut self.x
+ } else {
+ &mut self.y
+ }
+ }
+}
+
+trait Int {
+ fn get(self) -> isize;
+ fn get_from_ref(&self) -> isize;
+ fn inc(&mut self);
+}
+
+impl Int for isize {
+ fn get(self) -> isize { self }
+ fn get_from_ref(&self) -> isize { *self }
+ fn inc(&mut self) { *self += 1; }
+}
+
+fn main() {
+ let mut f = Foo {
+ x: 1,
+ y: 2,
+ };
+ assert_eq!(f[1], 2);
+ f[0] = 3;
+ assert_eq!(f[0], 3);
+ {
+ let p = &mut f[1];
+ *p = 4;
+ }
+ {
+ let p = &f[1];
+ assert_eq!(*p, 4);
+ }
+
+ // Test calling methods with `&mut self`, `self, and `&self` receivers:
+ f[1].inc();
+ assert_eq!(f[1].get(), 5);
+ assert_eq!(f[1].get_from_ref(), 5);
+}
diff --git a/src/test/ui/overloaded/overloaded_deref_with_ref_pattern.rs b/src/test/ui/overloaded/overloaded_deref_with_ref_pattern.rs
new file mode 100644
index 000000000..c87ba6a02
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded_deref_with_ref_pattern.rs
@@ -0,0 +1,95 @@
+// run-pass
+#![allow(unused_mut)]
+#![allow(unused_variables)]
+// Test that we choose Deref or DerefMut appropriately based on mutability of ref bindings (#15609).
+
+use std::ops::{Deref, DerefMut};
+
+struct DerefOk<T>(T);
+struct DerefMutOk<T>(T);
+
+impl<T> Deref for DerefOk<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<T> DerefMut for DerefOk<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ panic!()
+ }
+}
+
+impl<T> Deref for DerefMutOk<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+impl<T> DerefMut for DerefMutOk<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+fn main() {
+ // Check that mutable ref binding in match picks DerefMut
+ let mut b = DerefMutOk(0);
+ match *b {
+ ref mut n => n,
+ };
+
+ // Check that mutable ref binding in let picks DerefMut
+ let mut y = DerefMutOk(1);
+ let ref mut z = *y;
+
+ // Check that immutable ref binding in match picks Deref
+ let mut b = DerefOk(2);
+ match *b {
+ ref n => n,
+ };
+
+ // Check that immutable ref binding in let picks Deref
+ let mut y = DerefOk(3);
+ let ref z = *y;
+
+ // Check that mixed mutable/immutable ref binding in match picks DerefMut
+ let mut b = DerefMutOk((0, 9));
+ match *b {
+ (ref mut n, ref m) => (n, m),
+ };
+
+ let mut b = DerefMutOk((0, 9));
+ match *b {
+ (ref n, ref mut m) => (n, m),
+ };
+
+ // Check that mixed mutable/immutable ref binding in let picks DerefMut
+ let mut y = DerefMutOk((1, 8));
+ let (ref mut z, ref a) = *y;
+
+ let mut y = DerefMutOk((1, 8));
+ let (ref z, ref mut a) = *y;
+
+ // Check that multiple immutable ref bindings in match picks Deref
+ let mut b = DerefOk((2, 7));
+ match *b {
+ (ref n, ref m) => (n, m),
+ };
+
+ // Check that multiple immutable ref bindings in let picks Deref
+ let mut y = DerefOk((3, 6));
+ let (ref z, ref a) = *y;
+
+ // Check that multiple mutable ref bindings in match picks DerefMut
+ let mut b = DerefMutOk((4, 5));
+ match *b {
+ (ref mut n, ref mut m) => (n, m),
+ };
+
+ // Check that multiple mutable ref bindings in let picks DerefMut
+ let mut y = DerefMutOk((5, 4));
+ let (ref mut z, ref mut a) = *y;
+}
diff --git a/src/test/ui/overloaded/overloaded_deref_with_ref_pattern_issue15609.rs b/src/test/ui/overloaded/overloaded_deref_with_ref_pattern_issue15609.rs
new file mode 100644
index 000000000..61edd2ace
--- /dev/null
+++ b/src/test/ui/overloaded/overloaded_deref_with_ref_pattern_issue15609.rs
@@ -0,0 +1,37 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+// Test that we choose Deref or DerefMut appropriately based on mutability of ref bindings (#15609).
+
+fn main() {
+ use std::cell::RefCell;
+
+ struct S {
+ node: E,
+ }
+
+ enum E {
+ Foo(u32),
+ Bar,
+ }
+
+ // Check match
+ let x = RefCell::new(S { node: E::Foo(0) });
+
+ let mut b = x.borrow_mut();
+ match b.node {
+ E::Foo(ref mut n) => *n += 1,
+ _ => (),
+ }
+
+ // Check let
+ let x = RefCell::new(0);
+ let mut y = x.borrow_mut();
+ let ref mut z = *y;
+
+ fn foo(a: &mut RefCell<Option<String>>) {
+ if let Some(ref mut s) = *a.borrow_mut() {
+ s.push('a')
+ }
+ }
+}