From f2aaed8338d80afccd2159d9c819d8d0f300cb55 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 6 Nov 2014 17:34:33 -0500 Subject: [PATCH] libs: add Deref, DerefMut impls for references, fixing a bug in compiler in the process that was blocking this. Fixes #18621. --- src/liballoc/arc.rs | 2 +- src/libcore/ops.rs | 15 +++++++++++++ src/librustc/middle/typeck/check/method.rs | 19 ++++++++++------ src/libstd/collections/hash/table.rs | 4 ++++ src/test/run-pass/deref-mut-on-ref.rs | 21 ++++++++++++++++++ src/test/run-pass/deref-on-ref.rs | 25 ++++++++++++++++++++++ 6 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 src/test/run-pass/deref-mut-on-ref.rs create mode 100644 src/test/run-pass/deref-on-ref.rs diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index f543826fe0187..c4f53d744673f 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -166,7 +166,7 @@ impl Arc { // additional reference of either kind. if self.inner().strong.load(atomic::SeqCst) != 1 || self.inner().weak.load(atomic::SeqCst) != 1 { - *self = Arc::new(self.deref().clone()) + *self = Arc::new((**self).clone()) } // This unsafety is ok because we're guaranteed that the pointer // returned is the *only* pointer that will ever be returned to T. Our diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index ac735492be4a5..2631d0d442368 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -805,6 +805,16 @@ pub trait Deref { fn deref<'a>(&'a self) -> &'a Result; } +#[cfg(not(stage0))] +impl<'a, Sized? T> Deref for &'a T { + fn deref(&self) -> &T { *self } +} + +#[cfg(not(stage0))] +impl<'a, Sized? T> Deref for &'a mut T { + fn deref(&self) -> &T { *self } +} + /** * * The `DerefMut` trait is used to specify the functionality of dereferencing @@ -845,6 +855,11 @@ pub trait DerefMut: Deref { fn deref_mut<'a>(&'a mut self) -> &'a mut Result; } +#[cfg(not(stage0))] +impl<'a, Sized? T> DerefMut for &'a mut T { + fn deref_mut(&mut self) -> &mut T { *self } +} + /// A version of the call operator that takes an immutable receiver. #[lang="fn"] pub trait Fn { diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index f854bc52acd7b..ecc42f09a59e1 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -1702,13 +1702,18 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { PreferMutLvalue); } ast::ExprUnary(ast::UnDeref, ref base_expr) => { - check::try_overloaded_deref( - self.fcx, - expr.span, - Some(MethodCall::expr(expr.id)), - Some(&**base_expr), - self.fcx.expr_ty(&**base_expr), - PreferMutLvalue); + // if this is an overloaded deref, then re-evaluate with + // a preference for mut + let method_call = MethodCall::expr(expr.id); + if self.fcx.inh.method_map.borrow().contains_key(&method_call) { + check::try_overloaded_deref( + self.fcx, + expr.span, + Some(method_call), + Some(&**base_expr), + self.fcx.expr_ty(&**base_expr), + PreferMutLvalue); + } } _ => {} } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 4d73029b7b06b..fd964cdf02c53 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -166,18 +166,22 @@ impl RawBucket { } // For parameterizing over mutability. + +#[cfg(stage0)] impl<'t, K, V> Deref> for &'t RawTable { fn deref(&self) -> &RawTable { &**self } } +#[cfg(stage0)] impl<'t, K, V> Deref> for &'t mut RawTable { fn deref(&self) -> &RawTable { &**self } } +#[cfg(stage0)] impl<'t, K, V> DerefMut> for &'t mut RawTable { fn deref_mut(&mut self) -> &mut RawTable { &mut **self diff --git a/src/test/run-pass/deref-mut-on-ref.rs b/src/test/run-pass/deref-mut-on-ref.rs new file mode 100644 index 0000000000000..dcf7c483b2cdc --- /dev/null +++ b/src/test/run-pass/deref-mut-on-ref.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that `&mut T` implements `DerefMut` + +fn inc>(mut t: T) { + *t += 1; +} + +fn main() { + let mut x: int = 5; + inc(&mut x); + assert_eq!(x, 6); +} diff --git a/src/test/run-pass/deref-on-ref.rs b/src/test/run-pass/deref-on-ref.rs new file mode 100644 index 0000000000000..27e7d8f3ba2a4 --- /dev/null +++ b/src/test/run-pass/deref-on-ref.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that `&T` and `&mut T` implement `Deref` + +fn deref>(t: T) -> U { + *t +} + +fn main() { + let x: int = 3; + let y = deref(&x); + assert_eq!(y, 3); + + let mut x: int = 4; + let y = deref(&mut x); + assert_eq!(y, 4); +}