diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/overloaded | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
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') + } + } +} |